///<summary>Inserts the SmsToMobile to the database and creates a commlog if necessary.</summary> private static void HandleSentSms(List <SmsToMobile> listSmsToMobiles, bool makeCommLog, Userod user) { //No need to check RemotingRole; no call to db. foreach (SmsToMobile smsToMobile in listSmsToMobiles) { smsToMobile.SmsStatus = SmsDeliveryStatus.Pending; smsToMobile.DateTimeSent = DateTime.Now; if (smsToMobile.PatNum != 0 && makeCommLog) //Patient specified and calling code won't make commlog, make it here. { long userNum = 0; if (user != null) { userNum = user.UserNum; } Commlogs.Insert(new Commlog() { CommDateTime = smsToMobile.DateTimeSent, Mode_ = CommItemMode.Text, Note = "Text message sent: " + smsToMobile.MsgText, PatNum = smsToMobile.PatNum, CommType = Commlogs.GetTypeAuto(CommItemTypeAuto.TEXT), SentOrReceived = CommSentOrReceived.Sent, UserNum = userNum }); } } InsertMany(listSmsToMobiles); }
public static int GetNumReminders(long patNum) { if (RemotingClient.RemotingRole == RemotingRole.ClientWeb) { return(Meth.GetInt(MethodBase.GetCurrentMethod(), patNum)); } long commType = Commlogs.GetTypeAuto(CommItemTypeAuto.REACT); if (commType == 0) { return(0); } string cmd = @"SELECT COUNT(*) AS NumReminders FROM commlog WHERE commlog.CommType=" + POut.Long(commType) + " " + "AND commlog.PatNum=" + POut.Long(patNum); return(PIn.Int(Db.GetScalar(cmd))); }
public static DateTime GetDateLastContacted(long patNum) { if (RemotingClient.RemotingRole == RemotingRole.ClientWeb) { return(Meth.GetObject <DateTime>(MethodBase.GetCurrentMethod(), patNum)); } long commType = Commlogs.GetTypeAuto(CommItemTypeAuto.REACT); if (commType == 0) { return(DateTime.MinValue); } string cmd = @"SELECT MAX(commlog.CommDateTime) AS DateLastContacted FROM commlog WHERE commlog.CommType=" + POut.Long(commType) + " " + "AND commlog.PatNum=" + POut.Long(patNum) + " " + "GROUP BY commlog.PatNum"; return(PIn.DateT(Db.GetScalar(cmd))); }
private static void MakeCommlog(Patient pat, string phoneNumber, int statusCode) { string commText = ""; //Status code meanings: // -100: Patient had no phone number // -200: Patient can't text and had no email // 2XX: Successfully sent message // 422: Message has already been sent for patient // Anything else: Failure of some sort. switch (statusCode / 100) //Get general http status codes e.g. -100=-1, 203=2 { case -1: //Failure, no phone number commText = Lans.g("Podium", "Podium review invitation request failed because there was no phone number. Error code:") + " " + statusCode; break; case -2: //Failure, no email commText = Lans.g("Podium", "Podium review invitation request failed because the patient doesn't accept texts " + "and there was no email address. Error code:") + " " + statusCode; break; case 2: //Success https://httpstatusdogs.com/200-ok commText = Lans.g("Podium", "Podium review invitation request successfully sent."); break; case 4: //Client side communication failure https://httpstatusdogs.com/400-bad-request if (statusCode == 422) //422 is Unprocessable Entity, which is sent in this case when a phone number has received an invite already. { commText = Lans.g("Podium", "The request failed because an identical request was previously sent."); } else { commText = Lans.g("Podium", "The request failed to reach Podium with error code:") + " " + statusCode; } break; case 5: //Server side internal failure. https://httpstatusdogs.com/500-internal-server-error commText = Lans.g("Podium", "The request was rejected by the Podium server with error code:") + " " + statusCode; break; default: //General Failure commText = Lans.g("Podium", "The request failed to send with error code:") + " " + statusCode; break; } if (!string.IsNullOrEmpty(commText)) { commText += "\r\n"; } commText += Lans.g("Podium", "The information sent in the request was") + ": \r\n" + Lans.g("Podium", "First name") + ": \"" + pat.FName + "\", " + Lans.g("Podium", "Last name") + ": \"" + pat.LName + "\", " + Lans.g("Podium", "Email") + ": \"" + pat.Email + "\""; if (phoneNumber != "") //If "successful". { commText += ", " + Lans.g("Podium", "Phone number") + ": \"" + phoneNumber + "\""; } else { string wirelessPhone = new string(pat.WirelessPhone.Where(x => char.IsDigit(x)).ToArray()); string homePhone = new string(pat.HmPhone.Where(x => char.IsDigit(x)).ToArray()); List <string> phonesTried = new List <string> { wirelessPhone, homePhone }.FindAll(x => x != ""); string phoneNumbersTried = ", " + Lans.g("Podium", "No valid phone number found."); if (pat.TxtMsgOk == YN.No || (pat.TxtMsgOk == YN.Unknown && PrefC.GetBool(PrefName.TextMsgOkStatusTreatAsNo))) //Used email { phoneNumbersTried = ""; } else if (phonesTried.Count > 0) { phoneNumbersTried = ", " + Lans.g("Podium", "Phone numbers tried") + ": " + string.Join(", ", phonesTried); } commText += phoneNumbersTried; } long programNum = Programs.GetProgramNum(ProgramName.Podium); Commlog commlogCur = new Commlog(); commlogCur.CommDateTime = DateTime.Now; commlogCur.DateTimeEnd = DateTime.Now; commlogCur.PatNum = pat.PatNum; commlogCur.UserNum = 0; //run from server, no valid CurUser commlogCur.CommSource = CommItemSource.ProgramLink; commlogCur.ProgramNum = programNum; commlogCur.CommType = Commlogs.GetTypeAuto(CommItemTypeAuto.MISC); commlogCur.Note = commText; commlogCur.Mode_ = CommItemMode.Text; commlogCur.SentOrReceived = CommSentOrReceived.Sent; Commlogs.Insert(commlogCur); }
///<summary>Used when printing or emailing recall to make a commlog entry without any display.</summary> public static void InsertForRecall(long patNum, CommItemMode _mode, int numberOfReminders, long defNumNewStatus) { if (RemotingClient.RemotingRole == RemotingRole.ClientWeb) { Meth.GetVoid(MethodBase.GetCurrentMethod(), patNum, _mode, numberOfReminders, defNumNewStatus); return; } long recallType = Commlogs.GetTypeAuto(CommItemTypeAuto.RECALL); string command; string datesql = "CURDATE()"; if (DataConnection.DBtype == DatabaseType.Oracle) { datesql = "(SELECT CURRENT_DATE FROM dual)"; } if (recallType != 0) { command = "SELECT COUNT(*) FROM commlog WHERE "; command += DbHelper.DateColumn("CommDateTime") + " = " + datesql; command += " AND PatNum=" + POut.Long(patNum) + " AND CommType=" + POut.Long(recallType) + " AND Mode_=" + POut.Long((int)_mode) + " AND SentOrReceived=1"; if (Db.GetCount(command) != "0") { return; } } Commlog com = new Commlog(); com.PatNum = patNum; com.CommDateTime = DateTime.Now; com.CommType = recallType; com.Mode_ = _mode; com.SentOrReceived = CommSentOrReceived.Sent; com.Note = ""; if (numberOfReminders == 0) { com.Note = Lans.g("FormRecallList", "Recall reminder."); } else if (numberOfReminders == 1) { com.Note = Lans.g("FormRecallList", "Second recall reminder."); } else if (numberOfReminders == 2) { com.Note = Lans.g("FormRecallList", "Third recall reminder."); } else { com.Note = Lans.g("FormRecallList", "Recall reminder:") + " " + (numberOfReminders + 1).ToString(); } if (defNumNewStatus == 0) { com.Note += " " + Lans.g("Commlogs", "Status None"); } else { com.Note += " " + DefC.GetName(DefCat.RecallUnschedStatus, defNumNewStatus); } com.UserNum = Security.CurUser.UserNum; Insert(com); }
///<summary>Used when printing or emailing recall to make a commlog entry without any display. ///Set commSource to the corresponding entity that is making this recall. E.g. Web Sched. ///If the commSource is a 3rd party, set it to ProgramLink and make an overload that accepts the ProgramNum.</summary> public static Commlog InsertForRecall(long patNum, CommItemMode _mode, int numberOfReminders, long defNumNewStatus, CommItemSource commSource, long userNum, DateTime dateTimeNow) { if (RemotingClient.RemotingRole == RemotingRole.ClientWeb) { return(Meth.GetObject <Commlog>(MethodBase.GetCurrentMethod(), patNum, _mode, numberOfReminders, defNumNewStatus, commSource, userNum, dateTimeNow)); } long recallType = Commlogs.GetTypeAuto(CommItemTypeAuto.RECALL); string command; string datesql = "CURDATE()"; if (DataConnection.DBtype == DatabaseType.Oracle) { datesql = "(SELECT CURRENT_DATE FROM dual)"; } if (recallType != 0) { command = "SELECT * FROM commlog WHERE "; command += DbHelper.DtimeToDate("CommDateTime") + " = " + datesql; command += " AND PatNum=" + POut.Long(patNum) + " AND CommType=" + POut.Long(recallType) + " AND Mode_=" + POut.Long((int)_mode) + " AND SentOrReceived=1"; List <Commlog> listComms = Crud.CommlogCrud.SelectMany(command).OrderByDescending(x => x.CommDateTime).ToList(); if (listComms.Count > 0) { return(listComms[0]); } } Commlog com = new Commlog(); com.PatNum = patNum; com.CommDateTime = dateTimeNow; com.CommType = recallType; com.Mode_ = _mode; com.SentOrReceived = CommSentOrReceived.Sent; com.Note = ""; if (numberOfReminders == 0) { com.Note = Lans.g("FormRecallList", "Recall reminder."); } else if (numberOfReminders == 1) { com.Note = Lans.g("FormRecallList", "Second recall reminder."); } else if (numberOfReminders == 2) { com.Note = Lans.g("FormRecallList", "Third recall reminder."); } else { com.Note = Lans.g("FormRecallList", "Recall reminder:") + " " + (numberOfReminders + 1).ToString(); } if (defNumNewStatus == 0) { com.Note += " " + Lans.g("Commlogs", "Status None"); } else { com.Note += " " + Defs.GetName(DefCat.RecallUnschedStatus, defNumNewStatus); } com.UserNum = userNum; com.CommSource = commSource; com.CommlogNum = Insert(com); EhrMeasureEvent newMeasureEvent = new EhrMeasureEvent(); newMeasureEvent.DateTEvent = com.CommDateTime; newMeasureEvent.EventType = EhrMeasureEventType.ReminderSent; newMeasureEvent.PatNum = com.PatNum; newMeasureEvent.MoreInfo = com.Note; EhrMeasureEvents.Insert(newMeasureEvent); return(com); }
///<summary>Attempts to find exact match for patient. If found, creates commlog, associates Patnum, and inserts into DB. ///Otherwise, it simply inserts SmsFromMobiles into the DB. ClinicNum should have already been set before calling this function.</summary> public static void ProcessInboundSms(List <SmsFromMobile> listMessages) { if (listMessages == null || listMessages.Count == 0) { return; } List <SmsBlockPhone> listBlockedPhones = SmsBlockPhones.GetDeepCopy(); for (int i = 0; i < listMessages.Count; i++) { SmsFromMobile sms = listMessages[i]; if (listBlockedPhones.Any(x => TelephoneNumbers.AreNumbersEqual(x.BlockWirelessNumber, sms.MobilePhoneNumber))) { continue; //The office has blocked this number. } sms.DateTimeReceived = DateTime.Now; SmsPhone smsPhone = SmsPhones.GetByPhone(sms.SmsPhoneNumber); string countryCode = CultureInfo.CurrentCulture.Name.Substring(CultureInfo.CurrentCulture.Name.Length - 2); if (smsPhone != null) { sms.ClinicNum = smsPhone.ClinicNum; countryCode = smsPhone.CountryCode; } //First try the clinic that belongs to this phone. List <long> listClinicNums = new List <long>(); if (sms.ClinicNum != 0) { listClinicNums.Add(sms.ClinicNum); } List <long[]> listPatNums = FindPatNums(sms.MobilePhoneNumber, countryCode, listClinicNums); if (listPatNums.Count == 0 && listClinicNums.Count > 0) //Could not find that patient in this clinic so try again for all clinics. { listPatNums = FindPatNums(sms.MobilePhoneNumber, countryCode); } sms.MatchCount = listPatNums.Count; //Item1=PatNum; Item2=Guarantor if (listPatNums.Count == 0 || listPatNums.Select(x => x[1]).Distinct().ToList().Count != 1) { //We could not find definitive match, either 0 matches found, or more than one match found with different garantors Insert(sms); continue; } if (listPatNums.Count == 1) { sms.PatNum = listPatNums[0][0]; //PatNum } else { sms.PatNum = listPatNums[0][1]; //GuarantorNum; more than one match, but all have the same garantor. } Commlog comm = new Commlog() { CommDateTime = sms.DateTimeReceived, Mode_ = CommItemMode.Text, Note = sms.MsgText, PatNum = sms.PatNum, CommType = Commlogs.GetTypeAuto(CommItemTypeAuto.TEXT), SentOrReceived = CommSentOrReceived.Received }; sms.CommlogNum = Commlogs.Insert(comm); Insert(sms); } UpdateSmsNotification(); }
///<summary>Attempts to find exact match for patient. If found, creates commlog, associates Patnum, and inserts into DB. ///Otherwise, it simply inserts SmsFromMobiles into the DB. ClinicNum should have already been set before calling this function.</summary> public static void ProcessInboundSms(List <SmsFromMobile> listMessages) { if (listMessages == null || listMessages.Count == 0) { return; } List <SmsBlockPhone> listBlockedPhones = SmsBlockPhones.GetDeepCopy(); for (int i = 0; i < listMessages.Count; i++) { SmsFromMobile sms = listMessages[i]; if (listBlockedPhones.Any(x => TelephoneNumbers.AreNumbersEqual(x.BlockWirelessNumber, sms.MobilePhoneNumber))) { continue; //The office has blocked this number. } sms.DateTimeReceived = DateTime.Now; string countryCode = CultureInfo.CurrentCulture.Name.Substring(CultureInfo.CurrentCulture.Name.Length - 2); if (sms.SmsPhoneNumber != SmsPhones.SHORTCODE) { SmsPhone smsPhone = SmsPhones.GetByPhone(sms.SmsPhoneNumber); if (smsPhone != null) { sms.ClinicNum = smsPhone.ClinicNum; countryCode = smsPhone.CountryCode; } } if (!PrefC.HasClinicsEnabled) { //We want customer side records of this message to list SmsPhones.SHORTCODE as the number on which the message was sent. This ensures we do //not record this communication on a different valid SmsPhone/VLN that it didn't truly take place on. However, on the HQ side, we want //records of this communication to be listed as having taken place on the actual Short Code number. In the case of a Short Code, //sms.SmsPhoneNumber will read "SHORTCODE", which won't be found in the customer's SmsPhone table. As a result, the code to use the //customer's SmsPhone.ClinicNum and Country code cannot be used. Since this code was intended to handle the case where the customer had //turned clinics on->off, we will specifically check if the customer has disabled clinics and only then change the sms.ClinicNum. //Otherwise, trust HQ sent the correct ClinicNum. Since we expect to only use Short Codes in the US/Canada, we will trust the server we //are processing inbound sms will have the correct country code, which will be used here. sms.ClinicNum = 0; } //First try the clinic that belongs to this phone. List <long> listClinicNums = new List <long>(); if (sms.ClinicNum != 0) { listClinicNums.Add(sms.ClinicNum); } List <long[]> listPatNums = FindPatNums(sms.MobilePhoneNumber, countryCode, listClinicNums); if (listPatNums.Count == 0 && listClinicNums.Count > 0) //Could not find that patient in this clinic so try again for all clinics. { listPatNums = FindPatNums(sms.MobilePhoneNumber, countryCode); } sms.MatchCount = listPatNums.Count; //Item1=PatNum; Item2=Guarantor if (listPatNums.Count == 0 || listPatNums.Select(x => x[1]).Distinct().ToList().Count != 1) { //We could not find definitive match, either 0 matches found, or more than one match found with different garantors Insert(sms); //Alert ODMobile where applicable. PushNotificationUtils.ODM_NewTextMessage(sms); continue; } if (listPatNums.Count == 1) { sms.PatNum = listPatNums[0][0]; //PatNum } else { sms.PatNum = listPatNums[0][1]; //GuarantorNum; more than one match, but all have the same garantor. } Commlog comm = new Commlog() { CommDateTime = sms.DateTimeReceived, Mode_ = CommItemMode.Text, Note = sms.MsgText, PatNum = sms.PatNum, CommType = Commlogs.GetTypeAuto(CommItemTypeAuto.TEXT), SentOrReceived = CommSentOrReceived.Received }; sms.CommlogNum = Commlogs.Insert(comm); Insert(sms); //Alert ODMobile where applicable. PushNotificationUtils.ODM_NewTextMessage(sms, sms.PatNum); } //We used to update the SmsNotification indicator via a queries and a signal here. Now managed by the eConnector. }