///<summary>Returns the last known status for the given eService.</summary> public static eServiceSignalSeverity GetServiceStatus(eServiceCode serviceCode) { if(RemotingClient.RemotingRole==RemotingRole.ClientWeb) { return Meth.GetObject<eServiceSignalSeverity>(MethodBase.GetCurrentMethod(),serviceCode); } //The only statuses within the eServiceSignalSeverity enum are NotEnabled, Working, and Critical. //All other statuses are used for logging purposes and should not be considered within this method. string command="SELECT * FROM eservicesignal WHERE ServiceCode="+POut.Int((int)serviceCode)+" " +"AND Severity IN("+POut.Int((int)eServiceSignalSeverity.NotEnabled)+"," +POut.Int((int)eServiceSignalSeverity.Working)+"," +POut.Int((int)eServiceSignalSeverity.Critical)+") " +"ORDER BY SigDateTime DESC, Severity DESC "+DbHelper.LimitWhere(1); List<EServiceSignal> listSignal=Crud.EServiceSignalCrud.SelectMany(command); if(listSignal.Count==0) { //NoSignals exist for this service. return eServiceSignalSeverity.None; } //The listener service is considered down and in a critical state if there hasn't been a heartbeat in the last 5 minutes. //An eSignal severity of "Not Enabled" means the office no longer wants to monitor the status of the service. if(serviceCode==eServiceCode.ListenerService && listSignal[0].Severity!=eServiceSignalSeverity.NotEnabled && listSignal[0].SigDateTime<DateTime.Now.AddMinutes(-5)) { //Office has not disabled the monitoring of the listener service and there hasn't been a heartbeat in the last 5 minutes. return eServiceSignalSeverity.Critical; } return listSignal[0].Severity; }
///<summary>Any calls to WebServiceMainHQ must go through this method. The payload created here will be digested and extracted to OpenDentalWebServiceHQ.PayloadArgs. ///If any args are null or not provided then they will be retrieved from Prefs.</summary> ///<param name="registrationKey">An Open Dental distributed registration key that HQ has on file. Do not include hyphens.</param> ///<param name="practiceTitle">Any string is acceptable.</param> ///<param name="practicePhone">Any string is acceptable.</param> ///<param name="programVersion">Typically major.minor.build.revision. E.g. 12.4.58.0</param> ///<param name="payloadContentxAsXml">Use CreateXmlWriterSettings(true) to create your payload xml. Outer-most xml element MUST be labeled 'Payload'.</param> ///<param name="serviceCode">Used on case by case basis to validate that customer is registered for the given service.</param> ///<returns>An XML string that can be passed into a WebServiceHQ web method.</returns> public static string CreateWebServiceHQPayload( string payloadContentxAsXml, eServiceCode serviceCode, string registrationKey = null, string practiceTitle = null, string practicePhone = null, string programVersion = null) { StringBuilder strbuild = new StringBuilder(); using (XmlWriter writer = XmlWriter.Create(strbuild, CreateXmlWriterSettings(false))) { writer.WriteStartElement("Request"); writer.WriteStartElement("Credentials"); writer.WriteStartElement("RegistrationKey"); writer.WriteString(registrationKey ?? PrefC.GetString(PrefName.RegistrationKey)); writer.WriteEndElement(); writer.WriteStartElement("PracticeTitle"); writer.WriteString(practiceTitle ?? PrefC.GetString(PrefName.PracticeTitle)); writer.WriteEndElement(); writer.WriteStartElement("PracticePhone"); writer.WriteString(practicePhone ?? PrefC.GetString(PrefName.PracticePhone)); writer.WriteEndElement(); writer.WriteStartElement("ProgramVersion"); writer.WriteString(programVersion ?? PrefC.GetString(PrefName.ProgramVersion)); writer.WriteEndElement(); writer.WriteStartElement("ServiceCode"); writer.WriteString(serviceCode.ToString()); writer.WriteEndElement(); writer.WriteEndElement(); //Credentials writer.WriteRaw(payloadContentxAsXml); writer.WriteEndElement(); //Request } return(strbuild.ToString()); }
private string GetHostedUrlForCode(eServiceCode code) { switch (code) { case (eServiceCode.MobileWeb): return("http://127.0.0.1:5000/MobileWeb.html"); case (eServiceCode.PatientPortal): case (eServiceCode.PatientPortalMakePayment): case (eServiceCode.PatientPortalViewStatement): return("http://127.0.0.1:4000/PatientPortal.html"); case (eServiceCode.SignupPortal): return("http://127.0.0.1:8888/SignupPortal"); case (eServiceCode.WebForms): return("http://127.0.0.1:3000/WebForms.html"); case (eServiceCode.WebSched): case (eServiceCode.WebSchedASAP): case (eServiceCode.WebSchedNewPatAppt): return("http://127.0.0.1:8000/WebSched.html"); default: return(""); } }
public static RepeatCharge GetRepeatChargeCustomers(eServiceCode eService, long patNum) { return(DataAction.GetCustomers(() => { var all = RepeatCharges.Refresh(patNum).ToList(); var link = EServiceCodeLink.GetAll().FirstOrDefault(x => x.EService == eService) ?? new EServiceCodeLink(); return all.FirstOrDefault(x => x.ProcCode == link.ProcCode); })); }
///<summary>returns all eServiceSignals for a given service within the date range, inclusive.</summary> public static List<EServiceSignal> GetServiceHistory(eServiceCode serviceCode,DateTime dateStart,DateTime dateStop) { if(RemotingClient.RemotingRole==RemotingRole.ClientWeb) { return Meth.GetObject<List<EServiceSignal>>(MethodBase.GetCurrentMethod(),serviceCode,dateStart,dateStop); } string command="SELECT * FROM eservicesignal " +"WHERE ServiceCode="+POut.Int((int)serviceCode)+" " +"AND SigDateTime BETWEEN "+POut.Date(dateStart)+" AND "+POut.Date(dateStop.Date.AddDays(1))+" " +"ORDER BY SigDateTime DESC, Severity DESC"; return Crud.EServiceSignalCrud.SelectMany(command); }
///<summary>returns all eServiceSignals for a given service within the date range, inclusive.</summary> public static List <EServiceSignal> GetServiceHistory(eServiceCode serviceCode, DateTime dateStart, DateTime dateStop, int limit = 0) { if (RemotingClient.RemotingRole == RemotingRole.ClientWeb) { return(Meth.GetObject <List <EServiceSignal> >(MethodBase.GetCurrentMethod(), serviceCode, dateStart, dateStop, limit)); } string command = "SELECT * FROM eservicesignal " + "WHERE ServiceCode=" + POut.Int((int)serviceCode) + " " + "AND SigDateTime BETWEEN " + POut.Date(dateStart) + " AND " + POut.Date(dateStop.Date.AddDays(1)) + " " + "ORDER BY SigDateTime DESC, Severity DESC"; if (limit > 0) { command = DbHelper.LimitOrderBy(command, limit); } return(Crud.EServiceSignalCrud.SelectMany(command)); }
///<summary>Inserts a healthy heartbeat.</summary> public static void InsertHeartbeatForService(eServiceCode serviceCode) { if (RemotingClient.RemotingRole == RemotingRole.ClientWeb) { Meth.GetVoid(MethodBase.GetCurrentMethod(), serviceCode); return; } AlertItems.DeleteFor(AlertType.EConnectorDown); string command = "SELECT * FROM eservicesignal WHERE ServiceCode=" + POut.Int((int)serviceCode) + " AND Severity IN (" + POut.Int((int)eServiceSignalSeverity.NotEnabled) + "," + POut.Int((int)eServiceSignalSeverity.Working) + "," + POut.Int((int)eServiceSignalSeverity.Critical) + ") ORDER BY SigDateTime DESC " + DbHelper.LimitWhere(1);//only select not enabled, working, and critical statuses. EServiceSignal eServiceSignalLast = Crud.EServiceSignalCrud.SelectOne(command); DateTime dtNow = MiscData.GetNowDateTime(); //If initializing or changing state to working from not working, insert two signals; An anchor and a rolling timestamp. if (eServiceSignalLast == null || eServiceSignalLast.Severity != eServiceSignalSeverity.Working) //First ever heartbeat or critical which was not previously critical. { if (eServiceSignalLast != null && eServiceSignalLast.Severity == eServiceSignalSeverity.Critical //Do not create a signal if the eConnector was stopped because of an update && (eServiceSignalLast.SigDateTime > UpdateHistories.GetLastUpdateHistory().DateTimeUpdated || UpdateHistories.GetLastUpdateHistory().DateTimeUpdated.AddMinutes(10) < dtNow)) { //Changing from critical to working so alert user that this change took place and tell them how long we were in critical state. //Insert() will also insert Alert. Insert(new EServiceSignal() { ServiceCode = (int)serviceCode, Severity = eServiceSignalSeverity.Error, SigDateTime = dtNow, IsProcessed = false, Description = "Listener was critical for " + DateTime.Now.Subtract(eServiceSignalLast.SigDateTime).ToStringHmm() }); } Insert(new EServiceSignal() { ServiceCode = (int)serviceCode, Severity = eServiceSignalSeverity.Working, SigDateTime = dtNow, IsProcessed = true, Description = "Heartbeat Anchor" }); //anchor heartbeat Insert(new EServiceSignal() { ServiceCode = (int)serviceCode, Severity = eServiceSignalSeverity.Working, SigDateTime = dtNow.AddSeconds(1), IsProcessed = true, Description = "Heartbeat" }); //rolling heartbeat return; } eServiceSignalLast.SigDateTime = dtNow; Update(eServiceSignalLast); }
///<summary>Returns the last known status for the given eService.</summary> public static eServiceSignalSeverity GetServiceStatus(eServiceCode serviceCode) { if (RemotingClient.RemotingRole == RemotingRole.ClientWeb) { return(Meth.GetObject <eServiceSignalSeverity>(MethodBase.GetCurrentMethod(), serviceCode)); } //The only statuses within the eServiceSignalSeverity enum are NotEnabled, Working, and Critical. //All other statuses are used for logging purposes and should not be considered within this method. string command = "SELECT * FROM eservicesignal WHERE ServiceCode=" + POut.Int((int)serviceCode) + " " + "ORDER BY SigDateTime DESC, Severity DESC "; command = DbHelper.LimitOrderBy(command, 1); List <EServiceSignal> listSignal = Crud.EServiceSignalCrud.SelectMany(command); if (listSignal.Count == 0) { //NoSignals exist for this service. return(eServiceSignalSeverity.None); } return(listSignal[0].Severity); }
///<summary>Inserts a healthy heartbeat.</summary> public static void InsertHeartbeatForService(eServiceCode serviceCode) { if(RemotingClient.RemotingRole==RemotingRole.ClientWeb) { Meth.GetVoid(MethodBase.GetCurrentMethod(),serviceCode); return; } string command="SELECT * FROM eservicesignal WHERE ServiceCode="+POut.Int((int)serviceCode) +" AND Severity IN (" +POut.Int((int)eServiceSignalSeverity.NotEnabled)+"," +POut.Int((int)eServiceSignalSeverity.Working)+"," +POut.Int((int)eServiceSignalSeverity.Critical) +") ORDER BY SigDateTime DESC "+DbHelper.LimitWhere(1);//only select not enabled, working, and critical statuses. EServiceSignal eServiceSignalLast=Crud.EServiceSignalCrud.SelectOne(command); //If initializing or changing state to working from not working, insert two signals; An anchor and a rolling timestamp. if(eServiceSignalLast==null || eServiceSignalLast.Severity!=eServiceSignalSeverity.Working) { //First ever heartbeat or critical which was not previously critical. Crud.EServiceSignalCrud.Insert(new EServiceSignal() { ServiceCode=(int)serviceCode,Severity=eServiceSignalSeverity.Working,SigDateTime=DateTime.Now,IsProcessed=true,Description="Heartbeat Anchor" });//anchor heartbeat Crud.EServiceSignalCrud.Insert(new EServiceSignal() { ServiceCode=(int)serviceCode,Severity=eServiceSignalSeverity.Working,SigDateTime=DateTime.Now.AddSeconds(1),IsProcessed=true,Description="Heartbeat" });//rolling heartbeat return; } eServiceSignalLast.SigDateTime=DateTime.Now;//succeptible to system clock being different than server time. But since this code is being run from the server, this should never happen. Crud.EServiceSignalCrud.Update(eServiceSignalLast); }
///<summary>Makes web service call to HQ and validates if the given eService is allowed for the given clinic. ///Set clinicNum==0 to check for a non-clinics practice. Returns true if allowed; otherwise returns false. ///This is just a wrapper for GetEServiceClinicsAllowed().</summary> public static bool IsEServiceClinicAllowed(long clinicNum, eServiceCode eService) { return(GetEServiceClinicsAllowed(new List <long> { clinicNum }, eService).Any(x => x == clinicNum)); }
///<summary>Since repeating charges are saved using the ProcCode of the procedurecode table instead of the PK, this method will join on the ///procedurecode table in order to see if the procCode passed in is linked to within the eservicecodelink table. ///Returns true if there are any links to the procedure code passed in. This method and class are only used by HQ.</summary> public static bool IsProcCodeAnEService(string procCode, out eServiceCode eService) { //No need to check RemotingRole; no call to db. eService = GetEService(procCode); return(eService != eServiceCode.Undefined); }
///<summary>Only call this method from SendPushBackground() or SendPushAlert(). See summary of those methods for documentation. ///If runAsync==true then spawns a worker thread and makes the web call. This method is passive and returns void so no reason to wait for return.</summary> private static void SendPush(PushType pushType, bool isAlert, long mobileAppDeviceNum = 0, long clinicNum = 0, long userNum = 0, List <long> listPrimaryKeys = null, List <string> listTags = null, string alertTitle = null, string alertMessage = null, bool runAsync = true) { void execute() { eServiceCode eService = eServiceCode.EClipboard; switch (pushType) { case PushType.CI_CheckinPatient: case PushType.CI_AddSheet: case PushType.CI_RemoveSheet: case PushType.CI_GoToCheckin: case PushType.CI_NewEClipboardPrefs: case PushType.CI_IsAllowedChanged: case PushType.CI_TreatmentPlan: case PushType.CI_RemoveTreatmentPlan: eService = eServiceCode.EClipboard; break; case PushType.ODM_NewTextMessage: case PushType.ODM_LogoutODUser: eService = eServiceCode.MobileWeb; break; case PushType.None: default: throw new Exception("Unsupported PushType: " + pushType.ToString()); } PushNotificationPayload payload = new PushNotificationPayload { IsAlert = isAlert, AlertMessage = alertMessage ?? "", AlertTitle = alertTitle ?? "", UserNum = userNum, PushNotificationActionJSON = JsonConvert.SerializeObject(new PushNotificationAction() { TypeOfPush = pushType, ListPrimaryKeys = listPrimaryKeys ?? new List <long>(), ListTags = listTags ?? new List <string>() }, typeof(PushNotificationAction), new JsonSerializerSettings()) }; if (mobileAppDeviceNum > 0) //Send to one exact device. { MobileAppDevice mad = MobileAppDevices.GetOne(mobileAppDeviceNum); if (mad == null) { throw new Exception("MobileAppDeviceNum not found: " + mobileAppDeviceNum.ToString()); } payload.DeviceId = mad.UniqueID; payload.ClinicNum = mad.ClinicNum; } else { payload.ClinicNum = clinicNum; } //Validate that this clinic is signed up for eClipboard if the push is related to eClipboard if (eService == eServiceCode.EClipboard && !MobileAppDevices.IsClinicSignedUpForEClipboard(payload.ClinicNum)) { throw new Exception($"ClinicNum {payload.ClinicNum} is not signed up for eClipboard."); } //Validate that this clinic is signed up for MobileWeb if the push is related to ODMobile else if (eService == eServiceCode.MobileWeb && !MobileAppDevices.IsClinicSignedUpForMobileWeb(payload.ClinicNum)) { if (clinicNum > -1 || pushType != PushType.ODM_LogoutODUser) //Logout is allowed to be sent to non-specific clinicNum. All others are not. { throw new Exception($"ClinicNum {payload.ClinicNum} is not signed up for ODMobile."); } } string jsonPayload = JsonConvert.SerializeObject(payload, typeof(PushNotificationPayload), new JsonSerializerSettings()); string result = WebServiceMainHQProxy.GetWebServiceMainHQInstance().SendPushNotification(PayloadHelper.CreatePayload("", eService), jsonPayload); if (result.ToLower() != "success") { throw new Exception(result); } } ODThread th = new ODThread(new ODThread.WorkerDelegate((o) => { execute(); })); th.AddExceptionHandler((e) => { if (MockExceptionHandler != null) { MockExceptionHandler(e); } else { Logger.WriteException(e, "PushNotifications"); } }); th.Name = "SendPush_" + pushType.ToString() + "_ClinicNum_" + clinicNum.ToString() + "_UserNum_" + userNum.ToString(); th.Start(); if (MockExceptionHandler != null || !runAsync) //Join back to main thread to cause this to be a blocking call. Unit tests will always block. { th.Join(Timeout.Infinite); } }
///<summary>Gets the specified number of short GUIDs</summary> ///<returns>First item in the Tuple is the short GUID. Second item is the URL for the short GUID if there is one for this eService.</returns> public static List <ShortGuidResult> GetShortGUIDs(int numberToGet, long clinicNum, eServiceCode eService) { List <PayloadItem> listPayloadItems = new List <PayloadItem> { new PayloadItem(clinicNum, "ClinicNum"), new PayloadItem(numberToGet, "NumberShortGUIDsToGet") }; string officeData = WebServiceMainHQProxy.CreateWebServiceHQPayload(WebServiceMainHQProxy.CreatePayloadContent(listPayloadItems), eService); string result = WebServiceMainHQProxy.GetWebServiceMainHQInstance().GenerateShortGUIDs(officeData); return(WebServiceMainHQProxy.DeserializeOutput <List <ShortGuidResult> >(result, "ListShortGuidResults")); }
///<summary>Helper to interpret output from GetEServiceSetupFull(). ///Indicates if HQ says this account is registered for the given eService.</summary> public static bool IsEServiceActive(EServiceSetup.SignupOut signupOut, eServiceCode eService) { return(GetSignups <WebServiceMainHQProxy.EServiceSetup.SignupOut.SignupOutEService>(signupOut, eService) .Any(x => x.IsEnabled)); }
///<summary>Returns an XML payload that includes common information required by most HQ hosted services (e.g. reg key, program version, etc).</summary> ///<param name="registrationKey">An Open Dental distributed registration key that HQ has on file. Do not include hyphens.</param> ///<param name="practiceTitle">Any string is acceptable.</param> ///<param name="practicePhone">Any string is acceptable.</param> ///<param name="programVersion">Typically major.minor.build.revision. E.g. 12.4.58.0</param> ///<param name="listPayloadItems">All items that need to be included with the payload.</param> ///<param name="serviceCode">Used on case by case basis to validate that customer is registered for the given service.</param> ///<returns>An XML string that can be passed into an HQ hosted web method.</returns> public static string CreatePayload( List <PayloadItem> listPayloadItems, eServiceCode serviceCode, string registrationKey = null, string practiceTitle = null, string practicePhone = null, string programVersion = null) { return(CreatePayload(PayloadHelper.CreatePayloadContent(listPayloadItems), serviceCode, registrationKey, practiceTitle, practicePhone, programVersion)); }
public List <long> GetEServiceClinicsAllowed(List <long> listClinicNums, eServiceCode eService) { throw new NotImplementedException(); }
///<summary>Called by local practice db to query HQ for EService setup info. Must remain very lite and versionless. ///This method will determine if clinics are enabled and HQ will include ClinicNum 0 in the output without it first being included in the input. ///If clinics not enabled and an emptly list is passed in, then this method will automatically validate against the practice clinic (ClinicNum 0).</summary> public static List <long> GetEServiceClinicsAllowed(List <long> listClinicNums, eServiceCode eService) { if (MockWebServiceMainHQ != null) { //Using the mock implementation because calling the real guts of this method would be difficult in testing because you would have to have a //database setup with signups for eServices. return(MockWebServiceMainHQ.GetEServiceClinicsAllowed(listClinicNums, eService)); } EServiceSetup.SignupOut signupOut = ReadXml <EServiceSetup.SignupOut> ( WebSerializer.DeserializePrimitiveOrThrow <string> ( GetWebServiceMainHQInstance().EServiceSetup ( CreateWebServiceHQPayload ( WriteXml(new EServiceSetup.SignupIn() { MethodNameInt = (int)EServiceSetup.SetupMethod.ValidateClinics, HasClinics = PrefC.HasClinicsEnabled, SignupPortalPermissionInt = (int)SignupPortalPermission.ReadOnly, Clinics = listClinicNums.Select(x => new EServiceSetup.SignupIn.ClinicLiteIn() { ClinicNum = x }).ToList(), }), eService ) ) ) ); //Include the "Practice" clinic if the calling method didn't specifically provide ClinicNum 0. if (!signupOut.HasClinics && !listClinicNums.Contains(0)) { listClinicNums.Add(0); } return(signupOut.EServices //We only care about the input eService. .FindAll(x => x.EService == eService) //Must be included in the HQ output list in order to be considered valid. .FindAll(x => listClinicNums.Any(y => y == x.ClinicNum)) .Select(x => x.ClinicNum).ToList()); }
private WebServiceMainHQProxy.EServiceSetup.SignupOut.SignupOutEService GetEServiceForCode(eServiceCode code, long clinicNum = 0) { if (code == eServiceCode.IntegratedTexting) { return(new WebServiceMainHQProxy.EServiceSetup.SignupOut.SignupOutSms() { ClinicNum = clinicNum, EServiceCodeInt = (int)code, HostedUrl = GetHostedUrlForCode(code), HostedUrlPayment = "http://debug.hosted.url.payment", //TODO: no idea what to do here. IsEnabled = true, CountryCode = "US", MonthlySmsLimit = 20, SmsContractDate = DateTime.Today.AddYears(-1), }); } return(new WebServiceMainHQProxy.EServiceSetup.SignupOut.SignupOutEService() { ClinicNum = clinicNum, EServiceCodeInt = (int)code, HostedUrl = GetHostedUrlForCode(code), HostedUrlPayment = "http://debug.hosted.url.payment", //TODO: no idea what to do here. IsEnabled = true, }); }
///<summary>Makes web service call to HQ and validates if the given eService is allowed for the practice. ///True indicates that at least 1 clinic and/or the practice iteself is signed up. ///Use IsEServiceClinicAllowed() or GetEServiceClinicsAllowed() if you care about specific clinics. ///This is just a wrapper for GetEServiceClinicsAllowed().</summary> public static bool IsEServiceAllowed(eServiceCode eService) { return(GetEServiceClinicsAllowed(Clinics.GetDeepCopy().Select(x => x.ClinicNum).ToList(), eService).Count > 0); }
public List <long> GetEServiceClinicsAllowed(List <long> listClinicNums, eServiceCode eService) { return(WebServiceMainHQProxy.GetEServiceClinicsAllowed(listClinicNums, eService)); }
///<summary>Helper to interpret output from GetEServiceSetupFull(). ///Gets all signups found for the given eService.</summary> public static List <T> GetSignups <T>(EServiceSetup.SignupOut signupOut, eServiceCode eService) where T : WebServiceMainHQProxy.EServiceSetup.SignupOut.SignupOutEService { return(signupOut.EServices .FindAll(x => x.EService == eService) .Cast <T>().ToList()); }