1028 lines
29 KiB
C#
1028 lines
29 KiB
C#
|
using System;
|
||
|
using System.Collections;
|
||
|
using System.Data;
|
||
|
using System.Data.OleDb;
|
||
|
using System.Diagnostics;
|
||
|
using System.Drawing;
|
||
|
using System.Windows.Forms;
|
||
|
using IndianHealthService.BMXNet;
|
||
|
|
||
|
namespace IndianHealthService.ClinicalScheduling
|
||
|
{
|
||
|
/// <summary>
|
||
|
/// Contains the array of appointments and availabily that make up the document class
|
||
|
/// </summary>
|
||
|
public class CGDocument : System.Object
|
||
|
{
|
||
|
|
||
|
public CGDocument()
|
||
|
{
|
||
|
m_appointments = new CGAppointments();
|
||
|
m_pAvArray = new ArrayList();
|
||
|
m_sResourcesArray = new ArrayList();
|
||
|
}
|
||
|
|
||
|
#region Member Variables
|
||
|
public int m_nColumnCount; //todo: this should point to the view's member for column count
|
||
|
public int m_nTimeUnits;
|
||
|
private string m_sDocName;
|
||
|
public ArrayList m_sResourcesArray;
|
||
|
public ScheduleType m_ScheduleType;
|
||
|
private DateTime m_dSelectedDate; //Holds the user's selection from the dtpicker
|
||
|
private DateTime m_dStartDate; //Beginning date of document data
|
||
|
private DateTime m_dEndDate; //Ending date of document data
|
||
|
public CGAppointments m_appointments;
|
||
|
private ArrayList m_pAvArray;
|
||
|
private CGDocumentManager m_DocManager;
|
||
|
private DateTime m_dLastRefresh = DateTime.Now;
|
||
|
|
||
|
#endregion
|
||
|
|
||
|
#region Properties
|
||
|
|
||
|
/// <summary>
|
||
|
/// Returns the latest refresh time for this document
|
||
|
/// </summary>
|
||
|
public DateTime LastRefreshed
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
return m_dLastRefresh;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// The list of Resource names
|
||
|
/// </summary>
|
||
|
public ArrayList Resources
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
return this.m_sResourcesArray;
|
||
|
}
|
||
|
set
|
||
|
{
|
||
|
this.m_sResourcesArray = value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// The array of CGAvailabilities that contains appt type and slots
|
||
|
/// </summary>
|
||
|
public ArrayList AvailabilityArray
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
return this.m_pAvArray;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public CGDocumentManager DocManager
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
return m_DocManager;
|
||
|
}
|
||
|
set
|
||
|
{
|
||
|
m_DocManager = value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Contains the hashtable of appointments
|
||
|
/// </summary>
|
||
|
public CGAppointments Appointments
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
return m_appointments;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Holds the date selected by the user in CGView.dateTimePicker1
|
||
|
/// </summary>
|
||
|
public DateTime SelectedDate
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
return this.m_dSelectedDate;
|
||
|
}
|
||
|
set
|
||
|
{
|
||
|
this.m_dSelectedDate = value;
|
||
|
bool bRet = false;
|
||
|
if (m_sResourcesArray.Count == 1)
|
||
|
{
|
||
|
bRet = this.WeekNeedsRefresh(1, m_dSelectedDate, out this.m_dStartDate, out this.m_dEndDate);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
this.m_dStartDate = m_dSelectedDate;
|
||
|
this.m_dEndDate = m_dSelectedDate;
|
||
|
this.m_dEndDate = this.m_dEndDate.AddHours(23);
|
||
|
this.m_dEndDate = this.m_dEndDate.AddMinutes(59);
|
||
|
this.m_dEndDate = this.m_dEndDate.AddSeconds(59);
|
||
|
}
|
||
|
|
||
|
bRet = RefreshSchedule();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Contains the beginning date of the appointment document
|
||
|
/// </summary>
|
||
|
public DateTime StartDate
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
return this.m_dStartDate;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public string DocName
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
return this.m_sDocName;
|
||
|
}
|
||
|
set
|
||
|
{
|
||
|
this.m_sDocName = value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#endregion
|
||
|
|
||
|
#region Methods
|
||
|
|
||
|
public void UpdateAllViews()
|
||
|
{
|
||
|
//iterate through all views and call update.
|
||
|
Hashtable h = CGDocumentManager.Current.Views;
|
||
|
|
||
|
CGDocument d;
|
||
|
foreach (CGView v in h.Keys)
|
||
|
{
|
||
|
d = (CGDocument) h[v];
|
||
|
if (d == this)
|
||
|
{
|
||
|
v.UpdateArrays();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Update schedule based on info in RPMS
|
||
|
/// </summary>
|
||
|
private bool RefreshDaysSchedule()
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
string sPatientName;
|
||
|
string sPatientID;
|
||
|
DateTime dStart;
|
||
|
DateTime dEnd;
|
||
|
DateTime dCheckIn;
|
||
|
DateTime dAuxTime;
|
||
|
int nKeyID;
|
||
|
string sNote;
|
||
|
string sResource;
|
||
|
bool bNoShow = false;
|
||
|
string sNoShow = "0";
|
||
|
string sHRN = "";
|
||
|
int nAccessTypeID; //used in autorebook
|
||
|
string sWalkIn = "0";
|
||
|
bool bWalkIn;
|
||
|
CGAppointment pAppointment;
|
||
|
CGDocumentManager pApp = CGDocumentManager.Current;
|
||
|
DataTable rAppointmentSchedule;
|
||
|
|
||
|
m_dLastRefresh = DateTime.Now;
|
||
|
|
||
|
this.m_appointments.ClearAllAppointments();
|
||
|
|
||
|
rAppointmentSchedule = CGSchedLib.CreateAppointmentSchedule(m_DocManager, m_sResourcesArray, this.m_dStartDate, this.m_dEndDate);
|
||
|
CGSchedLib.OutputArray(rAppointmentSchedule, "rAppointmentSchedule");
|
||
|
foreach (DataRow r in rAppointmentSchedule.Rows)
|
||
|
{
|
||
|
|
||
|
if (r["APPOINTMENTID"].ToString() == "0")
|
||
|
{
|
||
|
string sMsg = r["NOTE"].ToString();
|
||
|
throw new BMXNetException(sMsg);
|
||
|
}
|
||
|
nKeyID = Convert.ToInt32(r["APPOINTMENTID"].ToString());
|
||
|
sResource = r["RESOURCENAME"].ToString();
|
||
|
sPatientName =r["PATIENTNAME"].ToString();
|
||
|
sPatientID =r["PATIENTID"].ToString();
|
||
|
dStart = (DateTime) r["START_TIME"];
|
||
|
dEnd = (DateTime) r["END_TIME"];
|
||
|
dCheckIn = new DateTime();
|
||
|
dAuxTime = new DateTime();
|
||
|
|
||
|
if (r["CHECKIN"].GetType() != typeof(System.DBNull))
|
||
|
dCheckIn = (DateTime) r["CHECKIN"];
|
||
|
if (r["AUXTIME"].GetType() != typeof(System.DBNull))
|
||
|
dCheckIn = (DateTime) r["AUXTIME"];
|
||
|
sNote = r["NOTE"].ToString();
|
||
|
sNoShow = r["NOSHOW"].ToString();
|
||
|
bNoShow = (sNoShow == "1")?true: false;
|
||
|
sHRN = r["HRN"].ToString();
|
||
|
nAccessTypeID = (int) r["ACCESSTYPEID"];
|
||
|
sWalkIn = r["WALKIN"].ToString();
|
||
|
bWalkIn = (sWalkIn == "1")?true: false;
|
||
|
|
||
|
pAppointment = new CGAppointment();
|
||
|
pAppointment.CreateAppointment(dStart, dEnd, sNote, nKeyID, sResource);
|
||
|
pAppointment.PatientName = sPatientName;
|
||
|
pAppointment.PatientID = Convert.ToInt32(sPatientID);
|
||
|
if (dCheckIn.Ticks > 0)
|
||
|
pAppointment.CheckInTime = dCheckIn;
|
||
|
if (dAuxTime.Ticks > 0)
|
||
|
pAppointment.AuxTime = dAuxTime;
|
||
|
pAppointment.NoShow = bNoShow;
|
||
|
pAppointment.HealthRecordNumber = sHRN;
|
||
|
pAppointment.AccessTypeID = nAccessTypeID;
|
||
|
pAppointment.WalkIn = bWalkIn;
|
||
|
this.m_appointments.AddAppointment(pAppointment);
|
||
|
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
catch(Exception Ex)
|
||
|
{
|
||
|
Debug.Write("CGDocument.RefreshDaysSchedule error: " + Ex.Message + "\n");
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
public void OnNewDocument()
|
||
|
{
|
||
|
/*
|
||
|
* TEST EXCEPTION -- REMOVE AFTER TESTING
|
||
|
*/
|
||
|
//throw new Exception("Simulated Uncaught Exception");
|
||
|
/*
|
||
|
* TEST EXCEPTION -- REMOVE AFTER TESTING
|
||
|
*/
|
||
|
|
||
|
//Open an empty document
|
||
|
m_sResourcesArray.Clear();
|
||
|
m_ScheduleType = ScheduleType.Resource;
|
||
|
|
||
|
//Set initial From and To dates based on current day
|
||
|
// DateTime dDate = new DateTime(2001,12,05); //Testing line
|
||
|
DateTime dDate = DateTime.Today;
|
||
|
bool bRet = this.WeekNeedsRefresh(2,dDate, out this.m_dStartDate, out this.m_dEndDate);
|
||
|
|
||
|
//Create new View
|
||
|
CGView view = new CGView();
|
||
|
view.InitializeDocView(this,
|
||
|
this.DocManager,
|
||
|
m_dStartDate,
|
||
|
this.Appointments,
|
||
|
DocManager.WindowText);
|
||
|
|
||
|
view.Show();
|
||
|
view.SyncTree();
|
||
|
view.Activate();
|
||
|
this.UpdateAllViews();
|
||
|
}
|
||
|
|
||
|
private void SetDate(DateTime dDate)
|
||
|
{
|
||
|
bool bRet = false;
|
||
|
if (m_ScheduleType == ScheduleType.Resource)
|
||
|
{
|
||
|
bRet = this.WeekNeedsRefresh(2,dDate, out this.m_dStartDate, out this.m_dEndDate);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
this.m_dStartDate = dDate;
|
||
|
this.m_dEndDate = dDate;
|
||
|
this.m_dEndDate = this.m_dEndDate.AddHours(23);
|
||
|
this.m_dEndDate = this.m_dEndDate.AddMinutes(59);
|
||
|
this.m_dEndDate = this.m_dEndDate.AddSeconds(59);
|
||
|
}
|
||
|
|
||
|
bRet = RefreshSchedule();
|
||
|
this.UpdateAllViews();
|
||
|
}
|
||
|
|
||
|
public void RefreshDocument()
|
||
|
{
|
||
|
bool bRet = RefreshSchedule();
|
||
|
this.UpdateAllViews();
|
||
|
}
|
||
|
|
||
|
public void OnOpenDocument()
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
//Create new Document
|
||
|
m_ScheduleType = (m_sResourcesArray.Count == 1) ? ScheduleType.Resource: ScheduleType.Clinic;
|
||
|
bool bRet = false;
|
||
|
|
||
|
//Set initial From and To dates based on current day
|
||
|
DateTime dDate = DateTime.Today;
|
||
|
if (m_ScheduleType == ScheduleType.Resource)
|
||
|
{
|
||
|
bRet = this.WeekNeedsRefresh(1,dDate, out this.m_dStartDate, out this.m_dEndDate);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
this.m_dStartDate = dDate;
|
||
|
this.m_dEndDate = dDate;
|
||
|
this.m_dEndDate = this.m_dEndDate.AddHours(23);
|
||
|
this.m_dEndDate = this.m_dEndDate.AddMinutes(59);
|
||
|
this.m_dEndDate = this.m_dEndDate.AddSeconds(59);
|
||
|
}
|
||
|
|
||
|
bRet = RefreshSchedule();
|
||
|
|
||
|
CGView view = null;
|
||
|
//If this document already has a view, the use it
|
||
|
Hashtable h = CGDocumentManager.Current.Views;
|
||
|
CGDocument d;
|
||
|
bool bReuseView = false;
|
||
|
foreach (CGView v in h.Keys)
|
||
|
{
|
||
|
d = (CGDocument) h[v];
|
||
|
if (d == this)
|
||
|
{
|
||
|
view = v;
|
||
|
bReuseView = true;
|
||
|
v.InitializeDocView(this.DocName);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//Otherwise, create new View
|
||
|
if (bReuseView == false)
|
||
|
{
|
||
|
view = new CGView();
|
||
|
|
||
|
view.InitializeDocView(this,
|
||
|
this.DocManager,
|
||
|
m_dStartDate,
|
||
|
this.Appointments,
|
||
|
this.DocName);
|
||
|
|
||
|
view.Show();
|
||
|
view.SyncTree();
|
||
|
|
||
|
}
|
||
|
this.UpdateAllViews();
|
||
|
}
|
||
|
catch (BMXNetException bmxEx)
|
||
|
{
|
||
|
throw bmxEx;
|
||
|
}
|
||
|
catch (Exception ex)
|
||
|
{
|
||
|
throw new BMXNet.BMXNetException("ClinicalScheduling.OnOpenDocument error: " + ex.Message);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private bool RefreshSchedule()
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
bool bRet = this.RefreshAvailabilitySchedule();
|
||
|
if (bRet == false)
|
||
|
{
|
||
|
return bRet;
|
||
|
}
|
||
|
bRet = this.RefreshDaysSchedule();
|
||
|
return bRet;
|
||
|
}
|
||
|
catch (ApplicationException aex)
|
||
|
{
|
||
|
Debug.Write("CGDocument.RefreshSchedule Application Error: " + aex.Message + "\n");
|
||
|
return false;
|
||
|
}
|
||
|
catch (Exception ex)
|
||
|
{
|
||
|
MessageBox.Show("CGDocument.RefreshSchedule error: " + ex.Message + "\n");
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private bool RefreshAvailabilitySchedule()
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
if (this.m_DocManager.ConnectInfo.Connected == false)
|
||
|
{
|
||
|
m_DocManager.ConnectInfo.LoadConnectInfo();
|
||
|
}
|
||
|
System.IntPtr pHandle = m_DocManager.Handle;
|
||
|
|
||
|
m_pAvArray.Clear();
|
||
|
|
||
|
ArrayList saryApptTypes = new ArrayList();
|
||
|
int nApptTypeID = 0;
|
||
|
|
||
|
//Refresh Availability schedules
|
||
|
DataTable rAvailabilitySchedule;
|
||
|
rAvailabilitySchedule = CGSchedLib.CreateAvailabilitySchedule(m_DocManager, m_sResourcesArray, this.m_dStartDate, this.m_dEndDate, saryApptTypes,/**/ m_ScheduleType, "0");
|
||
|
CGSchedLib.OutputArray(rAvailabilitySchedule, "rAvailabilitySchedule");
|
||
|
|
||
|
//Refresh Type Schedule
|
||
|
string sResourceName = "";
|
||
|
DataTable rTypeSchedule = new DataTable();;
|
||
|
for (int j = 0; j < m_sResourcesArray.Count; j++)
|
||
|
{
|
||
|
sResourceName = m_sResourcesArray[j].ToString();
|
||
|
DataTable dtTemp = CGSchedLib.CreateAssignedTypeSchedule(m_DocManager, sResourceName, this.m_dStartDate, this.m_dEndDate, m_ScheduleType);
|
||
|
CGSchedLib.OutputArray(dtTemp, "dtTemp");
|
||
|
if (j == 0)
|
||
|
{
|
||
|
rTypeSchedule = dtTemp;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
rTypeSchedule = CGSchedLib.UnionBlocks(rTypeSchedule, dtTemp);
|
||
|
}
|
||
|
}
|
||
|
CGSchedLib.OutputArray(rTypeSchedule, "rTypeSchedule");
|
||
|
|
||
|
DateTime dStart;
|
||
|
DateTime dEnd;
|
||
|
DateTime dTypeStart;
|
||
|
DateTime dTypeEnd;
|
||
|
int nSlots;
|
||
|
Rectangle crRectA = new Rectangle(0,0,1,0);
|
||
|
Rectangle crRectB= new Rectangle(0,0,1,0);
|
||
|
bool bIsect;
|
||
|
string sResourceList;
|
||
|
string sAccessRuleList;
|
||
|
|
||
|
|
||
|
foreach (DataRow rTemp in rAvailabilitySchedule.Rows)
|
||
|
{
|
||
|
//get StartTime, EndTime and Slots
|
||
|
dStart = (DateTime) rTemp["START_TIME"];
|
||
|
dEnd = (DateTime) rTemp["END_TIME"];
|
||
|
|
||
|
//TODO: Fix this slots datatype problem
|
||
|
string sSlots = rTemp["SLOTS"].ToString();
|
||
|
nSlots = Convert.ToInt16(sSlots);
|
||
|
|
||
|
sResourceList = rTemp["RESOURCE"].ToString();
|
||
|
sAccessRuleList = rTemp["ACCESS_TYPE"].ToString();
|
||
|
|
||
|
string sNote = rTemp["NOTE"].ToString();
|
||
|
|
||
|
if ((nSlots < -1000)||(sAccessRuleList == ""))
|
||
|
{
|
||
|
nApptTypeID = 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
foreach (DataRow rType in rTypeSchedule.Rows)
|
||
|
{
|
||
|
|
||
|
dTypeStart = (DateTime) rType["StartTime"];
|
||
|
dTypeEnd = (DateTime) rType["EndTime"];
|
||
|
//if start & end times overlap, then
|
||
|
string sTypeResource = rType["ResourceName"].ToString();
|
||
|
if ((dTypeStart.DayOfYear == dStart.DayOfYear) && (sResourceList == sTypeResource))
|
||
|
{
|
||
|
crRectA.Y = GetTotalMinutes(dStart);
|
||
|
crRectA.Height = GetTotalMinutes(dEnd) - crRectA.Top;
|
||
|
crRectB.Y = GetTotalMinutes(dTypeStart);
|
||
|
crRectB.Height = GetTotalMinutes(dTypeEnd) - crRectB.Top;
|
||
|
bIsect = crRectA.IntersectsWith(crRectB);
|
||
|
if (bIsect == true)
|
||
|
{
|
||
|
//TODO: This code:
|
||
|
// nApptTypeID = (int) rType["AppointmentTypeID"];
|
||
|
//Causes this exception:
|
||
|
//Unhandled Exception: System.InvalidCastException: Specified cast is not valid.
|
||
|
string sTemp = rType["AppointmentTypeID"].ToString();
|
||
|
nApptTypeID = Convert.ToInt16(sTemp);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}//end foreach datarow rType
|
||
|
}
|
||
|
|
||
|
AddAvailability(dStart, dEnd, nApptTypeID, nSlots, false, sResourceList, sAccessRuleList, sNote);
|
||
|
}//end foreach datarow rTemp
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
catch (Exception ex)
|
||
|
{
|
||
|
Debug.Write("CGDocument.RefreshAvailabilitySchedule error: " + ex.Message + "\n");
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private int GetTotalMinutes(DateTime dDate)
|
||
|
{
|
||
|
return ((dDate.Hour * 60) + dDate.Minute);
|
||
|
}
|
||
|
|
||
|
public int AddAvailability(DateTime StartTime, DateTime EndTime, int nType, int nSlots, bool UpdateView, string sResourceList, string sAccessRuleList, string sNote)
|
||
|
{
|
||
|
//adds it to the object array
|
||
|
//Returns the index in the array
|
||
|
|
||
|
CGAvailability pNewAv = new CGAvailability();
|
||
|
pNewAv.Create(StartTime, EndTime, nType, nSlots, sResourceList, sAccessRuleList);
|
||
|
|
||
|
pNewAv.Note = sNote;
|
||
|
|
||
|
//Look up the color and type name using the AppointmentTypes datatable
|
||
|
DataTable dtType = this.m_DocManager.GlobalDataSet.Tables["AccessTypes"];
|
||
|
DataRow dRow = dtType.Rows.Find(nType.ToString());
|
||
|
if (dRow != null)
|
||
|
{
|
||
|
string sColor = dRow["DISPLAY_COLOR"].ToString();
|
||
|
pNewAv.DisplayColor = sColor;
|
||
|
string sTemp = dRow["RED"].ToString();
|
||
|
sTemp = (sTemp == "")?"0":sTemp;
|
||
|
int nRed = Convert.ToInt16(sTemp);
|
||
|
pNewAv.Red = nRed;
|
||
|
sTemp = dRow["GREEN"].ToString();
|
||
|
sTemp = (sTemp == "")?"0":sTemp;
|
||
|
int nGreen = Convert.ToInt16(sTemp);
|
||
|
pNewAv.Green = nGreen;
|
||
|
sTemp = dRow["BLUE"].ToString();
|
||
|
sTemp = (sTemp == "")?"0":sTemp;
|
||
|
int nBlue = Convert.ToInt16(sTemp);
|
||
|
pNewAv.Blue = nBlue;
|
||
|
|
||
|
string sName = dRow["ACCESS_TYPE_NAME"].ToString();
|
||
|
pNewAv.AccessTypeName = sName;
|
||
|
}
|
||
|
|
||
|
int nIndex = 0;
|
||
|
nIndex = m_pAvArray.Add(pNewAv);
|
||
|
if (UpdateView == true)
|
||
|
{
|
||
|
this.UpdateAllViews();
|
||
|
}
|
||
|
return nIndex;
|
||
|
}
|
||
|
|
||
|
|
||
|
public void AddResource(string sResource)
|
||
|
{
|
||
|
//TODO: Test that resource is not currently in list, that it IS a resource, etc
|
||
|
this.m_sResourcesArray.Add(sResource);
|
||
|
this.UpdateAllViews();
|
||
|
}
|
||
|
|
||
|
public void ClearResources()
|
||
|
{
|
||
|
this.m_sResourcesArray.Clear();
|
||
|
}
|
||
|
|
||
|
public int SlotsAvailable(DateTime dSelStart, DateTime dSelEnd, string sResource, out string sAccessType, out string sAvailabilityMessage)
|
||
|
{
|
||
|
sAccessType = "";
|
||
|
sAvailabilityMessage = "";
|
||
|
DateTime dStart;
|
||
|
DateTime dEnd;
|
||
|
int nAvailableSlots = 999;
|
||
|
int nSlots = 0;
|
||
|
int i = 0;
|
||
|
CGAvailability pAv;
|
||
|
Rectangle crRectA = new Rectangle(0,0,1,0);
|
||
|
Rectangle crRectB = new Rectangle(0,0,1,0);
|
||
|
bool bIsect;
|
||
|
crRectB.Y = GetTotalMinutes(dSelStart);
|
||
|
crRectB.Height = GetTotalMinutes(dSelEnd)- crRectB.Y;
|
||
|
|
||
|
// //loop thru m_pAvArray
|
||
|
// //Compare the start time and end time of eachblock
|
||
|
while (i < m_pAvArray.Count)
|
||
|
{
|
||
|
pAv = (CGAvailability) m_pAvArray[i];
|
||
|
dStart = pAv.StartTime;
|
||
|
dEnd = pAv.EndTime;
|
||
|
if ((sResource == pAv.ResourceList) &&
|
||
|
((dSelStart.Date == dStart.Date) || (dSelStart.Date == dEnd.Date)))
|
||
|
{
|
||
|
crRectA.Y = (dStart.Date < dSelStart.Date) ? 0 : GetTotalMinutes(dStart);
|
||
|
crRectA.Height = (dEnd.Date > dSelEnd.Date) ? 1440 : GetTotalMinutes(dEnd);
|
||
|
crRectA.Height = crRectA.Height - crRectA.Y;
|
||
|
bIsect = crRectA.IntersectsWith(crRectB);
|
||
|
if (bIsect != false)
|
||
|
{
|
||
|
nSlots = pAv.Slots;
|
||
|
if (nSlots < 1)
|
||
|
{
|
||
|
nAvailableSlots = 0;
|
||
|
break;
|
||
|
}
|
||
|
if (nSlots < nAvailableSlots)
|
||
|
{
|
||
|
nAvailableSlots = nSlots;
|
||
|
sAccessType = pAv.AccessTypeName;
|
||
|
sAvailabilityMessage = pAv.Note;
|
||
|
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
i++;
|
||
|
}
|
||
|
if (nAvailableSlots == 999)
|
||
|
{
|
||
|
nAvailableSlots = 0;
|
||
|
}
|
||
|
return nAvailableSlots;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Given a selected date,
|
||
|
/// Calculates StartDay and End Day and returns them in output params.
|
||
|
/// nWeeks == number of Weeks to display
|
||
|
/// nColumnCount is number of days displayed per week. If 5 columns, begin on
|
||
|
/// Monday, if 7 Columns, begin on Sunday
|
||
|
///
|
||
|
/// Returns TRUE if the document's data needs refreshing based on
|
||
|
/// this newly selected date.
|
||
|
/// </summary>
|
||
|
public bool WeekNeedsRefresh(int nWeeks, DateTime SelectedDate,
|
||
|
out DateTime WeekStartDay, out DateTime WeekEndDay)
|
||
|
{
|
||
|
DateTime OldStartDay = m_dStartDate;
|
||
|
DateTime OldEndDay = m_dEndDate;
|
||
|
int nWeekDay = (int) SelectedDate.DayOfWeek; //0 == Sunday
|
||
|
|
||
|
int nOff = 1;
|
||
|
TimeSpan ts = new TimeSpan(nWeekDay - nOff,0,0,0); //d,h,m,s
|
||
|
|
||
|
if (m_nColumnCount == 1)
|
||
|
{
|
||
|
ts = new TimeSpan(0,23,59,59);
|
||
|
WeekStartDay = SelectedDate;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
WeekStartDay = SelectedDate - ts;
|
||
|
if (m_nColumnCount == 7)
|
||
|
{
|
||
|
ts = new TimeSpan(1,0,0,0);
|
||
|
WeekStartDay -= ts;
|
||
|
}
|
||
|
int nEnd = (m_nColumnCount == 7) ? 1 : 3;
|
||
|
ts = new TimeSpan((7* nWeeks) - nEnd, 23, 59,59);
|
||
|
}
|
||
|
WeekEndDay = WeekStartDay + ts;
|
||
|
bool bRet = (( WeekStartDay.Date != OldStartDay.Date) || (WeekEndDay.Date != OldEndDay.Date));
|
||
|
return bRet;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Calls RPMS to create appointment then
|
||
|
/// adds appointment to the m_appointments collection
|
||
|
/// Returns the IEN of the appointment in the RPMS BSDX APPOINTMENT file.
|
||
|
/// </summary>
|
||
|
/// <param name="rApptInfo"></param>
|
||
|
/// <returns></returns>
|
||
|
public int CreateAppointment(CGAppointment rApptInfo)
|
||
|
{
|
||
|
return CreateAppointment(rApptInfo, false);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Use this overload to create a walkin appointment
|
||
|
/// </summary>
|
||
|
/// <param name="rApptInfo"></param>
|
||
|
/// <param name="bWalkin"></param>
|
||
|
/// <returns></returns>
|
||
|
public int CreateAppointment(CGAppointment rApptInfo, bool bWalkin)
|
||
|
{
|
||
|
string sStart;
|
||
|
string sEnd;
|
||
|
string sPatID;
|
||
|
string sResource;
|
||
|
string sNote;
|
||
|
string sLen;
|
||
|
string sApptID;
|
||
|
|
||
|
sStart = rApptInfo.StartTime.ToString("M-d-yyyy@HH:mm");
|
||
|
sEnd = rApptInfo.EndTime.ToString("M-d-yyyy@HH:mm");
|
||
|
TimeSpan sp = rApptInfo.EndTime - rApptInfo.StartTime;
|
||
|
sLen = sp.TotalMinutes.ToString();
|
||
|
sPatID = rApptInfo.PatientID.ToString();
|
||
|
sNote = rApptInfo.Note;
|
||
|
sResource = rApptInfo.Resource;
|
||
|
if (bWalkin == true)
|
||
|
{
|
||
|
sApptID = "WALKIN";
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
sApptID = rApptInfo.AccessTypeID.ToString();
|
||
|
}
|
||
|
|
||
|
CGAppointment aCopy = new CGAppointment();
|
||
|
aCopy.CreateAppointment(rApptInfo.StartTime, rApptInfo.EndTime, sNote, 0, sResource);
|
||
|
aCopy.PatientID = rApptInfo.PatientID;
|
||
|
aCopy.PatientName = rApptInfo.PatientName;
|
||
|
aCopy.HealthRecordNumber = rApptInfo.HealthRecordNumber;
|
||
|
aCopy.AccessTypeID = rApptInfo.AccessTypeID;
|
||
|
|
||
|
string sSql = "BSDX ADD NEW APPOINTMENT^" + sStart + "^" + sEnd + "^" + sPatID + "^" + sResource + "^" + sLen + "^" + sNote + "^" + sApptID ;
|
||
|
System.Data.DataTable dtAppt = m_DocManager.RPMSDataTable(sSql, "NewAppointment");
|
||
|
int nApptID;
|
||
|
|
||
|
Debug.Assert(dtAppt.Rows.Count == 1);
|
||
|
DataRow r = dtAppt.Rows[0];
|
||
|
nApptID =Convert.ToInt32(r["APPOINTMENTID"]);
|
||
|
string sErrorID;
|
||
|
sErrorID = r["ERRORID"].ToString();
|
||
|
if ((sErrorID != "")||(nApptID < 1))
|
||
|
throw new Exception(sErrorID);
|
||
|
aCopy.AppointmentKey = nApptID;
|
||
|
this.m_appointments.AddAppointment(aCopy);
|
||
|
|
||
|
bool bRet = RefreshAvailabilitySchedule();
|
||
|
|
||
|
UpdateAllViews();
|
||
|
|
||
|
return nApptID;
|
||
|
}
|
||
|
|
||
|
public void EditAppointment(CGAppointment pAppt, string sNote)
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
int nApptID = pAppt.AppointmentKey;
|
||
|
string sSql = "BSDX EDIT APPOINTMENT^" + nApptID.ToString() + "^" + sNote;
|
||
|
|
||
|
System.Data.DataTable dtAppt = m_DocManager.RPMSDataTable(sSql, "EditAppointment");
|
||
|
|
||
|
Debug.Assert(dtAppt.Rows.Count == 1);
|
||
|
DataRow r = dtAppt.Rows[0];
|
||
|
string sErrorID = r["ERRORID"].ToString();
|
||
|
if (sErrorID == "-1")
|
||
|
pAppt.Note = sNote;
|
||
|
|
||
|
if (this.m_appointments.AppointmentTable.ContainsKey(nApptID))
|
||
|
{
|
||
|
bool bRet = RefreshAvailabilitySchedule();
|
||
|
UpdateAllViews();
|
||
|
}
|
||
|
}
|
||
|
catch (Exception ex)
|
||
|
{
|
||
|
Debug.Write("CGDocument.EditAppointment Failed: " + ex.Message);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void CheckInAppointment(int nApptID, DateTime dCheckIn,
|
||
|
string ClinicStopIEN,
|
||
|
string ProviderIEN,
|
||
|
string PrintRouteSlip,
|
||
|
string PCCClinicIEN,
|
||
|
string PCCFormIEN,
|
||
|
string PCCOutGuide
|
||
|
)
|
||
|
{
|
||
|
string sCheckIn = dCheckIn.ToString("M-d-yyyy@HH:mm");
|
||
|
|
||
|
string sSql = "BSDX CHECKIN APPOINTMENT^" + nApptID.ToString() + "^" + sCheckIn + "^";
|
||
|
sSql += ClinicStopIEN + "^" + ProviderIEN + "^" + PrintRouteSlip + "^";
|
||
|
sSql += PCCClinicIEN + "^" + PCCFormIEN + "^" + PCCOutGuide;
|
||
|
|
||
|
System.Data.DataTable dtAppt = m_DocManager.RPMSDataTable(sSql, "CheckInAppointment");
|
||
|
|
||
|
Debug.Assert(dtAppt.Rows.Count == 1);
|
||
|
DataRow r = dtAppt.Rows[0];
|
||
|
string sErrorID = r["ERRORID"].ToString();
|
||
|
|
||
|
if (this.m_appointments.AppointmentTable.ContainsKey(nApptID))
|
||
|
{
|
||
|
bool bRet = RefreshSchedule();
|
||
|
UpdateAllViews();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public string DeleteAppointment(int nApptID)
|
||
|
{
|
||
|
return DeleteAppointment(nApptID, true, 0, "");
|
||
|
}
|
||
|
|
||
|
public string DeleteAppointment(int nApptID, bool bClinicCancelled, int nReason, string sRemarks)
|
||
|
{
|
||
|
//Returns "" if deletion successful
|
||
|
//Otherwise, returns reason for failure
|
||
|
|
||
|
string sClinicCancelled = (bClinicCancelled == true)?"C":"PC";
|
||
|
string sReasonID = nReason.ToString();
|
||
|
string sSql = "BSDX CANCEL APPOINTMENT^" + nApptID.ToString();
|
||
|
sSql += "^" + sClinicCancelled;
|
||
|
sSql += "^" + sReasonID;
|
||
|
sSql += "^" + sRemarks;
|
||
|
DataTable dtAppt = m_DocManager.RPMSDataTable(sSql, "DeleteAppointment");
|
||
|
|
||
|
Debug.Assert(dtAppt.Rows.Count == 1);
|
||
|
DataRow r = dtAppt.Rows[0];
|
||
|
string sErrorID = r["ERRORID"].ToString();
|
||
|
if (sErrorID != "")
|
||
|
return sErrorID;
|
||
|
|
||
|
if (this.m_appointments.AppointmentTable.ContainsKey(nApptID))
|
||
|
{
|
||
|
this.m_appointments.RemoveAppointment(nApptID);
|
||
|
bool bRet = RefreshAvailabilitySchedule();
|
||
|
UpdateAllViews();
|
||
|
}
|
||
|
return "";
|
||
|
}
|
||
|
|
||
|
public string AutoRebook(CGAppointment a, int nSearchType, int nMinimumDays, int nMaximumDays, out CGAppointment aRebook)
|
||
|
{
|
||
|
//If successful Returns "1" and new start date and time returned in aRebook
|
||
|
//Otherwise, returns error message
|
||
|
|
||
|
CGAppointment aCopy = new CGAppointment();
|
||
|
aCopy.CreateAppointment(a.StartTime, a.EndTime, a.Note, 0, a.Resource);
|
||
|
aCopy.PatientID = a.PatientID;
|
||
|
aCopy.PatientName = a.PatientName;
|
||
|
aCopy.HealthRecordNumber = a.HealthRecordNumber;
|
||
|
aCopy.AccessTypeID = a.AccessTypeID;
|
||
|
aRebook = aCopy;
|
||
|
|
||
|
//Determine Rebook access type
|
||
|
//nSearchType = -1: use current, -2: use any non-zero type, >0 use this access type id
|
||
|
int nAVType = 0;
|
||
|
|
||
|
switch (nSearchType)
|
||
|
{
|
||
|
case -1:
|
||
|
nAVType = a.AccessTypeID;
|
||
|
break;
|
||
|
case -2:
|
||
|
nAVType = 0;
|
||
|
break;
|
||
|
default:
|
||
|
nAVType = nSearchType;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
int nSlots = 0;
|
||
|
string sSlots = "";
|
||
|
int nAccessTypeID; //To compare with nAVType
|
||
|
|
||
|
DateTime dResult = new DateTime(); //StartTime of access block to autorebook into
|
||
|
|
||
|
//Next two are empty, but needed to pass to CreateAvailabilitySchedule
|
||
|
ArrayList alAccessTypes = new ArrayList();
|
||
|
string sSearchInfo = "";
|
||
|
|
||
|
//Find the StartTime of first availability block of this type for this clinic
|
||
|
//between nMinimumDays and nMaximumDays
|
||
|
|
||
|
string sAVStart = a.StartTime.AddDays(nMinimumDays).ToString("M/d/yyyy@H:mm");
|
||
|
|
||
|
//dtAVEnd is the last day to search
|
||
|
DateTime dtAVEnd = a.StartTime.AddDays(nMinimumDays + nMaximumDays);
|
||
|
string sAVEnd = dtAVEnd.ToString("M/d/yyyy@H:mm");
|
||
|
|
||
|
//Increment start day to search a week (or so) at a time
|
||
|
//30 is a test increment. Need to test different values for performance
|
||
|
int nIncrement = (nMaximumDays < 30)?nMaximumDays:30;
|
||
|
|
||
|
//nCount and nCountEnd are the 'moving' counters
|
||
|
//that I add to start and end to get the bracket
|
||
|
//At the beginning of the DO loop, nCount and nCountEnd are already set
|
||
|
bool bFinished = false;
|
||
|
bool bFound = false;
|
||
|
|
||
|
DateTime dStart = a.StartTime.AddDays(nMinimumDays);
|
||
|
DateTime dEnd = dStart.AddDays(nIncrement);
|
||
|
do
|
||
|
{
|
||
|
string sSql = "BSDX REBOOK NEXT BLOCK^" + dStart.ToString("M/d/yyyy@H:mm")+ "^" + a.Resource + "^" + nAVType.ToString();
|
||
|
DataTable dtNextBlock = this.DocManager.RPMSDataTable(sSql, "NextBlock");
|
||
|
Debug.Assert(dtNextBlock.Rows.Count == 1);
|
||
|
DataRow drNextBlockRow = dtNextBlock.Rows[0];
|
||
|
|
||
|
object oNextBlock;
|
||
|
oNextBlock = drNextBlockRow["NEXTBLOCK"];
|
||
|
if (oNextBlock.GetType() == typeof(System.DBNull))
|
||
|
break;
|
||
|
DateTime dNextBlock = (DateTime) drNextBlockRow["NEXTBLOCK"];
|
||
|
if (dNextBlock > dtAVEnd)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
dStart = dNextBlock;
|
||
|
dEnd = dStart.AddDays(nIncrement);
|
||
|
if (dEnd > dtAVEnd)
|
||
|
dEnd = dtAVEnd;
|
||
|
|
||
|
DataTable dtResult = CGSchedLib.CreateAvailabilitySchedule(m_DocManager, this.Resources, dStart, dEnd, alAccessTypes, ScheduleType.Resource, sSearchInfo);
|
||
|
//Loop thru dtResult looking for a slot having the required availability type.
|
||
|
//If found, set bFinished = true;
|
||
|
foreach (DataRow dr in dtResult.Rows)
|
||
|
{
|
||
|
|
||
|
sSlots = dr["SLOTS"].ToString();
|
||
|
if (sSlots == "")
|
||
|
sSlots = "0";
|
||
|
nSlots = Convert.ToInt16(sSlots);
|
||
|
if (nSlots > 0)
|
||
|
{
|
||
|
nAccessTypeID = 0; //holds the access type id of the availability block
|
||
|
if (dr["ACCESS_TYPE"].ToString() != "")
|
||
|
nAccessTypeID =Convert.ToInt16(dr["ACCESS_TYPE"].ToString());
|
||
|
if ((nSearchType == -2) && (nAccessTypeID > 0)) //Match on any non-zero type
|
||
|
{
|
||
|
bFinished = true;
|
||
|
bFound = true;
|
||
|
dResult = (DateTime) dr["START_TIME"];
|
||
|
break;
|
||
|
}
|
||
|
if (nAccessTypeID == nAVType)
|
||
|
{
|
||
|
bFinished = true;
|
||
|
bFound = true;
|
||
|
dResult = (DateTime) dr["START_TIME"];
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
dStart = dEnd.AddDays(1);
|
||
|
dEnd = dStart.AddDays(nIncrement);
|
||
|
if (dEnd > dtAVEnd)
|
||
|
dEnd = dtAVEnd;
|
||
|
} while (bFinished == false);
|
||
|
|
||
|
if (bFound == true)
|
||
|
{
|
||
|
aCopy.StartTime = dResult;
|
||
|
aCopy.EndTime = dResult.AddMinutes(a.Duration);
|
||
|
//Create the appointment
|
||
|
//Set the AUTOREBOOKED flag
|
||
|
//and store the "AutoRebooked To DateTime"
|
||
|
//in each autorebooked appointment
|
||
|
this.CreateAppointment(aCopy);
|
||
|
SetAutoRebook(a, dResult);
|
||
|
return "1";
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return "0";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void SetAutoRebook(CGAppointment a, DateTime dtRebookedTo)
|
||
|
{
|
||
|
string sApptKey = a.AppointmentKey.ToString();
|
||
|
string sRebookedTo = dtRebookedTo.ToString("M/d/yyyy@HH:mm");
|
||
|
string sSql = "BSDX REBOOK SET^" + sApptKey + "^" + sRebookedTo;
|
||
|
System.Data.DataTable dtRebook = m_DocManager.RPMSDataTable(sSql, "AutoRebook");
|
||
|
|
||
|
}
|
||
|
|
||
|
public string AppointmentNoShow(int nApptID, bool bNoShow)
|
||
|
{
|
||
|
/*
|
||
|
* BSDX NOSHOW RPC Returns 1 in ERRORID if successfully sets NOSHOW flag in BSDX APPOINTMENT and, if applicable, File 2
|
||
|
*Otherwise, returns 0 for failure and errormessage in ERRORTXT
|
||
|
*THIS routine returns "" if success or the message in ERRORTEXT if failed
|
||
|
*Exceptions should be caught by caller
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
string sTest = bNoShow.ToString();
|
||
|
string sNoShow = (bNoShow == true)?"1":"0";
|
||
|
string sSql = "BSDX NOSHOW^" + nApptID.ToString();
|
||
|
sSql += "^";
|
||
|
sSql += sNoShow;
|
||
|
|
||
|
DataTable dtAppt = m_DocManager.RPMSDataTable(sSql, "AppointmentNoShow");
|
||
|
|
||
|
Debug.Assert(dtAppt.Rows.Count == 1);
|
||
|
DataRow r = dtAppt.Rows[0];
|
||
|
string sErrorID = r["ERRORID"].ToString();
|
||
|
if (sErrorID != "1")
|
||
|
{
|
||
|
return r["ERRORTEXT"].ToString();
|
||
|
}
|
||
|
|
||
|
bool bRet = RefreshSchedule();
|
||
|
|
||
|
return sErrorID;
|
||
|
}
|
||
|
|
||
|
#endregion Methods
|
||
|
|
||
|
}//End class
|
||
|
}//End namespace
|