1343 lines
65 KiB
C#
1343 lines
65 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using System.Text;
|
||
using Sdaleo;
|
||
using Sdaleo.Systems.SQLServer;
|
||
using Pluto.Api;
|
||
using System.Data;
|
||
using Sdaleo.Systems;
|
||
using Yaulw.Win32;
|
||
using Sdaleo.Systems.Advantage;
|
||
|
||
namespace PlutoServer.MSL.Connectors
|
||
{
|
||
public static class MedisoftConnector
|
||
{
|
||
internal static string MAKE_SURE_APOSTROPHY_IS_SQL_READY(string str)
|
||
{
|
||
if (!String.IsNullOrEmpty(str))
|
||
{
|
||
str = str.Replace("'", "''");
|
||
return str;
|
||
}
|
||
return String.Empty;
|
||
}
|
||
|
||
internal static bool IS_VALID_FOUR_DIGIT_PIN(string fourdigitpin)
|
||
{
|
||
if (!String.IsNullOrEmpty(fourdigitpin))
|
||
{
|
||
fourdigitpin = fourdigitpin.Trim();
|
||
if (fourdigitpin.Length == 4)
|
||
{
|
||
foreach (char c in fourdigitpin)
|
||
{
|
||
if (!Char.IsDigit(c))
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
|
||
#region System / Setup Specific
|
||
|
||
/// <summary>
|
||
/// Retrieve the entire Practice List for the given Shared DB Credential * Credential must point to Shared DB *
|
||
/// </summary>
|
||
/// <param name="credential"></param>
|
||
/// <returns></returns>
|
||
public static DBRetVal GetPracticeList(AdvantageCredential credential)
|
||
{
|
||
if (credential != null)
|
||
{
|
||
DB db = DB.Create(credential);
|
||
DBRetVal retVal = db.FillDataTable("SELECT [DataSet Name],[Data Path],[UserAPIKey] FROM [MWDBList]");
|
||
if (!retVal.IsValid)
|
||
MSLSpecific.Logger.Error("Medisoft. Failed to retrieve Practice List for DataSource:{0}", credential.DataSource);
|
||
return retVal;
|
||
}
|
||
return new DBRetVal();
|
||
}
|
||
|
||
/// <summary>
|
||
/// Retrieve the userapi key for a given practice, given Shared DB Credential * Credential must point to Shared DB *
|
||
/// </summary>
|
||
/// <param name="credential"></param>
|
||
/// <returns></returns>
|
||
public static string GetUserApiKeyForPractice(AdvantageCredential credential, string DataSetOrDataBaseName, out bool bErrorOccured)
|
||
{
|
||
bErrorOccured = true;
|
||
if (credential != null && !String.IsNullOrEmpty(DataSetOrDataBaseName))
|
||
{
|
||
DB db = DB.Create(credential);
|
||
DBRetVal retVal = db.ExecuteScalar(String.Format("SELECT [UserAPIKey] FROM [MWDBList] WHERE [DataSet Name]='{0}'", MAKE_SURE_APOSTROPHY_IS_SQL_READY(DataSetOrDataBaseName)));
|
||
bErrorOccured = retVal.ErrorOccured;
|
||
if(retVal.IsValid)
|
||
return retVal.GetScalarRetVal().Trim();
|
||
}
|
||
return String.Empty;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Use this to Set the User API Key * Credential must point to Shared DB *
|
||
/// </summary>
|
||
/// <param name="credential"></param>
|
||
/// <param name="PracticeName"></param>
|
||
/// <param name="UserApiKey"></param>
|
||
/// <returns></returns>
|
||
public static bool SetUserApiKeyForPractice(AdvantageCredential credential, string DataSetOrDataBaseName, string UserApiKey)
|
||
{
|
||
if (credential != null && !String.IsNullOrEmpty(DataSetOrDataBaseName))
|
||
{
|
||
DB db = DB.Create(credential);
|
||
DBRetVal retVal = db.ExecuteNonQuery(String.Format("UPDATE [MWDBList] SET [UserApiKey]='{0}' WHERE [DataSet Name]='{1}'", UserApiKey, MAKE_SURE_APOSTROPHY_IS_SQL_READY(DataSetOrDataBaseName)));
|
||
if (!retVal.IsValid)
|
||
MSLSpecific.Logger.Error("Medisoft. Failed to set ApiKey for DataSource:{0} DataSet:{1}", credential.DataSource, DataSetOrDataBaseName);
|
||
return retVal.IsValid;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
/// <summary>
|
||
/// we must ensure uniqueness amongst all our userapikeys (Lytec and somehow Medisoft get into an
|
||
/// invalid state) where they duplicate them * Credential must point to Shared DB *
|
||
/// </summary>
|
||
/// <param name="credential"></param>
|
||
/// <param name="PracticeName"></param>
|
||
/// <param name="UserApiKey"></param>
|
||
/// <returns></returns>
|
||
public static void CleanUpDuplicateUserApiKeyExists(AdvantageCredential credential)
|
||
{
|
||
DBRetVal retVal = GetPracticeList(credential);
|
||
if (retVal.IsValid)
|
||
{
|
||
Stack<string> userApiStack = new Stack<string>();
|
||
foreach (DataRow row in retVal.GetDataTableRetVal().Rows)
|
||
{
|
||
string UserApiKey = DataRet.Retrieve(row["UserAPIKey"]);
|
||
if (!String.IsNullOrEmpty(UserApiKey))
|
||
{
|
||
if (!userApiStack.Contains(UserApiKey))
|
||
{
|
||
userApiStack.Push(UserApiKey);
|
||
}
|
||
else
|
||
{
|
||
// we found a duplicate!!! (Clear the UserApiKey for that Database - IMP!)
|
||
string DBName = DataRet.Retrieve(row["DataSet Name"]);
|
||
SetUserApiKeyForPractice(credential, DBName, String.Empty);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region User Authentication
|
||
|
||
/// <summary>
|
||
/// User Authentication
|
||
/// </summary>
|
||
/// <param name="SystemApiKey"></param>
|
||
/// <param name="User"></param>
|
||
/// <param name="Password"></param>
|
||
/// <returns></returns>
|
||
public static UserInfo1 AuthenticateUserLogin(string SystemApiKey, string User, string Password)
|
||
{
|
||
if (!String.IsNullOrEmpty(User) && !String.IsNullOrEmpty(Password))
|
||
{
|
||
AdvantageCredential credential = DBCache.GetAdvantageConnection(SystemApiKey);
|
||
DB db = DB.Create(credential);
|
||
DBRetVal result = db.FillDataTable(String.Format("SELECT [Code],[Name],[Access Level],[Password] FROM [mwSEC] Where upper([Code])='{0}'", MAKE_SURE_APOSTROPHY_IS_SQL_READY(User).ToUpper()));
|
||
//if ((result != null) && (result.IsValid)) /* Rameshes fix that should not be needed and didn't make sense */
|
||
if (result.IsValid)
|
||
{
|
||
DataRow row = result.GetDataTableFirstRow();
|
||
string dbName = DataRet.Retrieve(row["Name"]);
|
||
string dbPwd = DataRet.Retrieve(row["Password"]);
|
||
|
||
// Authenticate! Password must match (case-insensitive) Medisoft also doesn't care about case
|
||
if (!String.IsNullOrEmpty(dbName) && (String.Compare(Password.Trim(), dbPwd, true) == 0))
|
||
{
|
||
UserInfo1 info = new UserInfo1();
|
||
info.AuthToken = SystemApiKey;
|
||
info.Id = DataRet.Retrieve(row["Code"]);
|
||
info.UserName = info.Id;
|
||
|
||
// Seperate First n' Last name, if possible
|
||
info.Name = dbName;
|
||
int nFirst = dbName.IndexOf(' ');
|
||
if (nFirst != -1)
|
||
{
|
||
info.FirstName = dbName.Substring(0, nFirst);
|
||
info.LastName = dbName.Substring(nFirst + 1);
|
||
}
|
||
else
|
||
{
|
||
info.FirstName = dbName;
|
||
info.LastName = "";
|
||
}
|
||
|
||
// Authenticated, return the object
|
||
info.IsProvider = true;
|
||
return info;
|
||
}
|
||
}
|
||
// Users must be setup with Mobile Privilege * ignore code below *
|
||
//else
|
||
//{
|
||
// // Check to see if any users are set up in the table
|
||
// result = db.ExecuteScalar("SELECT COUNT([Code]) FROM [mwSEC]");
|
||
// uint nCount = 0;
|
||
|
||
// // If there no users, let them in anyway
|
||
// if (result.IsValid && uint.TryParse(result.GetScalarRetVal(), out nCount) && nCount == 0)
|
||
// {
|
||
// UserInfo1 info = new UserInfo1();
|
||
// info.AuthToken = SystemApiKey;
|
||
// info.Id = "(Unspecified)";
|
||
// info.UserName = "(Unspecified)";
|
||
|
||
// // Default Authenticated, return the object (No Users exist in table)
|
||
// info.IsProvider = true;
|
||
// return info;
|
||
// }
|
||
//}
|
||
}
|
||
return null;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Pin Authentication
|
||
/// </summary>
|
||
/// <param name="SystemApiKey"></param>
|
||
/// <param name="User"></param>
|
||
/// <param name="pin"></param>
|
||
/// <returns></returns>
|
||
public static UserInfo1 AuthenticateUserPIN(string SystemApiKey, string User, string pin)
|
||
{
|
||
if (!String.IsNullOrEmpty(User) && IS_VALID_FOUR_DIGIT_PIN(pin))
|
||
{
|
||
AdvantageCredential credential = DBCache.GetAdvantageConnection(SystemApiKey);
|
||
DB db = DB.Create(credential);
|
||
DBRetVal result = db.FillDataTable(String.Format("SELECT [Code],[Name],[MobilePIN] FROM [mwSEC] Where upper([Code])='{0}'", MAKE_SURE_APOSTROPHY_IS_SQL_READY(User).ToUpper()));
|
||
if (result.IsValid)
|
||
{
|
||
DataRow row = result.GetDataTableFirstRow();
|
||
string dbName = DataRet.Retrieve(row["Name"]);
|
||
string dbPin = DataRet.Retrieve(row["MobilePIN"]);
|
||
|
||
// Authenticate! Password must match (case-insensitive) Medisoft also doesn't care about case
|
||
if (!String.IsNullOrEmpty(dbName) && (String.Compare(pin.Trim(), dbPin, true) == 0))
|
||
{
|
||
UserInfo1 info = new UserInfo1();
|
||
info.AuthToken = SystemApiKey;
|
||
info.Id = DataRet.Retrieve(row["Code"]);
|
||
info.UserName = info.Id;
|
||
|
||
// Seperate First n' Last name, if possible
|
||
info.Name = dbName;
|
||
int nFirst = dbName.IndexOf(' ');
|
||
if (nFirst != -1)
|
||
{
|
||
info.FirstName = dbName.Substring(0, nFirst);
|
||
info.LastName = dbName.Substring(nFirst + 1);
|
||
}
|
||
else
|
||
{
|
||
info.FirstName = dbName;
|
||
info.LastName = "";
|
||
}
|
||
|
||
// Authenticated, return the object
|
||
info.IsProvider = true;
|
||
return info;
|
||
}
|
||
}
|
||
}
|
||
return null;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Create Pin
|
||
/// </summary>
|
||
/// <param name="SystemApiKey"></param>
|
||
/// <param name="User"></param>
|
||
/// <param name="pin"></param>
|
||
/// <returns></returns>
|
||
public static bool CreatePin(string SystemApiKey, string User, string pin)
|
||
{
|
||
if (!String.IsNullOrEmpty(User) && IS_VALID_FOUR_DIGIT_PIN(pin))
|
||
{
|
||
AdvantageCredential credential = DBCache.GetAdvantageConnection(SystemApiKey);
|
||
DB db = DB.Create(credential);
|
||
string sql = String.Format("UPDATE [mwSEC] SET [MobilePIN]='{0}' WHERE upper([Code])='{1}'", MAKE_SURE_APOSTROPHY_IS_SQL_READY(pin), MAKE_SURE_APOSTROPHY_IS_SQL_READY(User).ToUpper());
|
||
DBRetVal result = db.ExecuteNonQuery(sql);
|
||
return result.IsValid;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Pin is Set
|
||
/// </summary>
|
||
/// <param name="SystemApiKey"></param>
|
||
/// <param name="User"></param>
|
||
/// <returns></returns>
|
||
public static bool PinIsSet(string SystemApiKey, string User)
|
||
{
|
||
if (!String.IsNullOrEmpty(User))
|
||
{
|
||
AdvantageCredential credential = DBCache.GetAdvantageConnection(SystemApiKey);
|
||
DB db = DB.Create(credential);
|
||
string sql = String.Format("SELECT [MobilePIN] FROM [mwSEC] Where upper([Code])='{0}'", MAKE_SURE_APOSTROPHY_IS_SQL_READY(User).ToUpper());
|
||
DBRetVal result = db.ExecuteScalar(sql);
|
||
if (result.IsValid)
|
||
{
|
||
string currentPin = DataRet.Retrieve(result.GetScalarRetVal());
|
||
return IS_VALID_FOUR_DIGIT_PIN(currentPin);
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region Medisoft User Options
|
||
|
||
internal enum DefaultCase
|
||
{
|
||
DateModified = 0,
|
||
HighestCase = 1,
|
||
LowestCase = 2
|
||
}
|
||
/// <summary>
|
||
/// Which is the default case to use?
|
||
/// </summary>
|
||
/// <param name="SystemApiKey"></param>
|
||
/// <returns></returns>
|
||
internal static DefaultCase GetDefaultCase(string SystemApiKey)
|
||
{
|
||
AdvantageCredential credential = DBCache.GetAdvantageConnection(SystemApiKey);
|
||
DB db = DB.Create(credential);
|
||
DBRetVal result = db.ExecuteScalar("SELECT [Case Default] from [MWOPT]");
|
||
if (result.IsValid)
|
||
{
|
||
try
|
||
{
|
||
DefaultCase Case = (DefaultCase) Enum.Parse(typeof(DefaultCase), result.GetScalarRetVal());
|
||
return Case;
|
||
}
|
||
catch (Exception e)
|
||
{
|
||
MSLSpecific.Logger.Error("Failed to retrieve Default Case", e);
|
||
}
|
||
}
|
||
return DefaultCase.DateModified;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Use CopayRemainder Calculation or plain Patient Balance Calculation
|
||
/// </summary>
|
||
/// <param name="SystemApiKey"></param>
|
||
/// <returns></returns>
|
||
internal static bool UseCopayRemainderCalculation(string SystemApiKey)
|
||
{
|
||
//AdvantageCredential credential = DBCache.GetAdvantageConnection(SystemApiKey);
|
||
//DB db = DB.Create(credential);
|
||
|
||
////The figureMissedCopay was the Boolean from the mwopt table
|
||
//DBRetVal result = db.ExecuteScalar("SELECT [Case Default] from MWOPT");
|
||
//if (result.IsValid)
|
||
//{
|
||
// bool bSomethingSomething = DataRet.Retrieve<bool>(result.GetScalarRetVal(), false);
|
||
// return bSomethingSomething;
|
||
//}
|
||
|
||
// For Testing Purpose
|
||
if ((DateTime.Now.Ticks % 2) == 0)
|
||
return true;
|
||
else
|
||
return false;
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region Public Simple Info Getters
|
||
|
||
/// <summary>
|
||
/// get Providers
|
||
/// </summary>
|
||
/// <param name="SystemApiKey"></param>
|
||
/// <returns></returns>
|
||
public static ProviderInfo1[] GetProviderList(string SystemApiKey)
|
||
{
|
||
AdvantageCredential credential = DBCache.GetAdvantageConnection(SystemApiKey);
|
||
DB db = DB.Create(credential);
|
||
DBRetVal result = db.FillDataTable("SELECT [Code],[First Name],[Middle Name],[Last Name],[Phone] FROM [MWPHY] WHERE [Inactive] = false");
|
||
List<ProviderInfo1> providers = new List<ProviderInfo1>();
|
||
if (result.IsValid)
|
||
{
|
||
foreach (DataRow row in result.GetDataTableRetVal().Rows)
|
||
{
|
||
ProviderInfo1 info = new ProviderInfo1();
|
||
info.UserId = DataRet.Retrieve(row["Code"]);
|
||
info.FirstName = DataRet.Retrieve(row["First Name"]);
|
||
info.MiddleName = DataRet.Retrieve(row["Middle Name"]);
|
||
info.LastName = DataRet.Retrieve(row["Last Name"]);
|
||
info.Id = -1;
|
||
string phone = DataRet.Retrieve(row["Phone"]);
|
||
if (!String.IsNullOrEmpty(phone) && phone != "( ) -")
|
||
{
|
||
info.Phone = phone;
|
||
}
|
||
providers.Add(info);
|
||
}
|
||
return providers.ToArray();
|
||
}
|
||
return null;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Get Diagnosis
|
||
/// </summary>
|
||
/// <param name="SystemApiKey"></param>
|
||
/// <param name="searchStr"></param>
|
||
/// <returns></returns>
|
||
public static TerminologyInfo1[] GetDiagnosisList(string SystemApiKey, string searchStr)
|
||
{
|
||
AdvantageCredential credential = DBCache.GetAdvantageConnection(SystemApiKey);
|
||
DB db = DB.Create(credential);
|
||
string sql = "SELECT [Code 1],[Description] FROM [MWDIA] WHERE [Inactive] = false";
|
||
if (!String.IsNullOrEmpty(searchStr))
|
||
sql += String.Format(" AND (upper([Code 1]) like '%{0}%' OR upper([Description]) like '%{0}%')", MAKE_SURE_APOSTROPHY_IS_SQL_READY(searchStr).ToUpper());
|
||
|
||
DBRetVal result = db.FillDataTable(sql);
|
||
List<TerminologyInfo1> diagnoses = new List<TerminologyInfo1>();
|
||
if (result.IsValid)
|
||
{
|
||
foreach (DataRow row in result.GetDataTableRetVal().Rows)
|
||
{
|
||
TerminologyInfo1 info = new TerminologyInfo1();
|
||
info.Code = DataRet.Retrieve(row["Code 1"]);
|
||
info.Description = DataRet.Retrieve(row["Description"]);
|
||
diagnoses.Add(info);
|
||
}
|
||
return diagnoses.ToArray();
|
||
}
|
||
return null;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Get Procedures
|
||
/// </summary>
|
||
/// <param name="SystemApiKey"></param>
|
||
/// <param name="chart"></param>
|
||
/// <param name="searchStr"></param>
|
||
/// <returns></returns>
|
||
public static TerminologyInfo1[] GetProceduresList(string SystemApiKey, string chart, string searchStr)
|
||
{
|
||
AdvantageCredential credential = DBCache.GetAdvantageConnection(SystemApiKey);
|
||
DB db = DB.Create(credential);
|
||
string sql = "SELECT [Code 1],[Description],[Default Modifier 1],[Default Modifier 2],[Default Modifier 3],[Default Modifier 4],[Default Units] FROM [MWPRO] WHERE [Inactive] = 0";
|
||
if (!String.IsNullOrEmpty(searchStr))
|
||
sql += String.Format(" AND (upper([Code 1]) like '%{0}%' OR upper([Description]) like '%{0}%')", MAKE_SURE_APOSTROPHY_IS_SQL_READY(searchStr).ToUpper());
|
||
|
||
DBRetVal result = db.FillDataTable(sql);
|
||
List<TerminologyInfo1> procedures = new List<TerminologyInfo1>();
|
||
if (result.IsValid)
|
||
{
|
||
foreach (DataRow row in result.GetDataTableRetVal().Rows)
|
||
{
|
||
TerminologyInfo1 info = new TerminologyInfo1();
|
||
info.Code = DataRet.Retrieve(row["Code 1"]);
|
||
info.Description = DataRet.Retrieve(row["Description"]);
|
||
info.Modifier1 = DataRet.Retrieve(row["Default Modifier 1"]);
|
||
info.Modifier2 = DataRet.Retrieve(row["Default Modifier 2"]);
|
||
info.Modifier3 = DataRet.Retrieve(row["Default Modifier 3"]);
|
||
info.Modifier4 = DataRet.Retrieve(row["Default Modifier 4"]);
|
||
info.Units = DataRet.Retrieve<decimal>(row["Default Units"]);
|
||
procedures.Add(info);
|
||
}
|
||
return procedures.ToArray();
|
||
}
|
||
return null;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Get Facilities
|
||
/// </summary>
|
||
/// <param name="SystemApiKey"></param>
|
||
/// <returns></returns>
|
||
public static FacilityInfo1[] GetFacilitiesList(string SystemApiKey)
|
||
{
|
||
AdvantageCredential credential = DBCache.GetAdvantageConnection(SystemApiKey);
|
||
DB db = DB.Create(credential);
|
||
|
||
string sql = "SELECT [Code],[Name],[Street 1],[Street 2],[City],[State],[Zip Code],[Phone],[Contact],[Email] FROM mwadd WHERE Type='Facility' OR Type='Laboratory' AND [Inactive] = false";
|
||
DBRetVal result = db.FillDataTable(sql);
|
||
List<FacilityInfo1> facilities = new List<FacilityInfo1>();
|
||
if (result.IsValid)
|
||
{
|
||
foreach (DataRow row in result.GetDataTableRetVal().Rows)
|
||
{
|
||
FacilityInfo1 info = new FacilityInfo1();
|
||
info.Code = DataRet.Retrieve(row["Code"]);
|
||
info.Name = DataRet.Retrieve(row["Name"]);
|
||
|
||
// Address Info
|
||
info.Address = new AddressInfo1();
|
||
info.Address.Address1 = DataRet.Retrieve(row["Street 1"]);
|
||
info.Address.Address2 = DataRet.Retrieve(row["Street 2"]);
|
||
info.Address.City = DataRet.Retrieve(row["City"]);
|
||
info.Address.State = DataRet.Retrieve(row["State"]);
|
||
info.Address.Zip = DataRet.Retrieve(row["Zip Code"]);
|
||
|
||
facilities.Add(info);
|
||
}
|
||
return facilities.ToArray();
|
||
}
|
||
return null;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Not implemented (NOT CALLED)
|
||
/// </summary>
|
||
/// <param name="SystemApiKey"></param>
|
||
/// <returns></returns>
|
||
public static ResourceInfo1[] GetResourcesList(string SystemApiKey)
|
||
{
|
||
// Not implemented
|
||
return null;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Get Patients
|
||
/// </summary>
|
||
/// <param name="SystemApiKey"></param>
|
||
/// <param name="lastName"></param>
|
||
/// <param name="firstName"></param>
|
||
/// <param name="dateOfBirth"></param>
|
||
/// <returns></returns>
|
||
public static PatientInfo1[] GetPatientList(string SystemApiKey, string lastName, string firstName, string dateOfBirth)
|
||
{
|
||
AdvantageCredential credential = DBCache.GetAdvantageConnection(SystemApiKey);
|
||
DB db = DB.Create(credential);
|
||
string sql = "SELECT [Chart Number],[First Name],[Middle Name],[Last Name],[Date of Birth] as [Birth Date],[Sex],[Street 1],[Street 2],[City],[State],[Zip Code],[Phone 1],[Phone 2],[Phone 3],[Social Security Number] FROM [MWPAT]";
|
||
|
||
// Allow them to search by patient name or by date of birth,
|
||
// not both that is just too confusing
|
||
bool bWhereIsSet = false;
|
||
if (!String.IsNullOrEmpty(dateOfBirth))
|
||
{
|
||
DateTime dt;
|
||
if (DateTime.TryParse(dateOfBirth, out dt))
|
||
{
|
||
sql = sql + String.Format(" WHERE [Date of Birth] = '{0:D4}-{1:D2}-{2:D2}' ", dt.Year, dt.Month, dt.Day);
|
||
bWhereIsSet = true;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (!String.IsNullOrEmpty(lastName))
|
||
{
|
||
sql = sql + String.Format(" WHERE upper([Last Name]) like '%{0}%' {1}", MAKE_SURE_APOSTROPHY_IS_SQL_READY(lastName).ToUpper(), !String.IsNullOrEmpty(firstName) ? "OR" : "");
|
||
bWhereIsSet = true;
|
||
}
|
||
if (!String.IsNullOrEmpty(firstName) && !String.IsNullOrEmpty(lastName))
|
||
{
|
||
sql = sql + String.Format(" {1} upper([First Name]) like '%{0}%' ", MAKE_SURE_APOSTROPHY_IS_SQL_READY(firstName).ToUpper(), String.IsNullOrEmpty(lastName) ? "WHERE" : "");
|
||
}
|
||
}
|
||
|
||
// Only query for Active Patients
|
||
if(bWhereIsSet)
|
||
sql = sql + " AND [Inactive] = false ";
|
||
else
|
||
sql = sql + " WHERE [Inactive] = false ";
|
||
|
||
// Order Correctly
|
||
sql = sql + " ORDER BY [Last Name],[First Name],[Middle Name] ";
|
||
|
||
DBRetVal result = db.FillDataTable(sql);
|
||
List<PatientInfo1> patients = new List<PatientInfo1>();
|
||
if (result.IsValid)
|
||
{
|
||
foreach (DataRow row in result.GetDataTableRetVal().Rows)
|
||
{
|
||
PatientInfo1 info = FillInPatientInformation(row, false, true);
|
||
patients.Add(info);
|
||
}
|
||
return patients.ToArray();
|
||
}
|
||
return null;
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region Private Static SQL Query Helper
|
||
|
||
/// <summary>
|
||
/// Fills in the Patient Info from the Patient Table Columns
|
||
/// </summary>
|
||
/// <param name="row"></param>
|
||
/// <param name="bFillAsMuchPatientInfoAsPossible">If Set to true, will fill in as much patient information as possible, otherwise will on fill basic patient name / chart information</param>
|
||
/// <param name="bFillInPhoneInfo">if set to true will fill try to fill in phone information</param>
|
||
/// <returns></returns>
|
||
private static PatientInfo1 FillInPatientInformation(DataRow row, bool bFillAsMuchPatientInfoAsPossible, bool bFillInPhoneInfo)
|
||
{
|
||
PatientInfo1 info = new PatientInfo1();
|
||
|
||
// Basic Patient Info (Always fill that information)
|
||
info.ChartId = DataRet.Retrieve(row["Chart Number"]);
|
||
info.Id = DataRet.Retrieve(row["Chart Number"]);
|
||
info.FirstName = DataRet.Retrieve(row["First Name"]);
|
||
info.MiddleName = DataRet.Retrieve(row["Middle Name"]);
|
||
info.LastName = DataRet.Retrieve(row["Last Name"]);
|
||
info.Weight = ""; // we don't track weight
|
||
|
||
// Birth Date & Age Calculation
|
||
info.DOB = DataRet.Retrieve<DateTime>(row["Birth Date"]);
|
||
if (info.DOB > DateTime.MinValue)
|
||
{
|
||
DateTime now = DateTime.Today;
|
||
int age = now.Year - info.DOB.Year;
|
||
if (info.DOB > now.AddYears(-age)) age--;
|
||
info.Age = age.ToString();
|
||
}
|
||
|
||
// Gender
|
||
info.Gender = DataRet.Retrieve(row["Sex"], "Unknown", true);
|
||
|
||
// If we want more details on the Patient, this will be set to false
|
||
if (bFillAsMuchPatientInfoAsPossible)
|
||
{
|
||
// Social Security
|
||
info.SocialSecurity = DataRet.Retrieve(row["Social Security Number"]);
|
||
|
||
// Primary Address
|
||
AddressInfo1 address = new AddressInfo1();
|
||
address.Address1 = DataRet.Retrieve(row["Street 1"]);
|
||
address.Address2 = DataRet.Retrieve(row["Street 2"]);
|
||
address.City = DataRet.Retrieve(row["City"]);
|
||
address.State = DataRet.Retrieve(row["State"]);
|
||
address.Zip = DataRet.Retrieve(row["Zip Code"]);
|
||
info.PrimaryAddress = address;
|
||
}
|
||
|
||
// Phone Number may already be filled in for us
|
||
if (bFillInPhoneInfo)
|
||
{
|
||
// Primary Phone
|
||
string Phone = DataRet.Retrieve(row["Phone 1"]);
|
||
if (!String.IsNullOrEmpty(Phone) && Phone != "( ) -")
|
||
{
|
||
info.PrimaryPhone = Phone;
|
||
}
|
||
else
|
||
{
|
||
Phone = DataRet.Retrieve(row["Phone 2"]);
|
||
if (!String.IsNullOrEmpty(Phone) && Phone != "( ) -")
|
||
{
|
||
info.PrimaryPhone = Phone;
|
||
}
|
||
else
|
||
{
|
||
Phone = DataRet.Retrieve(row["Phone 3"]);
|
||
if (!String.IsNullOrEmpty(Phone) && Phone != "( ) -")
|
||
{
|
||
info.PrimaryPhone = Phone;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
return info;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Basically the same query as Appointment Query except with no Appointment information because all we have
|
||
/// is a Chart
|
||
/// </summary>
|
||
/// <param name="PatientChart">Patient Chart</param>
|
||
/// <returns></returns>
|
||
private static string BuildPatientQuery(string PatientChart, DefaultCase Case)
|
||
{
|
||
if (!String.IsNullOrEmpty(PatientChart))
|
||
{
|
||
StringBuilder sb = new StringBuilder();
|
||
sb.Append("SELECT TOP 1 p.[Chart Number], p.[First Name],p.[Middle Name],p.[Last Name],p.[Date of Birth] as [Birth Date],p.[Sex],p.[Street 1],p.[Street 2],p.[City]");
|
||
//sb.Append(",p.[State],p.[Zip Code],p.[Phone 1],p.[Phone 2],p.[Phone 3],p.[Work Phone],p.[Work Extension], p.[Social Security Number]"); // Not using Work Phone / Work Extension
|
||
sb.Append(",p.[State],p.[Zip Code],p.[Phone 1],p.[Phone 2],p.[Phone 3],p.[Social Security Number]");
|
||
sb.Append(",c.[Copayment Amount] as [Patient Copay]");
|
||
sb.Append(",i.[Name] as [Primary Insurance Name]");
|
||
sb.Append(",h.[Last Name] as [Ref Phy Last Name],h.[First Name] as [Ref Phy First Name],h.[Office] as [Ref Physician Phone],h.[Phone] as [Ref Physician Main Phone], h.[Cell] as [Ref Physician Mobile Phone]");
|
||
sb.Append(" FROM [MWPAT] p LEFT JOIN");
|
||
sb.Append(" [MWCAS] c ON p.[Chart Number] = c.[Chart Number]");
|
||
sb.Append(" LEFT JOIN [MWINS] i ON c.[Insurance Carrier #1] = i.[Code]");
|
||
sb.Append(" LEFT JOIN [MWRPH] h ON c.[Referring Provider] = h.[Code]");
|
||
sb.Append(" WHERE ");
|
||
sb.Append(String.Format("p.[Chart Number] = '{0}' ", MAKE_SURE_APOSTROPHY_IS_SQL_READY(PatientChart)));
|
||
|
||
// Don't forget the order by
|
||
switch (Case)
|
||
{
|
||
case DefaultCase.DateModified:
|
||
sb.Append("Order By c.[Date Modified] DESC");
|
||
break;
|
||
case DefaultCase.HighestCase:
|
||
sb.Append("Order By c.[Case Number] DESC");
|
||
break;
|
||
case DefaultCase.LowestCase:
|
||
sb.Append("Order By c.[Case Number] ASC");
|
||
break;
|
||
}
|
||
return sb.ToString();
|
||
}
|
||
return String.Empty;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Build the Appointment / Patient SQL Query as needed, either specify a Date Range or give a specific ID
|
||
/// </summary>
|
||
/// <param name="startDT"></param>
|
||
/// <param name="endDT"></param>
|
||
/// <returns></returns>
|
||
private static string BuildAppointmentQuery(int nApptID, DateTime startDT, DateTime endDT, string[] providers, string[] resources)
|
||
{
|
||
StringBuilder sb = new StringBuilder();
|
||
sb.Append("SELECT a.[ID],a.[Resource],a.[Date], a.[Status],a.[Start Time],a.[Case Number],a.[Length],a.[Name],a.[Chart Number],a.[Provider],a.[Procedure Code],a.[Note],a.[Color],a.[Reason Code]");
|
||
sb.Append(",a.[Phone] as [Appt Home Phone],a.[Cell Phone] as [Appt Mobile Phone]");
|
||
sb.Append(",p.[First Name],p.[Middle Name],p.[Last Name],p.[Date of Birth] as [Birth Date],p.[Sex],p.[Street 1],p.[Street 2],p.[City]");
|
||
//sb.Append(",p.[State],p.[Zip Code],p.[Phone 1],p.[Phone 2],p.[Phone 3],p.[Work Phone],p.[Work Extension], p.[Social Security Number]"); // Not using Work Phone / Work Extension
|
||
sb.Append(",p.[State],p.[Zip Code],p.[Phone 1],p.[Phone 2],p.[Phone 3],p.[Social Security Number]");
|
||
sb.Append(",c.[Copayment Amount] as [Patient Copay]");
|
||
sb.Append(",r.[Description] as [Reason Description]");
|
||
sb.Append(",i.[Name] as [Primary Insurance Name]");
|
||
sb.Append(",h.[Last Name] as [Ref Phy Last Name],h.[First Name] as [Ref Phy First Name],h.[Office] as [Ref Physician Phone],h.[Phone] as [Ref Physician Main Phone], h.[Cell] as [Ref Physician Mobile Phone]");
|
||
sb.Append(" FROM [OHAPP] a LEFT JOIN");
|
||
sb.Append(" [MWPAT] p ON p.[Chart Number] = a.[Chart Number]");
|
||
sb.Append(" LEFT JOIN [OHRSN] r ON a.[Reason Code] = r.[Code]");
|
||
sb.Append(" LEFT JOIN [MWCAS] c ON a.[Case Number] = c.[Case Number]");
|
||
sb.Append(" LEFT JOIN [MWINS] i ON c.[Insurance Carrier #1] = i.[Code]");
|
||
sb.Append(" LEFT JOIN [MWRPH] h ON c.[Referring Provider] = h.[Code]");
|
||
sb.Append(" WHERE ");
|
||
|
||
// if ID is specified, we are looking for a single appointment,
|
||
// otherwise we are looking for a range
|
||
if (nApptID >= 0)
|
||
{
|
||
sb.Append(String.Format(" [ID] = {0} ", nApptID));
|
||
}
|
||
else
|
||
{
|
||
// [Date] between '10/24/2012' and '10/27/2012' AND
|
||
const string DATE_FORMAT = "{0:D2}/{1:D2}/{2:D4}";
|
||
string StartDate = String.Format(DATE_FORMAT, startDT.Month, startDT.Day, startDT.Year);
|
||
string EndDate = String.Format(DATE_FORMAT, endDT.Month, endDT.Day, endDT.Year);
|
||
sb.Append(String.Format("[Date] between '{0}' AND '{1}' AND ", StartDate, EndDate));
|
||
|
||
// [Appt Time] between '9:00:00 AM' AND '12:30:00 PM'
|
||
string StartTime = startDT.ToString("hh:mm:ss tt");
|
||
string EndTime = endDT.ToString("hh:mm:ss tt");
|
||
sb.Append(String.Format("[Start Time] between '{0}' AND '{1}' ", StartTime, EndTime));
|
||
|
||
// Do we have providers?
|
||
// AND [Provider] in ('LAB',)
|
||
if (providers != null && providers.Length > 0)
|
||
{
|
||
sb.Append("AND [Provider] in ('',"); // Allow '' blank providers
|
||
for (int i = 0; i < providers.Length; ++i)
|
||
{
|
||
sb.Append("'");
|
||
sb.Append(MAKE_SURE_APOSTROPHY_IS_SQL_READY(providers[i]));
|
||
sb.Append("'");
|
||
if (i != providers.Length - 1)
|
||
sb.Append(",");
|
||
}
|
||
sb.Append(") ");
|
||
}
|
||
|
||
// Do we have resources?
|
||
// AND [Resource] in (2, )
|
||
if (resources != null && resources.Length > 0)
|
||
{
|
||
sb.Append("AND [Resource] in ('',"); // Allow '' blank resources
|
||
for (int i = 0; i < resources.Length; ++i)
|
||
{
|
||
sb.Append(resources[i]);
|
||
if (i != resources.Length - 1)
|
||
sb.Append(",");
|
||
}
|
||
sb.Append(") ");
|
||
}
|
||
|
||
// Filter out all Cancelled Appointments
|
||
sb.Append("AND (a.[Status] <> '4' ");
|
||
|
||
// Allow "Break" appointment types
|
||
sb.Append("OR a.[Status] IS NULL) ");
|
||
|
||
// Don't forget the order by
|
||
sb.Append("Order By [Date],[Start Time],[ID]");
|
||
}
|
||
|
||
return sb.ToString();
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region Public Appointment Methods
|
||
|
||
/// <summary>
|
||
/// Retrieve all appointments for the given time period for the given providers or resources
|
||
/// </summary>
|
||
/// <param name="SystemApiKey"></param>
|
||
/// <param name="providerInfo"></param>
|
||
/// <param name="startDate"></param>
|
||
/// <param name="endDate"></param>
|
||
/// <returns></returns>
|
||
public static AppointmentInfo1[] GetAppointments(string SystemApiKey, ProviderInfo1[] providerInfo, ResourceInfo1[] resourceInfo, DateTime startDate, DateTime endDate)
|
||
{
|
||
AdvantageCredential credential = DBCache.GetAdvantageConnection(SystemApiKey);
|
||
DB db = DB.Create(credential);
|
||
|
||
string sql = "";
|
||
List<string> providers = new List<string>();
|
||
List<string> resources = new List<string>();
|
||
if (providerInfo != null)
|
||
{
|
||
foreach (ProviderInfo1 info1 in providerInfo)
|
||
{
|
||
if (!String.IsNullOrEmpty(info1.UserId))
|
||
providers.Add(info1.UserId);
|
||
}
|
||
}
|
||
if (resourceInfo != null)
|
||
{
|
||
foreach (ResourceInfo1 info1 in resourceInfo)
|
||
{
|
||
if (!String.IsNullOrEmpty(info1.Name))
|
||
resources.Add(info1.Name);
|
||
}
|
||
}
|
||
|
||
// Build the Appointment QUERY (don't pass in an Appt ID and it will use a range)
|
||
sql = BuildAppointmentQuery(-1, startDate, endDate, providers.ToArray(), resources.ToArray());
|
||
|
||
DBRetVal result = db.FillDataTable(sql);
|
||
List<AppointmentInfo1> appointments = new List<AppointmentInfo1>();
|
||
if (result.IsValid)
|
||
{
|
||
foreach (DataRow row in result.GetDataTableRetVal().Rows)
|
||
{
|
||
AppointmentInfo1 info = new AppointmentInfo1();
|
||
|
||
info.Id = DataRet.Retrieve<long>(row["ID"]);
|
||
|
||
// Retrieving Description for the Appointment Reason Code via join
|
||
info.Reason = DataRet.Retrieve(row["Reason Description"]);
|
||
|
||
//Retrieving Provider code for the appointment
|
||
info.ProviderCode = DataRet.Retrieve(row["Provider"]);
|
||
|
||
// Let's figgure out the Appointment DTs
|
||
// StartDateTime = DateTime.Parse(string.Format("{0} {1}:{2}:00 AM", today.ToShortDateString(), 2, 15)),
|
||
// EndDateTime = DateTime.Parse(string.Format("{0} {1}:{2}:00 PM", today.ToShortDateString(), 2, 30)),
|
||
DateTime dtDate = DataRet.Retrieve<DateTime>(row["Date"]);
|
||
DateTime dtTime = DataRet.Retrieve<DateTime>(row["Start Time"]);
|
||
int nDuration = DataRet.Retrieve<int>(row["Length"]);
|
||
|
||
info.StartDateTime = DateTime.Parse(string.Format("{0} {1:D2}:{2:D2}:{3:D2}", dtDate.ToShortDateString(), dtTime.Hour, dtTime.Minute, dtTime.Second));
|
||
if (nDuration == 0)
|
||
{
|
||
// Leave it as is (no duration was set)
|
||
info.EndDateTime = info.StartDateTime;
|
||
}
|
||
else
|
||
{
|
||
dtTime = dtTime.AddMinutes(nDuration);
|
||
info.EndDateTime = DateTime.Parse(string.Format("{0} {1:D2}:{2:D2}:{3:D2}", dtDate.ToShortDateString(), dtTime.Hour, dtTime.Minute, dtTime.Second));
|
||
}
|
||
|
||
// Appointment Primary Phone
|
||
bool bAppointmentPhoneFound = false;
|
||
string Phone = DataRet.Retrieve(row["Appt Home Phone"]);
|
||
if (!String.IsNullOrEmpty(Phone) && Phone != "( ) -")
|
||
{
|
||
bAppointmentPhoneFound = true;
|
||
}
|
||
else
|
||
{
|
||
Phone = DataRet.Retrieve(row["Appt Mobile Phone"]);
|
||
if (!String.IsNullOrEmpty(Phone) && Phone != "( ) -")
|
||
bAppointmentPhoneFound = true;
|
||
}
|
||
|
||
// Attach Chart Information (Only the most basic information, try to attach Phone Number if none found in appointment)
|
||
bool bHasChart = (DataRet.Retrieve(row["Chart Number"]) != "");
|
||
if (bHasChart)
|
||
info.Patient = FillInPatientInformation(row, false, !bAppointmentPhoneFound);
|
||
else
|
||
info.AppointmentDescription = DataRet.Retrieve(row["Name"]);
|
||
|
||
// Attach Appointment Phone always, if found
|
||
if (bAppointmentPhoneFound)
|
||
info.AppointmentPhone = Phone;
|
||
|
||
//[Background Color]
|
||
//#define DEFAULT_GRID_TEXT_COLOR (RGB(0,0,0))
|
||
//#define DEFAULT_GRID_BKGND_COLOR (RGB(255,255,255))
|
||
int ColorRef = DataRet.Retrieve<int>(row["Color"], 0);
|
||
if (ColorRef == 0)
|
||
info.AppointmentColor = new AppointmentColor1() { Red = 255, Green = 255, Blue = 255 };
|
||
else
|
||
info.AppointmentColor = new AppointmentColor1() { Red = Functions.GetRValue(ColorRef), Green = Functions.GetGValue(ColorRef), Blue = Functions.GetBValue(ColorRef) };
|
||
|
||
// Determine the Appointment Status
|
||
/*
|
||
* Medisoft Status
|
||
0 – Unconfirmed
|
||
1 – Confirmed
|
||
2 – Checked In
|
||
3 – Missed
|
||
4 – Cancelled
|
||
5 – Being Seen
|
||
6 – Checked Out
|
||
7 – Rescheduled
|
||
* --------------------------
|
||
* Medisoft To Mobile Mapping
|
||
0 – Unconfirmed_Pending
|
||
1 – Confirmed
|
||
2 – CheckedIn_Waiting
|
||
3 – Missed
|
||
4 – Cancelled
|
||
5 – Being Seen
|
||
6 – CheckedOut_Completed
|
||
7 - Rescheduled
|
||
* */
|
||
string status = DataRet.Retrieve(row["Status"]);
|
||
switch (status)
|
||
{
|
||
case "0":
|
||
info.AppointmentStatus = AppointmentStatusEnum.Unconfirmed_Pending;
|
||
break;
|
||
case "1":
|
||
info.AppointmentStatus = AppointmentStatusEnum.Confirmed;
|
||
break;
|
||
case "2":
|
||
info.AppointmentStatus = AppointmentStatusEnum.CheckedIn_Waiting;
|
||
break;
|
||
case "3":
|
||
info.AppointmentStatus = AppointmentStatusEnum.Missed;
|
||
break;
|
||
case "4":
|
||
info.AppointmentStatus = AppointmentStatusEnum.Cancelled;
|
||
break;
|
||
case "5":
|
||
info.AppointmentStatus = AppointmentStatusEnum.BeingSeen;
|
||
break;
|
||
case "6":
|
||
info.AppointmentStatus = AppointmentStatusEnum.CheckedOut_Completed;
|
||
break;
|
||
case "7":
|
||
info.AppointmentStatus = AppointmentStatusEnum.Rescheduled;
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
|
||
// Finally, add the appointment
|
||
appointments.Add(info);
|
||
}
|
||
return appointments.ToArray();
|
||
}
|
||
return null;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Appointment Detail query. Fills in useful information for the patient regarding the Appointment
|
||
/// </summary>
|
||
/// <param name="SystemApiKey"></param>
|
||
/// <param name="ApptID"></param>
|
||
/// <returns></returns>
|
||
public static AppointmentDetail1 GetAppointmentDetail(string SystemApiKey, int ApptID, bool bCalculateBalance)
|
||
{
|
||
AdvantageCredential credential = DBCache.GetAdvantageConnection(SystemApiKey);
|
||
DB db = DB.Create(credential);
|
||
|
||
string sql = BuildAppointmentQuery(ApptID, DateTime.MinValue, DateTime.MinValue, null, null);
|
||
DBRetVal result = db.FillDataTable(sql);
|
||
if (result.IsValid)
|
||
{
|
||
DataRow row = result.GetDataTableFirstRow();
|
||
AppointmentDetail1 detail = new AppointmentDetail1();
|
||
|
||
// Appointment Stuff
|
||
detail.ApptNote = DataRet.Retrieve(row["Note"]);
|
||
detail.ApptReason = DataRet.Retrieve(row["Reason Description"]);
|
||
|
||
// Chart Info
|
||
bool bHasChart = (DataRet.Retrieve(row["Chart Number"]) != "");
|
||
if (bHasChart)
|
||
detail.PatientDetail = GetPatientDetail(SystemApiKey, row, String.Empty, bCalculateBalance);
|
||
|
||
// Return the Appointment Detail Item
|
||
return detail;
|
||
}
|
||
|
||
return null;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Similar to GetAppointmentDetail, except all we have here is only the chart, so no appointment information
|
||
/// </summary>
|
||
/// <param name="SystemApiKey"></param>
|
||
/// <param name="UseThisRowInsteadOfQuery">if this is set to not null (a valid DBRetVal), it will use the DBRetVal and not re-query</param>
|
||
/// <param name="ApptID"></param>
|
||
/// <returns></returns>
|
||
public static PatientDetail1 GetPatientDetail(string SystemApiKey, DataRow UseThisRowInsteadOfQuery, string PatientChart, bool bCalculateBalance)
|
||
{
|
||
AdvantageCredential credential = DBCache.GetAdvantageConnection(SystemApiKey);
|
||
DB db = DB.Create(credential);
|
||
|
||
DataRow row = null;
|
||
// Query only if the row has not been passed in
|
||
if (UseThisRowInsteadOfQuery == null)
|
||
{
|
||
string sql = BuildPatientQuery(PatientChart, GetDefaultCase(SystemApiKey));
|
||
DBRetVal result = db.FillDataTable(sql);
|
||
if (result.IsValid)
|
||
row = result.GetDataTableFirstRow();
|
||
}
|
||
else
|
||
{
|
||
row = UseThisRowInsteadOfQuery;
|
||
}
|
||
|
||
// Fill in the information
|
||
if (row != null)
|
||
{
|
||
PatientDetail1 detail = new PatientDetail1();
|
||
|
||
// Chart Info
|
||
detail.Patient = FillInPatientInformation(row, true, true);
|
||
|
||
// Patient Billing Information
|
||
detail.PatientBilling = new PatientBillingInfo1();
|
||
|
||
detail.PatientBilling.CopayAmount = DataRet.Retrieve<decimal>(row["Patient Copay"], 0);
|
||
detail.PatientBilling.PrimaryInsCarrier = DataRet.Retrieve(row["Primary Insurance Name"]);
|
||
|
||
// Refering Provider comes from Patient Table also
|
||
detail.PatientBilling.RefProvider = DataRet.Retrieve(row["Ref Phy First Name"]) + " " + DataRet.Retrieve(row["Ref Phy Last Name"]);
|
||
|
||
// Fill in Refering Provider Phone
|
||
string Phone = DataRet.Retrieve(row["Ref Physician Phone"]);
|
||
if (!String.IsNullOrEmpty(Phone) && Phone != "( ) -")
|
||
{
|
||
detail.PatientBilling.RefProviderPhone = Phone;
|
||
}
|
||
else
|
||
{
|
||
Phone = DataRet.Retrieve(row["Ref Physician Main Phone"]);
|
||
if (!String.IsNullOrEmpty(Phone) && Phone != "( ) -")
|
||
{
|
||
detail.PatientBilling.RefProviderPhone = Phone;
|
||
}
|
||
else
|
||
{
|
||
Phone = DataRet.Retrieve(row["Ref Physician Mobile Phone"]);
|
||
if (!String.IsNullOrEmpty(Phone) && Phone != "( ) -")
|
||
{
|
||
detail.PatientBilling.RefProviderPhone = Phone;
|
||
}
|
||
}
|
||
}
|
||
|
||
// Calculate Account Balance (May take awhile)
|
||
if (bCalculateBalance)
|
||
{
|
||
detail.PatientBilling.AccountBalance = CalculatePatientBalance(detail.Patient.ChartId, SystemApiKey);
|
||
}
|
||
|
||
// Return the Appointment Detail Item
|
||
return detail;
|
||
}
|
||
|
||
return null;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Used to calculate the Patient Balance (stripped out of Lytec)
|
||
/// </summary>
|
||
/// <param name="Chart"></param>
|
||
/// <returns></returns>
|
||
private static decimal CalculatePatientBalance(string Chart, string SystemApiKey)
|
||
{
|
||
if (!String.IsNullOrEmpty(Chart))
|
||
{
|
||
// Copied from Medisoft Source Code (Sent to my by Scott Toney)
|
||
// Query1: This is used to get the patient balance without the missed copays
|
||
StringBuilder sb1 = new StringBuilder();
|
||
sb1.Append("SELECT SUM([Amount] + ");
|
||
sb1.Append("[Insurance 1 Amount Paid] + ");
|
||
sb1.Append("[Insurance 2 Amount Paid] + ");
|
||
sb1.Append("[Insurance 3 Amount Paid] + ");
|
||
sb1.Append("[Guarantor Amount Paid] + ");
|
||
sb1.Append("[Attorney Amount Paid] + ");
|
||
sb1.Append("[Adjustment Amount] ");
|
||
sb1.Append(") as RemainderBalance ");
|
||
sb1.Append("FROM [MWTRN] ");
|
||
//sb1.Append("WHERE [Transaction type] <= " + QuotedStr('H') + " AND ");
|
||
sb1.Append("WHERE [Transaction type] <= 'H' AND ");
|
||
sb1.Append("( [Guarantor Responsible] = True ) ");
|
||
sb1.Append("AND ([Insurance 1 Paid] = True ) ");
|
||
sb1.Append("AND ([Insurance 2 Paid] = True ) ");
|
||
sb1.Append("AND ([Insurance 3 Paid] = True ) ");
|
||
sb1.Append("AND ([Guarantor Paid] = False ) AND ");
|
||
sb1.Append("[case number] IN ");
|
||
sb1.Append("(SELECT [case number] FROM [MWCAS] WHERE [guarantor] = ");
|
||
sb1.Append("(SELECT TOP 1 [guarantor] FROM [MWCAS] WHERE [chart number] = '" + MAKE_SURE_APOSTROPHY_IS_SQL_READY(Chart) + "')) ");
|
||
string sqlQuery1 = sb1.ToString();
|
||
|
||
// Copied from Medisoft Source Code (Sent to my by Scott Toney)
|
||
// Query2: run the query to get the missed copays
|
||
StringBuilder sb2 = new StringBuilder();
|
||
sb2.Append("SELECT SUM([Copayment_Expected_Amount] + ");
|
||
sb2.Append("[Copayment_Amount_Paid] ");
|
||
sb2.Append(") as CopayBalance ");
|
||
sb2.Append("from [MWTRN] ");
|
||
//sb2.Append("WHERE [Transaction type] <= " + QuotedStr('H') + " AND ");
|
||
sb2.Append("WHERE [Transaction type] <= 'H' AND ");
|
||
sb2.Append("( [Guarantor Responsible] = True ) ");
|
||
sb2.Append("AND ( (( [Insurance 1 Responsible] = True ) and ( [Insurance 1 Paid] <> [Insurance 1 Responsible] )) ");
|
||
sb2.Append("OR (( [Insurance 2 Responsible] = True ) and ( [Insurance 2 Paid] <> [Insurance 2 Responsible] )) ");
|
||
sb2.Append("OR (( [Insurance 3 Responsible] = True ) and ( [Insurance 3 Paid] <> [Insurance 3 Responsible] )) ");
|
||
sb2.Append(") ");
|
||
sb2.Append("AND ( [Guarantor Paid] = False ) and ");
|
||
sb2.Append("[case number] in ");
|
||
sb2.Append("(SELECT [case number] From [MWCAS] WHERE [guarantor] = ");
|
||
sb2.Append("(SELECT TOP 1 [guarantor] from [MWCAS] where [chart number] = '" + MAKE_SURE_APOSTROPHY_IS_SQL_READY(Chart) + "')) ");
|
||
string sqlQuery2 = sb2.ToString();
|
||
|
||
// Determine which query to run (Balance or CoPay Remainder)
|
||
string sql = "";
|
||
if (UseCopayRemainderCalculation(SystemApiKey))
|
||
sql = sqlQuery2;
|
||
else
|
||
sql = sqlQuery1;
|
||
|
||
// Run the Query
|
||
AdvantageCredential credential = DBCache.GetAdvantageConnection(SystemApiKey);
|
||
DB db = DB.Create(credential);
|
||
DBRetVal result = db.ExecuteScalar(sql);
|
||
if (result.IsValid)
|
||
{
|
||
decimal Balance = DataRet.Retrieve<decimal>(result.GetScalarRetVal(), 0);
|
||
return Balance;
|
||
}
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region Post Billing
|
||
|
||
/// <summary>
|
||
/// Post Billing to Unproccessed Transactions
|
||
/// </summary>
|
||
/// <param name="SystemApiKey"></param>
|
||
/// <param name="User"></param>
|
||
/// <param name="billingInfo"></param>
|
||
/// <returns></returns>
|
||
public static bool PostBilling(string SystemApiKey, string User, BillingPost1 billingInfo)
|
||
{
|
||
// Make sure this is a valid BillingPost we are getting passed in
|
||
if ((billingInfo == null) || (billingInfo.BillingDetails == null) ||
|
||
(billingInfo.BillingDetails.Length == 0))
|
||
return false;
|
||
|
||
// Generate new Unique ID
|
||
string UniqueID = Guid.NewGuid().ToString();
|
||
UniqueID = UniqueID.Replace("-", "").Substring(0, 32);
|
||
|
||
// Create encryption code.
|
||
string sSource = billingInfo.ChartID + billingInfo.PatientLastName + UniqueID;
|
||
string s64Trimmed = CrossProduct.Core.Utils.MD5EncryptMsg(sSource, 20);
|
||
bool bSuccessfulPost = true;
|
||
|
||
// Setup Main DB
|
||
AdvantageCredential credential = DBCache.GetAdvantageConnection(SystemApiKey);
|
||
DB db = DB.Create(credential);
|
||
|
||
// for auditing * may not work *
|
||
AdvantageCredential credentialUser = null;
|
||
DB dbUser = null;
|
||
|
||
// Try to Audit, following Scott's instructions, however, there seems to be no
|
||
// guarantee that this works (Advantage can get quickly out of sync it seems)
|
||
bool bTryToAudit = !String.IsNullOrEmpty(User);
|
||
bTryToAudit = false;
|
||
if (bTryToAudit)
|
||
{
|
||
credentialUser = DBCache.GetAdvantageConnection(SystemApiKey, User);
|
||
dbUser = DB.Create(credentialUser);
|
||
}
|
||
|
||
// Deal with Notes first * Load them all up into a Memo Field *
|
||
StringBuilder sbBillingNotes = new StringBuilder();
|
||
for (int i = 0; i < billingInfo.BillingDetails.Length; ++i)
|
||
{
|
||
BillingDetail1 detail = billingInfo.BillingDetails[i];
|
||
if (!String.IsNullOrEmpty(detail.BillingNote))
|
||
{
|
||
sbBillingNotes.Append(detail.BillingNote);
|
||
sbBillingNotes.Append("\n"); // Could be '\r' - test
|
||
}
|
||
}
|
||
if(sbBillingNotes.Length > 0)
|
||
sbBillingNotes.Remove(sbBillingNotes.Length - 1, 1); // remove trailing '\n'
|
||
|
||
// Deal with the rest of the items, notes are stuffed into the first item only
|
||
bool bFirstInsert = true;
|
||
int nNotesFound = 0;
|
||
for (int i = 0; i < billingInfo.BillingDetails.Length && bSuccessfulPost; ++i)
|
||
{
|
||
BillingDetail1 detail = billingInfo.BillingDetails[i];
|
||
|
||
// Skip Billing Notes (already dealt with)
|
||
if (!String.IsNullOrEmpty(detail.BillingNote))
|
||
{
|
||
nNotesFound++;
|
||
continue;
|
||
}
|
||
|
||
StringBuilder ValueList = new StringBuilder();
|
||
string newID = CrossProduct.Core.Utils.CreateGUID();
|
||
ValueList.Append("'" + MAKE_SURE_APOSTROPHY_IS_SQL_READY(newID) + "', "); // ID // ID
|
||
ValueList.Append("0, "); // Post, tinyint
|
||
ValueList.Append("0, "); // Transaction status, int
|
||
ValueList.Append("'" + MAKE_SURE_APOSTROPHY_IS_SQL_READY(billingInfo.ChartID) + "', "); // varchar15
|
||
ValueList.Append("0, "); // Billing, Case int
|
||
ValueList.Append("'" + MAKE_SURE_APOSTROPHY_IS_SQL_READY(billingInfo.ProviderID) + "', "); // varchar 15
|
||
|
||
// Make sure valid Date From
|
||
if (billingInfo.DateFrom != null && billingInfo.DateFrom != DateTime.MinValue)
|
||
ValueList.Append(" CONVERT('" + CrossProduct.Core.Utils.AdvDTStringDateOnly(billingInfo.DateFrom) + "', sql_timestamp), "); // datetime
|
||
else
|
||
ValueList.Append(" CONVERT('" + CrossProduct.Core.Utils.AdvDTStringDateOnly(DateTime.Now) + "', sql_timestamp), "); // datetime
|
||
|
||
ValueList.Append("'" + MAKE_SURE_APOSTROPHY_IS_SQL_READY(detail.ProcedureCode) + "', "); // varchar 15
|
||
ValueList.Append("'" + MAKE_SURE_APOSTROPHY_IS_SQL_READY(detail.ProcedureModifier1) + "', "); // varchar 3
|
||
ValueList.Append("'" + MAKE_SURE_APOSTROPHY_IS_SQL_READY(detail.ProcedureModifier2) + "', "); // varchar 3
|
||
ValueList.Append("'" + MAKE_SURE_APOSTROPHY_IS_SQL_READY(detail.ProcedureModifier3) + "', "); // varchar 3
|
||
ValueList.Append("'" + MAKE_SURE_APOSTROPHY_IS_SQL_READY(detail.ProcedureModifier4) + "', "); // varchar 3
|
||
ValueList.Append(detail.Units + ", "); // real
|
||
ValueList.Append((i + 1 - nNotesFound).ToString() + ", "); // Procedure Order, int
|
||
ValueList.Append("'" + MAKE_SURE_APOSTROPHY_IS_SQL_READY(billingInfo.PatientLastName) + "', "); // patient last name
|
||
ValueList.Append("'" + MAKE_SURE_APOSTROPHY_IS_SQL_READY(billingInfo.PatientFirstName) + "', "); // patient first name
|
||
|
||
// Don't insert an invalid birthday (Medisoft allows nulls)
|
||
if (billingInfo.BirthDate != null && billingInfo.BirthDate != DateTime.MinValue)
|
||
ValueList.Append(" CONVERT('" + CrossProduct.Core.Utils.AdvDTStringDateOnly(billingInfo.BirthDate) + "', sql_timestamp), "); // datetime
|
||
else
|
||
ValueList.Append(" NULL, "); // datetime
|
||
|
||
ValueList.Append("'" + MAKE_SURE_APOSTROPHY_IS_SQL_READY(billingInfo.PatientSocialSecurity) + "', ");// varchar 11
|
||
ValueList.Append("-1, "); // Exception // int
|
||
ValueList.Append("'" + MAKE_SURE_APOSTROPHY_IS_SQL_READY(billingInfo.Facility) + "', "); // Facility
|
||
ValueList.Append("0, "); // Created By Application. // int
|
||
ValueList.Append("0, "); // Amount
|
||
ValueList.Append("'" + UniqueID + "', "); // varchar 32
|
||
ValueList.Append("'', "); // Error msg. varchar 80
|
||
ValueList.Append(" CONVERT('" + CrossProduct.Core.Utils.AdvDTString(DateTime.Now) + "', sql_timestamp), "); // Created Date, datetime
|
||
ValueList.Append("NULL, "); // mod date, datetime
|
||
ValueList.Append("0,"); // Viewed, tinyint
|
||
ValueList.Append("'" + MAKE_SURE_APOSTROPHY_IS_SQL_READY(s64Trimmed) + "',"); // Encryption Code.
|
||
ValueList.Append("'" + MAKE_SURE_APOSTROPHY_IS_SQL_READY(detail.ImmunizationBatchNumber) + "', "); // Immunization Batch Number ?
|
||
|
||
// On First Insert, add the billing notes to first post
|
||
if (bFirstInsert)
|
||
{
|
||
if (sbBillingNotes.Length > 0)
|
||
ValueList.Append("'" + MAKE_SURE_APOSTROPHY_IS_SQL_READY(sbBillingNotes.ToString()) + "', "); // Mobile Notes. Memo.
|
||
else
|
||
ValueList.Append("'', "); // Mobile Notes. Memo.
|
||
bFirstInsert = false;
|
||
}
|
||
else
|
||
ValueList.Append("'', "); // Mobile Notes. Memo.
|
||
|
||
/// *******
|
||
/// Attach each Diagnosis Code (we can do up to 12) for each procedure
|
||
/// Always do this last, deals with trailing Comma (,)
|
||
/// *******
|
||
for (int j = 0; j < 12; ++j)
|
||
{
|
||
try
|
||
{
|
||
ValueList.Append("'");
|
||
ValueList.Append(MAKE_SURE_APOSTROPHY_IS_SQL_READY(detail.DiagnosisCodes[j])); // Diagnosis 1 - 12, varchar 15
|
||
if (j < 11)
|
||
ValueList.Append("', ");
|
||
else
|
||
ValueList.Append("'");
|
||
}
|
||
catch (IndexOutOfRangeException)
|
||
{
|
||
if (j < 11)
|
||
ValueList.Append("', ");
|
||
else
|
||
ValueList.Append("'");
|
||
}
|
||
catch(NullReferenceException)
|
||
{
|
||
if (j < 11)
|
||
ValueList.Append("', ");
|
||
else
|
||
ValueList.Append("'");
|
||
}
|
||
}
|
||
|
||
// Build our sql statement.
|
||
StringBuilder sb = new StringBuilder("INSERT INTO [MWUTC] ");
|
||
sb.Append(" ([ID], [Post], [Transaction_Status], [Chart_Number], [Case_Number], [Provider], [Date_From], [Procedure_Code], [Modifier_1], [Modifier_2], [Modifier_3], [Modifier_4], [Units], [Procedure_Order], [Patient_Last_Name], [Patient_First_Name], [Birth_Date], [SSN], [Exception], [Facility], [Creating_App], [Amount], [HL7MessageID], [ErrorMsg], [Date_Created], [Date_Modified], [Viewed], [Checksum], [Immunization Batch Number], [Mobile Notes], [Diagnosis_Code_1], [Diagnosis_Code_2], [Diagnosis_Code_3], [Diagnosis_Code_4], [Diagnosis_Code_5], [Diagnosis_Code_6], [Diagnosis_Code_7], [Diagnosis_Code_8], [Diagnosis_Code_9], [Diagnosis_Code_10], [Diagnosis_Code_11], [Diagnosis_Code_12])");
|
||
sb.Append(" VALUES (" + ValueList.ToString() + ")");
|
||
string StrSQL = sb.ToString();
|
||
|
||
DBRetVal result = null;
|
||
if (bTryToAudit)
|
||
{
|
||
// Post the Billing (via user way)
|
||
result = dbUser.ExecuteNonQuery(StrSQL);
|
||
bSuccessfulPost = result.IsValid;
|
||
if (bSuccessfulPost)
|
||
{
|
||
// posted succesful for user moving on
|
||
continue;
|
||
}
|
||
else
|
||
{
|
||
MSLSpecific.Logger.Info("submitting superbill via the user {0} didn't work, will submitt the superbill without the user credential (msg:{1})", User, result.ErrorMsg);
|
||
bTryToAudit = false;
|
||
}
|
||
}
|
||
|
||
// Post the Billing (the regular way)
|
||
result = db.ExecuteNonQuery(StrSQL);
|
||
bSuccessfulPost = result.IsValid;
|
||
}
|
||
|
||
return bSuccessfulPost;
|
||
}
|
||
|
||
#endregion
|
||
}
|
||
}
|