diff --git a/municipal-services/asset-services/src/main/java/org/egov/asset/service/WorkflowService.java b/municipal-services/asset-services/src/main/java/org/egov/asset/service/WorkflowService.java index e934a55c473..59a37514f28 100644 --- a/municipal-services/asset-services/src/main/java/org/egov/asset/service/WorkflowService.java +++ b/municipal-services/asset-services/src/main/java/org/egov/asset/service/WorkflowService.java @@ -85,6 +85,7 @@ public State updateWorkflow(AssetRequest assetRequest, CreationReason creationRe // else // request.getProperty().setStatus(Status.fromValue(state.getApplicationStatus())); // request.getProperty().getWorkflow().setState(state); + assetRequest.getAsset().setStatus(state.getApplicationStatus()); return state; } diff --git a/municipal-services/asset-services/src/main/resources/db/migration/main/V20243005102355__asset_niuadeployment.sql b/municipal-services/asset-services/src/main/resources/db/migration/main/V20243005102355__asset_niuadeployment.sql new file mode 100644 index 00000000000..f56edfa39b8 --- /dev/null +++ b/municipal-services/asset-services/src/main/resources/db/migration/main/V20243005102355__asset_niuadeployment.sql @@ -0,0 +1,10 @@ +-- Create ENUM types +--CREATE TYPE public.asset_classification AS ENUM ('MOVABLE', 'IMMOVABLE'); +--CREATE TYPE public.parent_type AS ENUM ('LAND', 'BUILDING', 'SERVICE','OTHER'); + +--ALTER TABLE eg_asset_assetdetails DROP COLUMN action; + +--ALTER TABLE eg_asset_auditdetails DROP COLUMN action; + +--ALTER TABLE eg_asset_auditdetails ADD COLUMN remarks character varying(256); +ALTER TABLE eg_asset_auditdetails ALTER COLUMN additionaldetails TYPE JSONB; \ No newline at end of file diff --git a/municipal-services/inbox/src/main/java/org/egov/inbox/service/AssetInboxFilterService.java b/municipal-services/inbox/src/main/java/org/egov/inbox/service/AssetInboxFilterService.java new file mode 100644 index 00000000000..53b78627531 --- /dev/null +++ b/municipal-services/inbox/src/main/java/org/egov/inbox/service/AssetInboxFilterService.java @@ -0,0 +1,147 @@ +package org.egov.inbox.service; + +import com.jayway.jsonpath.JsonPath; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.request.RequestInfo; +import org.egov.inbox.repository.ServiceRequestRepository; +import org.egov.inbox.web.model.InboxSearchCriteria; +import org.egov.inbox.web.model.workflow.ProcessInstanceSearchCriteria; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; +import org.springframework.util.ObjectUtils; +import org.springframework.web.client.RestTemplate; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.egov.inbox.util.AssetConstants.*; + + +@Slf4j +@Service +public class AssetInboxFilterService { + + @Value("${egov.user.host}") + private String userHost; + + @Value("${egov.user.search.path}") + private String userSearchEndpoint; + + @Value("${egov.searcher.host}") + private String searcherHost; + + @Value("${egov.searcher.asset.search.path}") + private String assetInboxSearcherEndpoint; + + @Value("${egov.searcher.asset.search.desc.path}") + private String assetInboxSearcherDescEndpoint; + + @Autowired + private RestTemplate restTemplate; + + @Autowired + private ServiceRequestRepository serviceRequestRepository; + + public List fetchApplicationNumbersFromSearcher(InboxSearchCriteria criteria, HashMap StatusIdNameMap, RequestInfo requestInfo){ + List applicationNumbers = new ArrayList<>(); + HashMap moduleSearchCriteria = criteria.getModuleSearchCriteria(); + ProcessInstanceSearchCriteria processCriteria = criteria.getProcessSearchCriteria(); + Boolean isSearchResultEmpty = false; + List userUUIDs = new ArrayList<>(); + Boolean isMobileNumberPresent = false; + + if(moduleSearchCriteria.containsKey(MOBILE_NUMBER_PARAM)){ + isMobileNumberPresent = true; + } + if(isMobileNumberPresent) { + String tenantId = criteria.getTenantId(); + String mobileNumber = String.valueOf(moduleSearchCriteria.get(MOBILE_NUMBER_PARAM)); + userUUIDs = fetchUserUUID(mobileNumber, requestInfo, tenantId); + Boolean isUserPresentForGivenMobileNumber = CollectionUtils.isEmpty(userUUIDs) ? false : true; + isSearchResultEmpty = !isMobileNumberPresent || !isUserPresentForGivenMobileNumber; + if(isSearchResultEmpty){ + return new ArrayList<>(); + } + } + + + if(!isSearchResultEmpty){ + Object result = null; + + Map searcherRequest = new HashMap<>(); + Map searchCriteria = new HashMap<>(); + + searchCriteria.put(TENANT_ID_PARAM,criteria.getTenantId()); + searchCriteria.put(BUSINESS_SERVICE_PARAM, processCriteria.getBusinessService()); + + if(moduleSearchCriteria.containsKey(LOCALITY_PARAM)){ + searchCriteria.put(LOCALITY_PARAM, moduleSearchCriteria.get(LOCALITY_PARAM)); + } + if(moduleSearchCriteria.containsKey(ASSET_APPLICATION_NUMBER_PARAM)) { + searchCriteria.put(ASSET_APPLICATION_NUMBER_PARAM, moduleSearchCriteria.get(ASSET_APPLICATION_NUMBER_PARAM)); + } + + // Accomodating process search criteria in searcher request + if(!ObjectUtils.isEmpty(processCriteria.getAssignee())){ + searchCriteria.put(ASSIGNEE_PARAM, processCriteria.getAssignee()); + } + if(!ObjectUtils.isEmpty(processCriteria.getStatus())){ + searchCriteria.put(STATUS_PARAM, processCriteria.getStatus()); + }else{ + if(StatusIdNameMap.values().size() > 0) { + if(CollectionUtils.isEmpty(processCriteria.getStatus())) { + searchCriteria.put(STATUS_PARAM, StatusIdNameMap.keySet()); + } + } + } + + // Paginating searcher results + searchCriteria.put(OFFSET_PARAM, criteria.getOffset()); + searchCriteria.put(NO_OF_RECORDS_PARAM, criteria.getLimit()); + moduleSearchCriteria.put(LIMIT_PARAM, criteria.getLimit()); + + searcherRequest.put(REQUESTINFO_PARAM, requestInfo); + searcherRequest.put(SEARCH_CRITERIA_PARAM, searchCriteria); + + StringBuilder uri = new StringBuilder(); + if(moduleSearchCriteria.containsKey(SORT_ORDER_PARAM) && moduleSearchCriteria.get(SORT_ORDER_PARAM).equals(DESC_PARAM)){ + uri.append(searcherHost).append(assetInboxSearcherDescEndpoint); + }else { + uri.append(searcherHost).append(assetInboxSearcherEndpoint); + } + result = restTemplate.postForObject(uri.toString(), searcherRequest, Map.class); + applicationNumbers = JsonPath.read(result, "$.Asset.*.applicationno"); + + } + return applicationNumbers; + } + + + private List fetchUserUUID(String mobileNumber, RequestInfo requestInfo, String tenantId) { + StringBuilder uri = new StringBuilder(); + uri.append(userHost).append(userSearchEndpoint); + Map userSearchRequest = new HashMap<>(); + userSearchRequest.put("RequestInfo", requestInfo); + userSearchRequest.put("tenantId", tenantId); + userSearchRequest.put("userType", "EMPLOYEE"); + userSearchRequest.put("mobileNumber", mobileNumber); + List userUuids = new ArrayList<>(); + try { + Object user = serviceRequestRepository.fetchResult(uri, userSearchRequest); + if(null != user) { + //log.info(user.toString()); + userUuids = JsonPath.read(user, "$.user.*.uuid"); + }else { + log.error("Service returned null while fetching user for mobile number - " + mobileNumber); + } + }catch(Exception e) { + log.error("Exception while fetching user for mobile number - " + mobileNumber); + log.error("Exception trace: ", e); + } + return userUuids; + } +} \ No newline at end of file diff --git a/municipal-services/inbox/src/main/java/org/egov/inbox/service/InboxService.java b/municipal-services/inbox/src/main/java/org/egov/inbox/service/InboxService.java index 8aaa2ced3b2..b212d7d2020 100644 --- a/municipal-services/inbox/src/main/java/org/egov/inbox/service/InboxService.java +++ b/municipal-services/inbox/src/main/java/org/egov/inbox/service/InboxService.java @@ -34,6 +34,7 @@ import static org.egov.inbox.util.BSConstants.*; import static org.egov.inbox.util.WSConstants.WS; import static org.egov.inbox.util.PTRConstants.PTR; +import static org.egov.inbox.util.AssetConstants.ASSET; import java.util.*; import java.util.function.Function; @@ -122,6 +123,9 @@ public class InboxService { @Autowired private BillingAmendmentInboxFilterService billInboxFilterService; + + @Autowired + private AssetInboxFilterService assetInboxFilterService; @Autowired private RestTemplate restTemplate; @@ -155,11 +159,12 @@ public InboxResponse fetchInboxData(InboxSearchCriteria criteria, RequestInfo re } Integer totalCount = 0; + log.info(processCriteria.getModuleName().toString()); if(!(processCriteria.getModuleName().equals(SW) || processCriteria.getModuleName().equals(WS))) totalCount = workflowService.getProcessCount(criteria.getTenantId(), requestInfo, processCriteria); // Integer nearingSlaProcessCount = workflowService.getNearingSlaProcessCount(criteria.getTenantId(), requestInfo, processCriteria); Integer nearingSlaProcessCount = 0; - if(!(processCriteria.getModuleName().equals(PTR) || processCriteria.getModuleName().equals(PT))) { + if(!(processCriteria.getModuleName().equals(PTR) || processCriteria.getModuleName().equals(PT) || processCriteria.getModuleName().equals(ASSET))) { nearingSlaProcessCount = workflowService.getNearingSlaProcessCount(criteria.getTenantId(), requestInfo, processCriteria); } @@ -370,6 +375,20 @@ public InboxResponse fetchInboxData(InboxSearchCriteria criteria, RequestInfo re } }//for pet service + if (!ObjectUtils.isEmpty(processCriteria.getModuleName()) && processCriteria.getModuleName().equals(ASSET)) { + + List applicationNumbers = assetInboxFilterService.fetchApplicationNumbersFromSearcher(criteria, + StatusIdNameMap, requestInfo); + if (!CollectionUtils.isEmpty(applicationNumbers)) { + moduleSearchCriteria.put(ACKNOWLEDGEMENT_IDS_PARAM, applicationNumbers); + businessKeys.addAll(applicationNumbers); + moduleSearchCriteria.remove(LOCALITY_PARAM); + moduleSearchCriteria.remove(OFFSET_PARAM); + } else { + isSearchResultEmpty = true; + } + }//for asset service + if (!ObjectUtils.isEmpty(processCriteria.getModuleName()) && ( processCriteria.getModuleName().equals(TL) || processCriteria.getModuleName().equals(BPAREG))) { totalCount = tlInboxFilterService.fetchApplicationCountFromSearcher(criteria, StatusIdNameMap, requestInfo); @@ -1047,11 +1066,13 @@ private JSONArray fetchModuleObjects(HashMap moduleSearchCriteria, List } StringBuilder url = new StringBuilder(srvMap.get("searchPath")); url.append("?tenantId=").append(tenantId); - if(moduleSearchCriteria.containsKey("status")) { // for pet-service - if(businessServiceName.contains("ptr")) { - moduleSearchCriteria.remove("status"); - } - }//for pet-service + + if (moduleSearchCriteria.containsKey("status")) { // for pet-service + if (businessServiceName.contains("ptr")) { + moduleSearchCriteria.remove("status"); + } + } // for pet-service + Set searchParams = moduleSearchCriteria.keySet(); searchParams.forEach((param) -> { diff --git a/municipal-services/inbox/src/main/java/org/egov/inbox/util/AssetConstants.java b/municipal-services/inbox/src/main/java/org/egov/inbox/util/AssetConstants.java new file mode 100644 index 00000000000..588d31c1d4a --- /dev/null +++ b/municipal-services/inbox/src/main/java/org/egov/inbox/util/AssetConstants.java @@ -0,0 +1,24 @@ +package org.egov.inbox.util; + +public class AssetConstants { + + public static final String ASSET = "asset-services"; + public static final String MOBILE_NUMBER_PARAM = "mobileNumber"; + public static final String BUSINESS_SERVICE_PARAM = "businessservice"; + public static final String TENANT_ID_PARAM = "tenantId"; + public static final String LOCALITY_PARAM = "locality"; + public static final String ASSET_APPLICATION_NUMBER_PARAM = "applicationNo"; + public static final String ASSIGNEE_PARAM = "assignee"; + public static final String STATUS_PARAM = "status"; + public static final String OFFSET_PARAM = "offset"; + public static final String NO_OF_RECORDS_PARAM = "noOfRecords"; + public static final String LIMIT_PARAM = "limit"; + public static final String ACKNOWLEDGEMENT_IDS_PARAM = "acknowledgementIds"; + public static final String REQUESTINFO_PARAM = "RequestInfo"; + public static final String SEARCH_CRITERIA_PARAM = "searchCriteria"; + public static final String USERID_PARAM = "userid"; + public static final String SORT_ORDER_PARAM = "sortOrder"; + public static final String DESC_PARAM = "DESC"; + + +} diff --git a/municipal-services/inbox/src/main/resources/application.properties b/municipal-services/inbox/src/main/resources/application.properties index efbe5cb7408..cc479c04403 100644 --- a/municipal-services/inbox/src/main/resources/application.properties +++ b/municipal-services/inbox/src/main/resources/application.properties @@ -4,9 +4,31 @@ server.servlet.context-path=/inbox server.port=9011 app.timezone=GMT+5:30 +#DATABASE CONFIGURATION +spring.datasource.driver-class-name=org.postgresql.Driver +spring.datasource.url=jdbc:postgresql://localhost:5432/asset +spring.datasource.username=postgres +spring.datasource.password=postgres + +#spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect +#spring.jpa.show-sql=true +#spring.jpa.hibernate.ddl-auto=none + +#FLYWAY CONFIGURATION +spring.flyway.url=jdbc:postgresql://localhost:5432/asset +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 + + # wf url #dev +#workflow.host=http://localhost:8096 workflow.host=http://egov-workflow-v2:8080 workflow.process.search.path=/egov-workflow-v2/egov-wf/process/_search workflow.businessservice.search.path=/egov-workflow-v2/egov-wf/businessservice/_search @@ -28,16 +50,20 @@ egov.fsm.host=http://fsm.egov:8080 egov.fsm.fetchApplicationIds.path=/fsm/v1/fetchApplicationIds #service.search.mapping={"FSM":{"searchPath":"http://localhost:9098/fsm/v1/_search","dataRoot":"fsm","applNosParam":"applicationNos","businessIdProperty":"applicationNo","applsStatusParam":"applicationStatus"},"FSM_VEHICLE_TRIP":{"searchPath":"http://localhost:8061/vehicle/trip/v1/_search","dataRoot":"vehicleTrip","applNosParam":"applicationNos","businessIdProperty":"applicationNo","applsStatusParam":"applicationStatus"}} -service.search.mapping={"FSM":{"searchPath":"http://localhost:9098/fsm/v1/_search","dataRoot":"fsm","applNosParam":"applicationNos","businessIdProperty":"applicationNo","applsStatusParam":"applicationStatus"},"FSM_POST_PAY_SERVICE":{"searchPath":"http://localhost:9098/fsm/v1/_search","dataRoot":"fsm","applNosParam":"applicationNos","businessIdProperty":"applicationNo","applsStatusParam":"applicationStatus"},"FSM_VEHICLE_TRIP":{"searchPath":"http://localhost:8061/vehicle/trip/v1/_search","dataRoot":"vehicleTrip","applNosParam":"applicationNos","businessIdProperty":"applicationNo","applsStatusParam":"applicationStatus"},"PT.CREATE,PT.MUTATION,PT.UPDATE":{"searchPath":"http://localhost:8084/property-services/property/_search","dataRoot":"Properties","applNosParam":"acknowldgementNumber","businessIdProperty":"acknowldgementNumber","applsStatusParam":"status"},"ptr":{"searchPath":"http://localhost:8034/pet-services/pet-registration/_search","dataRoot":"PetRegistrationApplications","applNosParam":"applicationNumber","businessIdProperty":"applicationNumber","applsStatusParam":"status"},"NewTL,EDITRENEWAL,DIRECTRENEWAL":{"searchPath":"http://localhost:8088/tl-services/v1/_search","dataRoot":"Licenses","applNosParam":"applicationNumber","businessIdProperty":"applicationNumber","applsStatusParam":"status"},"BPA_LOW,BPA,BPA_OC":{"searchPath":"http://localhost:8098/bpa-services/v1/bpa/_search","dataRoot":"BPA","applNosParam":"applicationNo","businessIdProperty":"applicationNo","applsStatusParam":"status"},"ARCHITECT,ENGINEER,STRUCTURALENGINEER,BUILDER":{"searchPath":"http://localhost:8088/tl-services/v1/BPAREG/_search","dataRoot":"Licenses","applNosParam":"applicationNumber","businessIdProperty":"applicationNumber","applsStatusParam":"status"},"FIRE_NOC_SRV,FIRE_NOC_OFFLINE,AIRPORT_NOC_OFFLINE,AIRPORT_NOC_SRV":{"searchPath":"http://localhost:8099/noc-services/v1/noc/_search","dataRoot":"Noc","applNosParam":"applicationNo","businessIdProperty":"applicationNo","applsStatusParam":"status"},"NewWS1,ModifyWSConnection,DisconnectWSConnection":{"searchPath":"http://localhost:1080/ws-services/wc/_search","dataRoot":"WaterConnection","applNosParam":"applicationNumber","businessIdProperty":"applicationNo","applsStatusParam":"applicationStatus"},"NewSW1,ModifySWConnection,DisconnectSWConnection":{"searchPath":"http://localhost:1081/sw-services/swc/_search","dataRoot":"SewerageConnections","applNosParam":"applicationNumber","businessIdProperty":"applicationNo","applsStatusParam":"applicationStatus"},"WS.AMENDMENT,SW.AMENDMENT":{"searchPath":"http://localhost:1082/billing-service/amendment/_search","dataRoot":"Amendments","applNosParam":"consumerCode","businessIdProperty":"amendmentId","applsStatusParam":"status"}} +service.search.mapping={"FSM":{"searchPath":"http://localhost:9098/fsm/v1/_search","dataRoot":"fsm","applNosParam":"applicationNos","businessIdProperty":"applicationNo","applsStatusParam":"applicationStatus"},"FSM_POST_PAY_SERVICE":{"searchPath":"http://localhost:9098/fsm/v1/_search","dataRoot":"fsm","applNosParam":"applicationNos","businessIdProperty":"applicationNo","applsStatusParam":"applicationStatus"},"FSM_VEHICLE_TRIP":{"searchPath":"http://localhost:8061/vehicle/trip/v1/_search","dataRoot":"vehicleTrip","applNosParam":"applicationNos","businessIdProperty":"applicationNo","applsStatusParam":"applicationStatus"},"PT.CREATE,PT.MUTATION,PT.UPDATE":{"searchPath":"http://localhost:8084/property-services/property/_search","dataRoot":"Properties","applNosParam":"acknowldgementNumber","businessIdProperty":"acknowldgementNumber","applsStatusParam":"status"},"ptr":{"searchPath":"http://localhost:8034/pet-services/pet-registration/_search","dataRoot":"PetRegistrationApplications","applNosParam":"applicationNumber","businessIdProperty":"applicationNumber","applsStatusParam":"status"},"NewTL,EDITRENEWAL,DIRECTRENEWAL":{"searchPath":"http://localhost:8088/tl-services/v1/_search","dataRoot":"Licenses","applNosParam":"applicationNumber","businessIdProperty":"applicationNumber","applsStatusParam":"status"},"BPA_LOW,BPA,BPA_OC":{"searchPath":"http://localhost:8098/bpa-services/v1/bpa/_search","dataRoot":"BPA","applNosParam":"applicationNo","businessIdProperty":"applicationNo","applsStatusParam":"status"},"ARCHITECT,ENGINEER,STRUCTURALENGINEER,BUILDER":{"searchPath":"http://localhost:8088/tl-services/v1/BPAREG/_search","dataRoot":"Licenses","applNosParam":"applicationNumber","businessIdProperty":"applicationNumber","applsStatusParam":"status"},"FIRE_NOC_SRV,FIRE_NOC_OFFLINE,AIRPORT_NOC_OFFLINE,AIRPORT_NOC_SRV":{"searchPath":"http://localhost:8099/noc-services/v1/noc/_search","dataRoot":"Noc","applNosParam":"applicationNo","businessIdProperty":"applicationNo","applsStatusParam":"status"},"NewWS1,ModifyWSConnection,DisconnectWSConnection":{"searchPath":"http://localhost:1080/ws-services/wc/_search","dataRoot":"WaterConnection","applNosParam":"applicationNumber","businessIdProperty":"applicationNo","applsStatusParam":"applicationStatus"},"NewSW1,ModifySWConnection,DisconnectSWConnection":{"searchPath":"http://localhost:1081/sw-services/swc/_search","dataRoot":"SewerageConnections","applNosParam":"applicationNumber","businessIdProperty":"applicationNo","applsStatusParam":"applicationStatus"},"WS.AMENDMENT,SW.AMENDMENT":{"searchPath":"http://localhost:1082/billing-service/amendment/_search","dataRoot":"Amendments","applNosParam":"consumerCode","businessIdProperty":"amendmentId","applsStatusParam":"status"},"asset-create":{"searchPath":"http://localhost:8098/asset-services/v1/assets/_search","dataRoot":"Assets","applNosParam":"applicationNo","businessIdProperty":"applicationNo","applsStatusParam":"status"}} # CONFIGS bs.businesscode.service.search= {"WS":{"searchPath":"http://localhost:1080/ws-services/wc/_search","dataRoot":"WaterConnection","consumerCodeParam":"connectionNumber","consumerParamInService":"connectionNo"},"SW":{"searchPath":"http://localhost:1081/sw-services/swc/_search","dataRoot":"SewerageConnections","consumerCodeParam":"connectionNumber","consumerParamInService":"connectionNo"}} # user url + +#egov.user.host=http://localhost:8099 egov.user.host=http://egov-user:8080 egov.user.search.path=/user/_search egov.user.create.path=/user/users/_createnovalidate + +#egov.searcher.host=http://localhost:9094 egov.searcher.host=http://egov-searcher:8080 egov.searcher.pt.search.path=/egov-searcher/property-services/inboxpropertysearch/_get egov.searcher.tl.search.path=/egov-searcher/tl-services/inboxtlsearch/_get @@ -87,11 +113,19 @@ egov.searcher.bs.sw.search.desc.path=/egov-searcher/bsSw-service/inboxbsswsearch egov.searcher.pet.search.path=/egov-searcher/pet-services/inboxpetsearch/_get egov.searcher.pet.search.desc.path=/egov-searcher/pet-services/inboxpetsearchdesc/_get +#Asset Searcher end points +egov.searcher.asset.search.path=/egov-searcher/asset-services/inboxassetsearch/_get +egov.searcher.asset.search.desc.path=/egov-searcher/asset-services/inboxassetsearchdesc/_get + #getchartv2 end points egov.dashboard.analytics.host=http://localhost:8282 egov.dashboard.analytics.getchartv2.path=/dashboard-analytics/dashboard/getChartV2 -egov.mdms.host=https://niuatt.niua.in + +#egov.mdms.host=http://localhost:8094 +#egov.mdms.host=https://niuatt.niua.in +egov.workflow.host=http://egov-workflow-v2:8080 + egov.mdms.search.endpoint=/egov-mdms-service/v1/_search diff --git a/upyog-mdms-data-niuatt-bimal b/upyog-mdms-data-niuatt-bimal deleted file mode 160000 index 7be7ab21d26..00000000000 --- a/upyog-mdms-data-niuatt-bimal +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 7be7ab21d269b54437485bca9381c3dd2b650e3e