source: Scheduling/trunk/cs/bsdx0200GUISourceCode/CGDocument.cs@ 1075

Last change on this file since 1075 was 1073, checked in by Sam Habiel, 13 years ago

calendarGrid: Removed MouseEnter event and added it to CGView which now has to handle it properly.
CGAppointments: now supports cloning.
CGDocument: Added RefreshDocumentAsync, which retrives data from the server w/o asking the grid to refersh.
CGDocumentManager: CGView.InitializeDocView does not take appointments as argument; callers are changed.
CGView: Many Changes:

  • Opening a Schedule nows calls up a splash and a wait cursor while loading.
  • Events coming from the server are now handled asynchronously (not on UI thread). This results in much better responsiveness.
  • Appointments, Availabilities, Resources are all set in the CalendarGrid by UpdateArrays; as a centralized point of drawing the grid.
  • A mistaken "feature"--stealing focus from each others windows, was removed--CalendarGrid.Focus event only fired now if the form is the Active Form. This is accomplished using GetActiveWindow() from user32.dll (a Win32 API).

LoadingSplash: Opacity removed; form resized.

File size: 40.7 KB
Line 
1using System;
2using System.Collections;
3using System.Data;
4using System.Data.OleDb;
5using System.Diagnostics;
6using System.Drawing;
7using System.Windows.Forms;
8using IndianHealthService.BMXNet;
9
10namespace IndianHealthService.ClinicalScheduling
11{
12 /// <summary>
13 /// Contains the array of appointments and availabily that make up the document class
14 /// </summary>
15 public class CGDocument
16 {
17 #region Member Variables
18 public int m_nColumnCount; //todo: this should point to the view's member for column count
19 public int m_nTimeUnits; //?
20 private string m_sDocName; //Document Name ?
21 public ArrayList m_sResourcesArray; //keeps the resources
22 public ScheduleType m_ScheduleType; //Either a Resource or a Clinic (Group of Resources)
23 private DateTime m_dSelectedDate; //Holds the user's selection from the dtpicker
24 private DateTime m_dStartDate; //Beginning date of document data
25 private DateTime m_dEndDate; //Ending date of document data
26 public CGAppointments m_appointments; //Appointment List
27 private ArrayList m_pAvArray; //Availability List
28 private CGDocumentManager m_DocManager; //Holds a reference to the document manager
29 private DateTime m_dLastRefresh = DateTime.Now; //Holds last refersh date
30 #endregion
31
32 /// <summary>
33 /// Constructor. Initialize State Data:
34 /// 3 Arrays (Appointments, Availabilities, and Resources)
35 /// Schedule Type is Resource not Clinic
36 /// Selected Date is Today
37 /// Start Date is Today
38 /// End Date is 7 days from Today
39 /// </summary>
40 public CGDocument()
41 {
42 m_appointments = new CGAppointments(); // Holds Appointments
43 m_pAvArray = new ArrayList(); // Holds Availabilites
44 m_sResourcesArray = new ArrayList(); // Holds Resources
45 m_ScheduleType = ScheduleType.Resource; // Default Schedule Type is a Resource
46 m_dSelectedDate = DateTime.Today; // Default Selected Date is Today
47 m_dStartDate = DateTime.Today; // Default Start Date is Today
48 m_dEndDate = DateTime.Today.AddDays(7); // Default End Date is 7 days from Today.
49 }
50
51
52 #region Properties
53
54 /// <summary>
55 /// Returns the latest refresh time for this document
56 /// </summary>
57 public DateTime LastRefreshed
58 {
59 get
60 {
61 return m_dLastRefresh;
62 }
63 }
64
65 /// <summary>
66 /// The list of Resource names
67 /// </summary>
68 public ArrayList Resources
69 {
70 get
71 {
72 return this.m_sResourcesArray;
73 }
74 set
75 {
76 this.m_sResourcesArray = value;
77 }
78 }
79
80 /// <summary>
81 /// The array of CGAvailabilities that contains appt type and slots
82 /// </summary>
83 public ArrayList AvailabilityArray
84 {
85 get
86 {
87 return this.m_pAvArray;
88 }
89 }
90
91 public CGDocumentManager DocManager
92 {
93 get
94 {
95 return m_DocManager;
96 }
97 set
98 {
99 m_DocManager = value;
100 }
101 }
102
103 /// <summary>
104 /// Contains the hashtable of appointments
105 /// </summary>
106 public CGAppointments Appointments
107 {
108 get
109 {
110 return m_appointments;
111 }
112 }
113
114 /// <summary>
115 /// Holds the date selected by the user in CGView.dateTimePicker1
116 /// </summary>
117 public DateTime SelectedDate
118 {
119 get
120 {
121 return this.m_dSelectedDate;
122 }
123 set
124 {
125 this.m_dSelectedDate = value;
126 }
127 }
128
129 /// <summary>
130 /// Contains the beginning date of the appointment document
131 /// </summary>
132 public DateTime StartDate
133 {
134 get
135 {
136 return this.m_dStartDate;
137 }
138 }
139
140 public string DocName
141 {
142 get
143 {
144 return this.m_sDocName;
145 }
146 set
147 {
148 this.m_sDocName = value;
149 }
150 }
151
152 #endregion
153
154 #region Methods
155
156 public void UpdateAllViews()
157 {
158 //iterate through all views and call update.
159 Hashtable h = CGDocumentManager.Current.Views;
160
161 CGDocument d;
162 foreach (CGView v in h.Keys)
163 {
164 d = (CGDocument)h[v];
165 if (d == this)
166 {
167 v.UpdateArrays();
168 }
169 }
170
171 }
172
173 /// <summary>
174 /// Update schedule based on info in RPMS
175 /// </summary>
176 private bool RefreshDaysSchedule()
177 {
178 try
179 {
180 string sPatientName;
181 string sPatientID;
182 DateTime dStart;
183 DateTime dEnd;
184 DateTime dCheckIn;
185 DateTime dAuxTime;
186 int nKeyID;
187 string sNote;
188 string sResource;
189 bool bNoShow = false;
190 string sNoShow = "0";
191 string sHRN = "";
192 int nAccessTypeID; //used in autorebook
193 string sWalkIn = "0";
194 bool bWalkIn;
195 CGAppointment pAppointment;
196 CGDocumentManager pApp = CGDocumentManager.Current;
197 DataTable rAppointmentSchedule;
198
199 //Nice to know that it gets set here!!!
200 m_dLastRefresh = DateTime.Now;
201
202 this.m_appointments.ClearAllAppointments();
203
204 // calls RPC to get appointments
205 rAppointmentSchedule = CGSchedLib.CreateAppointmentSchedule(m_DocManager, m_sResourcesArray, this.m_dStartDate, this.m_dEndDate);
206
207 // Datatable dumper into Debug Log (nice to know that this exists)
208 CGSchedLib.OutputArray(rAppointmentSchedule, "rAppointmentSchedule");
209
210
211 foreach (DataRow r in rAppointmentSchedule.Rows)
212 {
213
214 if (r["APPOINTMENTID"].ToString() == "0")
215 {
216 string sMsg = r["NOTE"].ToString();
217 throw new BMXNetException(sMsg);
218 }
219 nKeyID = Convert.ToInt32(r["APPOINTMENTID"].ToString());
220 sResource = r["RESOURCENAME"].ToString();
221 sPatientName = r["PATIENTNAME"].ToString();
222 sPatientID = r["PATIENTID"].ToString();
223 dStart = (DateTime)r["START_TIME"];
224 dEnd = (DateTime)r["END_TIME"];
225 dCheckIn = new DateTime();
226 dAuxTime = new DateTime();
227
228 if (r["CHECKIN"].GetType() != typeof(System.DBNull))
229 dCheckIn = (DateTime)r["CHECKIN"];
230 if (r["AUXTIME"].GetType() != typeof(System.DBNull))
231 dCheckIn = (DateTime)r["AUXTIME"];
232 sNote = r["NOTE"].ToString();
233 sNoShow = r["NOSHOW"].ToString();
234 bNoShow = (sNoShow == "1") ? true : false;
235 sHRN = r["HRN"].ToString();
236 nAccessTypeID = (int)r["ACCESSTYPEID"];
237 sWalkIn = r["WALKIN"].ToString();
238 bWalkIn = (sWalkIn == "1") ? true : false;
239
240 pAppointment = new CGAppointment();
241 pAppointment.CreateAppointment(dStart, dEnd, sNote, nKeyID, sResource);
242 pAppointment.PatientName = sPatientName;
243 pAppointment.PatientID = Convert.ToInt32(sPatientID);
244 if (dCheckIn.Ticks > 0)
245 pAppointment.CheckInTime = dCheckIn;
246 if (dAuxTime.Ticks > 0)
247 pAppointment.AuxTime = dAuxTime;
248 pAppointment.NoShow = bNoShow;
249 pAppointment.HealthRecordNumber = sHRN;
250 pAppointment.AccessTypeID = nAccessTypeID;
251 pAppointment.WalkIn = bWalkIn;
252 this.m_appointments.AddAppointment(pAppointment);
253
254 }
255
256 return true;
257 }
258 catch (Exception Ex)
259 {
260 Debug.Write("CGDocument.RefreshDaysSchedule error: " + Ex.Message + "\n");
261 return false;
262 }
263 }
264
265
266 public bool IsRefreshNeeded()
267 {
268 if (m_sResourcesArray.Count == 0) return false;
269 return this.WeekNeedsRefresh(1, m_dSelectedDate, out this.m_dStartDate, out this.m_dEndDate);
270 }
271
272 //sam: This is a test that duplicates RefreshDocument, but without the UpdateAllViews,
273 // as that has to be done synchornously.
274 //XXXXXX: Needs to be refactored obviously, but now for testing.
275 public void RefreshDocumentAsync()
276 {
277 bool bRet = false;
278 if (m_sResourcesArray.Count == 0)
279 return;
280 if (m_sResourcesArray.Count == 1)
281 {
282 bRet = this.WeekNeedsRefresh(1, m_dSelectedDate, out this.m_dStartDate, out this.m_dEndDate);
283 }
284 else
285 {
286 this.m_dStartDate = m_dSelectedDate;
287 this.m_dEndDate = m_dSelectedDate;
288 this.m_dEndDate = this.m_dEndDate.AddHours(23);
289 this.m_dEndDate = this.m_dEndDate.AddMinutes(59);
290 this.m_dEndDate = this.m_dEndDate.AddSeconds(59);
291 }
292
293 bRet = RefreshSchedule();
294 }
295
296
297 public void RefreshDocument()
298 {
299 bool bRet = false;
300 if (m_sResourcesArray.Count == 0)
301 return;
302 if (m_sResourcesArray.Count == 1)
303 {
304 bRet = this.WeekNeedsRefresh(1, m_dSelectedDate, out this.m_dStartDate, out this.m_dEndDate);
305 }
306 else
307 {
308 this.m_dStartDate = m_dSelectedDate;
309 this.m_dEndDate = m_dSelectedDate;
310 this.m_dEndDate = this.m_dEndDate.AddHours(23);
311 this.m_dEndDate = this.m_dEndDate.AddMinutes(59);
312 this.m_dEndDate = this.m_dEndDate.AddSeconds(59);
313 }
314
315 bRet = RefreshSchedule();
316
317 this.UpdateAllViews();
318 }
319
320 public void OnOpenDocument()
321 {
322 try
323 {
324 //Create new Document
325 m_ScheduleType = (m_sResourcesArray.Count == 1) ? ScheduleType.Resource : ScheduleType.Clinic;
326 bool bRet = false;
327
328 //Set initial From and To dates based on current day
329 DateTime dDate = DateTime.Today;
330 if (m_ScheduleType == ScheduleType.Resource)
331 {
332 bRet = this.WeekNeedsRefresh(1, dDate, out this.m_dStartDate, out this.m_dEndDate);
333 }
334 else
335 {
336 this.m_dStartDate = dDate;
337 this.m_dEndDate = dDate;
338 this.m_dEndDate = this.m_dEndDate.AddHours(23);
339 this.m_dEndDate = this.m_dEndDate.AddMinutes(59);
340 this.m_dEndDate = this.m_dEndDate.AddSeconds(59);
341 }
342
343 bRet = RefreshSchedule();
344
345 CGView view = null;
346 //If this document already has a view, the use it
347 //SAM: Why do this again???
348 Hashtable h = CGDocumentManager.Current.Views;
349 CGDocument d;
350 bool bReuseView = false;
351 foreach (CGView v in h.Keys)
352 {
353 d = (CGDocument)h[v];
354 if (d == this)
355 {
356 view = v;
357 bReuseView = true;
358 v.InitializeDocView(this.DocName);
359 break;
360 }
361 }
362
363 //Otherwise, create new View
364 if (bReuseView == false)
365 {
366 view = new CGView();
367
368 view.InitializeDocView(this,
369 this.DocManager,
370 m_dStartDate,
371 this.DocName);
372
373 view.Show();
374 view.SyncTree();
375
376 }
377 this.UpdateAllViews();
378 }
379 catch (BMXNetException bmxEx)
380 {
381 throw bmxEx;
382 }
383 catch (Exception ex)
384 {
385 throw new BMXNet.BMXNetException("ClinicalScheduling.OnOpenDocument error: " + ex.Message);
386 }
387 }
388
389 /// <summary>
390 /// Refreshes Availablility and Schedules from RPMS.
391 /// </summary>
392 /// <returns>Success or Failure. Should be always Success.</returns>
393 private bool RefreshSchedule()
394 {
395 try
396 {
397 bool bRet = this.RefreshAvailabilitySchedule();
398 if (bRet == false)
399 {
400 return bRet;
401 }
402 bRet = this.RefreshDaysSchedule();
403 return bRet;
404 }
405 catch (ApplicationException aex)
406 {
407 Debug.Write("CGDocument.RefreshSchedule Application Error: " + aex.Message + "\n");
408 return false;
409 }
410 catch (Exception ex)
411 {
412 MessageBox.Show("CGDocument.RefreshSchedule error: " + ex.Message + "\n");
413 return false;
414 }
415 }
416
417 private bool RefreshAvailabilitySchedule()
418 {
419 try
420 {
421 if (this.m_DocManager.ConnectInfo.Connected == false)
422 {
423 m_DocManager.ConnectInfo.LoadConnectInfo();
424 }
425
426 m_pAvArray.Clear();
427
428 ArrayList saryApptTypes = new ArrayList();
429 int nApptTypeID = 0;
430
431 //Refresh Availability schedules
432 DataTable rAvailabilitySchedule;
433 rAvailabilitySchedule = CGSchedLib.CreateAvailabilitySchedule(m_DocManager, m_sResourcesArray, this.m_dStartDate, this.m_dEndDate, saryApptTypes,/**/ m_ScheduleType, "0");
434 CGSchedLib.OutputArray(rAvailabilitySchedule, "rAvailabilitySchedule");
435
436 //Refresh Type Schedule
437 string sResourceName = "";
438 DataTable rTypeSchedule = new DataTable(); ;
439 for (int j = 0; j < m_sResourcesArray.Count; j++)
440 {
441 sResourceName = m_sResourcesArray[j].ToString();
442 DataTable dtTemp = CGSchedLib.CreateAssignedTypeSchedule(m_DocManager, sResourceName, this.m_dStartDate, this.m_dEndDate, m_ScheduleType);
443 CGSchedLib.OutputArray(dtTemp, "dtTemp");
444 if (j == 0)
445 {
446 rTypeSchedule = dtTemp;
447 }
448 else
449 {
450 rTypeSchedule = CGSchedLib.UnionBlocks(rTypeSchedule, dtTemp);
451 }
452 }
453 CGSchedLib.OutputArray(rTypeSchedule, "rTypeSchedule");
454
455 DateTime dStart;
456 DateTime dEnd;
457 DateTime dTypeStart;
458 DateTime dTypeEnd;
459 int nSlots;
460 Rectangle crRectA = new Rectangle(0, 0, 1, 0);
461 Rectangle crRectB = new Rectangle(0, 0, 1, 0);
462 bool bIsect;
463 string sResourceList;
464 string sAccessRuleList;
465
466
467 foreach (DataRow rTemp in rAvailabilitySchedule.Rows)
468 {
469 //get StartTime, EndTime and Slots
470 dStart = (DateTime)rTemp["START_TIME"];
471 dEnd = (DateTime)rTemp["END_TIME"];
472
473 //TODO: Fix this slots datatype problem
474 string sSlots = rTemp["SLOTS"].ToString();
475 nSlots = Convert.ToInt16(sSlots);
476
477 sResourceList = rTemp["RESOURCE"].ToString();
478 sAccessRuleList = rTemp["ACCESS_TYPE"].ToString();
479
480 string sNote = rTemp["NOTE"].ToString();
481
482 if ((nSlots < -1000) || (sAccessRuleList == ""))
483 {
484 nApptTypeID = 0;
485 }
486 else
487 {
488 foreach (DataRow rType in rTypeSchedule.Rows)
489 {
490
491 dTypeStart = (DateTime)rType["StartTime"];
492 dTypeEnd = (DateTime)rType["EndTime"];
493 //if start & end times overlap, then
494 string sTypeResource = rType["ResourceName"].ToString();
495 if ((dTypeStart.DayOfYear == dStart.DayOfYear) && (sResourceList == sTypeResource))
496 {
497 crRectA.Y = GetTotalMinutes(dStart);
498 crRectA.Height = GetTotalMinutes(dEnd) - crRectA.Top;
499 crRectB.Y = GetTotalMinutes(dTypeStart);
500 crRectB.Height = GetTotalMinutes(dTypeEnd) - crRectB.Top;
501 bIsect = crRectA.IntersectsWith(crRectB);
502 if (bIsect == true)
503 {
504 //TODO: This code:
505 // nApptTypeID = (int) rType["AppointmentTypeID"];
506 //Causes this exception:
507 //Unhandled Exception: System.InvalidCastException: Specified cast is not valid.
508 string sTemp = rType["AppointmentTypeID"].ToString();
509 nApptTypeID = Convert.ToInt16(sTemp);
510 break;
511 }
512 }
513 }//end foreach datarow rType
514 }
515
516 AddAvailability(dStart, dEnd, nApptTypeID, nSlots, false, sResourceList, sAccessRuleList, sNote);
517 }//end foreach datarow rTemp
518
519 return true;
520 }
521 catch (Exception ex)
522 {
523 Debug.Write("CGDocument.RefreshAvailabilitySchedule error: " + ex.Message + "\n");
524 return false;
525 }
526 }
527
528 private int GetTotalMinutes(DateTime dDate)
529 {
530 return ((dDate.Hour * 60) + dDate.Minute);
531 }
532
533 public int AddAvailability(DateTime StartTime, DateTime EndTime, int nType, int nSlots, bool UpdateView, string sResourceList, string sAccessRuleList, string sNote)
534 {
535 //adds it to the object array
536 //Returns the index in the array
537
538 CGAvailability pNewAv = new CGAvailability();
539 pNewAv.Create(StartTime, EndTime, nType, nSlots, sResourceList, sAccessRuleList);
540
541 pNewAv.Note = sNote;
542
543 //Look up the color and type name using the AppointmentTypes datatable
544 DataTable dtType = this.m_DocManager.GlobalDataSet.Tables["AccessTypes"];
545 DataRow dRow = dtType.Rows.Find(nType.ToString());
546 if (dRow != null)
547 {
548 string sColor = dRow["DISPLAY_COLOR"].ToString();
549 pNewAv.DisplayColor = sColor;
550 string sTemp = dRow["RED"].ToString();
551 sTemp = (sTemp == "") ? "0" : sTemp;
552 int nRed = Convert.ToInt16(sTemp);
553 pNewAv.Red = nRed;
554 sTemp = dRow["GREEN"].ToString();
555 sTemp = (sTemp == "") ? "0" : sTemp;
556 int nGreen = Convert.ToInt16(sTemp);
557 pNewAv.Green = nGreen;
558 sTemp = dRow["BLUE"].ToString();
559 sTemp = (sTemp == "") ? "0" : sTemp;
560 int nBlue = Convert.ToInt16(sTemp);
561 pNewAv.Blue = nBlue;
562
563 string sName = dRow["ACCESS_TYPE_NAME"].ToString();
564 pNewAv.AccessTypeName = sName;
565 }
566
567 int nIndex = 0;
568 nIndex = m_pAvArray.Add(pNewAv);
569 if (UpdateView == true)
570 {
571 this.UpdateAllViews();
572 }
573 return nIndex;
574 }
575
576
577 public void AddResource(string sResource)
578 {
579 //TODO: Test that resource is not currently in list, that it IS a resource, etc
580 this.m_sResourcesArray.Add(sResource);
581 //SAM: removing: Remove UpdateAllViews: Redraws all the open views. But does not call server.
582 //this.UpdateAllViews();
583 }
584
585 public void ClearResources()
586 {
587 this.m_sResourcesArray.Clear();
588 }
589
590 public int SlotsAvailable(DateTime dSelStart, DateTime dSelEnd, string sResource, out string sAccessType, out string sAvailabilityMessage)
591 {
592 sAccessType = "";
593 sAvailabilityMessage = "";
594 DateTime dStart;
595 DateTime dEnd;
596 int nAvailableSlots = 999;
597 int nSlots = 0;
598 int i = 0;
599 CGAvailability pAv;
600 Rectangle crRectA = new Rectangle(0, 0, 1, 0);
601 Rectangle crRectB = new Rectangle(0, 0, 1, 0);
602 bool bIsect;
603 crRectB.Y = GetTotalMinutes(dSelStart);
604 crRectB.Height = GetTotalMinutes(dSelEnd) - crRectB.Y;
605
606 // //loop thru m_pAvArray
607 // //Compare the start time and end time of eachblock
608 while (i < m_pAvArray.Count)
609 {
610 pAv = (CGAvailability)m_pAvArray[i];
611 dStart = pAv.StartTime;
612 dEnd = pAv.EndTime;
613 if ((sResource == pAv.ResourceList) &&
614 ((dSelStart.Date == dStart.Date) || (dSelStart.Date == dEnd.Date)))
615 {
616 crRectA.Y = (dStart.Date < dSelStart.Date) ? 0 : GetTotalMinutes(dStart);
617 crRectA.Height = (dEnd.Date > dSelEnd.Date) ? 1440 : GetTotalMinutes(dEnd);
618 crRectA.Height = crRectA.Height - crRectA.Y;
619 bIsect = crRectA.IntersectsWith(crRectB);
620 if (bIsect != false)
621 {
622 nSlots = pAv.Slots;
623 if (nSlots < 1)
624 {
625 nAvailableSlots = 0;
626 break;
627 }
628 if (nSlots < nAvailableSlots)
629 {
630 nAvailableSlots = nSlots;
631 sAccessType = pAv.AccessTypeName;
632 sAvailabilityMessage = pAv.Note;
633
634 }
635 }
636 }
637 i++;
638 }
639 if (nAvailableSlots == 999)
640 {
641 nAvailableSlots = 0;
642 }
643 return nAvailableSlots;
644 }
645
646 /// <summary>
647 /// Given a selected date,
648 /// Calculates StartDay and End Day and returns them in output params.
649 /// nWeeks == number of Weeks to display
650 /// nColumnCount is number of days displayed per week.
651 /// If 5 columns, begin on Second Day of Week
652 /// If 7 Columns, begin on First Day of Week
653 /// (this is a change from the hardcoded behavior for US-based calendars)
654 ///
655 /// Returns TRUE if the document's data needs refreshing based on
656 /// this newly selected date.
657 /// </summary>
658 public bool WeekNeedsRefresh(int nWeeks, DateTime SelectedDate,
659 out DateTime WeekStartDay, out DateTime WeekEndDay)
660 {
661 DateTime OldStartDay = m_dStartDate;
662 DateTime OldEndDay = m_dEndDate;
663 // Week start based on thread locale
664 int nStartWeekDay = (int)System.Threading.Thread.CurrentThread.CurrentCulture.DateTimeFormat.FirstDayOfWeek;
665 // Current Day
666 int nWeekDay = (int)SelectedDate.DayOfWeek; //0 == Sunday
667
668 // this offset gets approrpriate day based on locale.
669 int nOff = (nStartWeekDay + 1) % 7;
670 TimeSpan ts = new TimeSpan(nWeekDay - nOff, 0, 0, 0); //d,h,m,s
671
672 // if ts is negative, we will jump to the next week in the logic.
673 // to show the correct week, add 7. Confusing, I know.
674 if (ts < new TimeSpan()) ts = ts + new TimeSpan(7, 0, 0, 0);
675
676 if (m_nColumnCount == 1) // if one column start and end on the same day.
677 {
678 ts = new TimeSpan(0, 23, 59, 59);
679 WeekStartDay = SelectedDate;
680 WeekEndDay = WeekStartDay + ts;
681 }
682 else if (m_nColumnCount == 5 || m_nColumnCount == 0) // if 5 column start (or default) at the 2nd day of this week and end in 4:23:59:59 days.
683 {
684 // if picked day is start of week (Sunday in US), start in the next day since that's the first day of work week
685 // else, just substract the calculated time span to get to the start of week (first work day)
686 WeekStartDay = (nWeekDay == nStartWeekDay) ? SelectedDate + new TimeSpan(1, 0, 0, 0) : SelectedDate - ts;
687 // End day calculation
688 int nEnd = 3;
689 ts = new TimeSpan((7 * nWeeks) - nEnd, 23, 59, 59);
690 WeekEndDay = WeekStartDay + ts;
691 }
692 else // if 7 column start at the 1st day of this week and end in 6:23:59:59 days.
693 {
694 // if picked day is start of week, use that. Otherwise, go to the fist work day and substract one to get to start of week.
695 WeekStartDay = (nWeekDay == nStartWeekDay) ? SelectedDate : SelectedDate - ts - new TimeSpan(1, 0, 0, 0);
696 // End day calculation
697 int nEnd = 1;
698 ts = new TimeSpan((7 * nWeeks) - nEnd, 23, 59, 59);
699 WeekEndDay = WeekStartDay + ts;
700 }
701
702 bool bRet = ((WeekStartDay.Date != OldStartDay.Date) || (WeekEndDay.Date != OldEndDay.Date));
703 return bRet;
704 }
705
706 /// <summary>
707 /// Calls RPMS to create appointment then
708 /// adds appointment to the m_appointments collection
709 /// Returns the IEN of the appointment in the RPMS BSDX APPOINTMENT file.
710 /// </summary>
711 /// <param name="rApptInfo"></param>
712 /// <returns></returns>
713 public int CreateAppointment(CGAppointment rApptInfo)
714 {
715 return CreateAppointment(rApptInfo, false);
716 }
717
718 /// <summary>
719 /// Use this overload to create a walkin appointment
720 /// </summary>
721 /// <param name="rApptInfo"></param>
722 /// <param name="bWalkin"></param>
723 /// <returns></returns>
724 public int CreateAppointment(CGAppointment rApptInfo, bool bWalkin)
725 {
726 string sStart;
727 string sEnd;
728 string sPatID;
729 string sResource;
730 string sNote;
731 string sLen;
732 string sApptID;
733
734 //sStart = rApptInfo.StartTime.ToString("M-d-yyyy@HH:mm");
735 //sEnd = rApptInfo.EndTime.ToString("M-d-yyyy@HH:mm");
736
737 // i18n code -- Use culture neutral FMDates
738 sStart = FMDateTime.Create(rApptInfo.StartTime).FMDateString;
739 sEnd = FMDateTime.Create(rApptInfo.EndTime).FMDateString;
740
741 TimeSpan sp = rApptInfo.EndTime - rApptInfo.StartTime;
742 sLen = sp.TotalMinutes.ToString();
743 sPatID = rApptInfo.PatientID.ToString();
744 sNote = rApptInfo.Note;
745 sResource = rApptInfo.Resource;
746 if (bWalkin == true)
747 {
748 sApptID = "WALKIN";
749 }
750 else
751 {
752 sApptID = rApptInfo.AccessTypeID.ToString();
753 }
754
755 CGAppointment aCopy = new CGAppointment();
756 aCopy.CreateAppointment(rApptInfo.StartTime, rApptInfo.EndTime, sNote, 0, sResource);
757 aCopy.PatientID = rApptInfo.PatientID;
758 aCopy.PatientName = rApptInfo.PatientName;
759 aCopy.HealthRecordNumber = rApptInfo.HealthRecordNumber;
760 aCopy.AccessTypeID = rApptInfo.AccessTypeID;
761
762 string sSql = "BSDX ADD NEW APPOINTMENT^" + sStart + "^" + sEnd + "^" + sPatID + "^" + sResource + "^" + sLen + "^" + sNote + "^" + sApptID;
763 System.Data.DataTable dtAppt = m_DocManager.RPMSDataTable(sSql, "NewAppointment");
764 int nApptID;
765
766 Debug.Assert(dtAppt.Rows.Count == 1);
767 DataRow r = dtAppt.Rows[0];
768 nApptID = Convert.ToInt32(r["APPOINTMENTID"]);
769 string sErrorID;
770 sErrorID = r["ERRORID"].ToString();
771 if ((sErrorID != "") || (nApptID < 1))
772 throw new Exception(sErrorID);
773 aCopy.AppointmentKey = nApptID;
774 this.m_appointments.AddAppointment(aCopy);
775
776 bool bRet = RefreshAvailabilitySchedule();
777
778 UpdateAllViews();
779
780 return nApptID;
781 }
782
783 public void EditAppointment(CGAppointment pAppt, string sNote)
784 {
785 try
786 {
787 int nApptID = pAppt.AppointmentKey;
788 string sSql = "BSDX EDIT APPOINTMENT^" + nApptID.ToString() + "^" + sNote;
789
790 System.Data.DataTable dtAppt = m_DocManager.RPMSDataTable(sSql, "EditAppointment");
791
792 Debug.Assert(dtAppt.Rows.Count == 1);
793 DataRow r = dtAppt.Rows[0];
794 string sErrorID = r["ERRORID"].ToString();
795 if (sErrorID == "-1")
796 pAppt.Note = sNote;
797
798 if (this.m_appointments.AppointmentTable.ContainsKey(nApptID))
799 {
800 bool bRet = RefreshAvailabilitySchedule();
801 UpdateAllViews();
802 }
803 }
804 catch (Exception ex)
805 {
806 Debug.Write("CGDocument.EditAppointment Failed: " + ex.Message);
807 }
808 }
809
810 public void CheckInAppointment(int nApptID, DateTime dCheckIn)
811 {
812 string sCheckIn = FMDateTime.Create(dCheckIn).FMDateString;
813
814 string sSql = "BSDX CHECKIN APPOINTMENT^" + nApptID.ToString() + "^" + sCheckIn; // +"^";
815 //sSql += ClinicStopIEN + "^" + ProviderIEN + "^" + PrintRouteSlip + "^";
816 //sSql += PCCClinicIEN + "^" + PCCFormIEN + "^" + PCCOutGuide;
817
818 System.Data.DataTable dtAppt = m_DocManager.RPMSDataTable(sSql, "CheckInAppointment");
819
820 Debug.Assert(dtAppt.Rows.Count == 1);
821 DataRow r = dtAppt.Rows[0];
822 string sErrorID = r["ERRORID"].ToString();
823
824 if (this.m_appointments.AppointmentTable.ContainsKey(nApptID))
825 {
826 bool bRet = RefreshSchedule();
827 UpdateAllViews();
828 }
829 }
830
831 public string DeleteAppointment(int nApptID)
832 {
833 return DeleteAppointment(nApptID, true, 0, "");
834 }
835
836 public string DeleteAppointment(int nApptID, bool bClinicCancelled, int nReason, string sRemarks)
837 {
838 //Returns "" if deletion successful
839 //Otherwise, returns reason for failure
840
841 string sClinicCancelled = (bClinicCancelled == true) ? "C" : "PC";
842 string sReasonID = nReason.ToString();
843 string sSql = "BSDX CANCEL APPOINTMENT^" + nApptID.ToString();
844 sSql += "^" + sClinicCancelled;
845 sSql += "^" + sReasonID;
846 sSql += "^" + sRemarks;
847 DataTable dtAppt = m_DocManager.RPMSDataTable(sSql, "DeleteAppointment");
848
849 Debug.Assert(dtAppt.Rows.Count == 1);
850 DataRow r = dtAppt.Rows[0];
851 string sErrorID = r["ERRORID"].ToString();
852 if (sErrorID != "")
853 return sErrorID;
854
855 if (this.m_appointments.AppointmentTable.ContainsKey(nApptID))
856 {
857 this.m_appointments.RemoveAppointment(nApptID);
858 bool bRet = RefreshAvailabilitySchedule();
859 UpdateAllViews();
860 }
861 return "";
862 }
863
864 public string AutoRebook(CGAppointment a, int nSearchType, int nMinimumDays, int nMaximumDays, out CGAppointment aRebook)
865 {
866 //If successful Returns "1" and new start date and time returned in aRebook
867 //Otherwise, returns error message
868
869 CGAppointment aCopy = new CGAppointment();
870 aCopy.CreateAppointment(a.StartTime, a.EndTime, a.Note, 0, a.Resource);
871 aCopy.PatientID = a.PatientID;
872 aCopy.PatientName = a.PatientName;
873 aCopy.HealthRecordNumber = a.HealthRecordNumber;
874 aCopy.AccessTypeID = a.AccessTypeID;
875 aRebook = aCopy;
876
877 //Determine Rebook access type
878 //nSearchType = -1: use current, -2: use any non-zero type, >0 use this access type id
879 int nAVType = 0;
880
881 switch (nSearchType)
882 {
883 case -1:
884 nAVType = a.AccessTypeID;
885 break;
886 case -2:
887 nAVType = 0;
888 break;
889 default:
890 nAVType = nSearchType;
891 break;
892 }
893
894 int nSlots = 0;
895 string sSlots = "";
896 int nAccessTypeID; //To compare with nAVType
897
898 DateTime dResult = new DateTime(); //StartTime of access block to autorebook into
899
900 //Next two are empty, but needed to pass to CreateAvailabilitySchedule
901 ArrayList alAccessTypes = new ArrayList();
902 string sSearchInfo = "";
903
904 //Find the StartTime of first availability block of this type for this clinic
905 //between nMinimumDays and nMaximumDays
906
907 string sAVStart = a.StartTime.AddDays(nMinimumDays).ToString("M/d/yyyy@H:mm");
908
909 //dtAVEnd is the last day to search
910 DateTime dtAVEnd = a.StartTime.AddDays(nMinimumDays + nMaximumDays);
911 string sAVEnd = dtAVEnd.ToString("M/d/yyyy@H:mm");
912
913 //Increment start day to search a week (or so) at a time
914 //30 is a test increment. Need to test different values for performance
915 int nIncrement = (nMaximumDays < 30) ? nMaximumDays : 30;
916
917 //nCount and nCountEnd are the 'moving' counters
918 //that I add to start and end to get the bracket
919 //At the beginning of the DO loop, nCount and nCountEnd are already set
920 bool bFinished = false;
921 bool bFound = false;
922
923 DateTime dStart = a.StartTime.AddDays(nMinimumDays);
924 // v 1.3 i18n support - FM Date passed insated of American Date
925 string sStart = FMDateTime.Create(dStart).DateOnly.FMDateString;
926 DateTime dEnd = dStart.AddDays(nIncrement);
927 do
928 {
929 string sSql = "BSDX REBOOK NEXT BLOCK^" + sStart + "^" + a.Resource + "^" + nAVType.ToString();
930 DataTable dtNextBlock = this.DocManager.RPMSDataTable(sSql, "NextBlock");
931 Debug.Assert(dtNextBlock.Rows.Count == 1);
932 DataRow drNextBlockRow = dtNextBlock.Rows[0];
933
934 object oNextBlock;
935 oNextBlock = drNextBlockRow["NEXTBLOCK"];
936 if (oNextBlock.GetType() == typeof(System.DBNull))
937 break;
938 DateTime dNextBlock = (DateTime)drNextBlockRow["NEXTBLOCK"];
939 if (dNextBlock > dtAVEnd)
940 {
941 break;
942 }
943
944 dStart = dNextBlock;
945 dEnd = dStart.AddDays(nIncrement);
946 if (dEnd > dtAVEnd)
947 dEnd = dtAVEnd;
948
949 DataTable dtResult = CGSchedLib.CreateAvailabilitySchedule(m_DocManager, this.Resources, dStart, dEnd, alAccessTypes, ScheduleType.Resource, sSearchInfo);
950 //Loop thru dtResult looking for a slot having the required availability type.
951 //If found, set bFinished = true;
952 foreach (DataRow dr in dtResult.Rows)
953 {
954
955 sSlots = dr["SLOTS"].ToString();
956 if (sSlots == "")
957 sSlots = "0";
958 nSlots = Convert.ToInt16(sSlots);
959 if (nSlots > 0)
960 {
961 nAccessTypeID = 0; //holds the access type id of the availability block
962 if (dr["ACCESS_TYPE"].ToString() != "")
963 nAccessTypeID = Convert.ToInt16(dr["ACCESS_TYPE"].ToString());
964 if ((nSearchType == -2) && (nAccessTypeID > 0)) //Match on any non-zero type
965 {
966 bFinished = true;
967 bFound = true;
968 dResult = (DateTime)dr["START_TIME"];
969 break;
970 }
971 if (nAccessTypeID == nAVType)
972 {
973 bFinished = true;
974 bFound = true;
975 dResult = (DateTime)dr["START_TIME"];
976 break;
977 }
978 }
979 }
980 dStart = dEnd.AddDays(1);
981 dEnd = dStart.AddDays(nIncrement);
982 if (dEnd > dtAVEnd)
983 dEnd = dtAVEnd;
984 } while (bFinished == false);
985
986 if (bFound == true)
987 {
988 aCopy.StartTime = dResult;
989 aCopy.EndTime = dResult.AddMinutes(a.Duration);
990 //Create the appointment
991 //Set the AUTOREBOOKED flag
992 //and store the "AutoRebooked To DateTime"
993 //in each autorebooked appointment
994 this.CreateAppointment(aCopy);
995 SetAutoRebook(a, dResult);
996 return "1";
997 }
998 else
999 {
1000 return "0";
1001 }
1002 }
1003
1004 private void SetAutoRebook(CGAppointment a, DateTime dtRebookedTo)
1005 {
1006 string sApptKey = a.AppointmentKey.ToString();
1007 //string sRebookedTo = dtRebookedTo.ToString("M/d/yyyy@HH:mm");
1008 // i18n
1009 string sRebookedTo = FMDateTime.Create(dtRebookedTo).FMDateString;
1010 string sSql = "BSDX REBOOK SET^" + sApptKey + "^" + sRebookedTo;
1011 System.Data.DataTable dtRebook = m_DocManager.RPMSDataTable(sSql, "AutoRebook");
1012
1013 }
1014
1015 public string AppointmentNoShow(int nApptID, bool bNoShow)
1016 {
1017 /*
1018 * BSDX NOSHOW RPC Returns 1 in ERRORID if successfully sets NOSHOW flag in BSDX APPOINTMENT and, if applicable, File 2
1019 *Otherwise, returns negative numbers for failure and errormessage in ERRORTXT
1020 *
1021 */
1022
1023 string sTest = bNoShow.ToString();
1024 string sNoShow = (bNoShow == true) ? "1" : "0";
1025 string sSql = "BSDX NOSHOW^" + nApptID.ToString();
1026 sSql += "^";
1027 sSql += sNoShow;
1028
1029 DataTable dtAppt = m_DocManager.RPMSDataTable(sSql, "AppointmentNoShow");
1030
1031 Debug.Assert(dtAppt.Rows.Count == 1);
1032 DataRow r = dtAppt.Rows[0];
1033 string sErrorID = r["ERRORID"].ToString();
1034 if (sErrorID != "1")
1035 {
1036 return r["ERRORTEXT"].ToString();
1037 }
1038
1039 bool bRet = RefreshSchedule();
1040
1041 return sErrorID;
1042 }
1043
1044 #endregion Methods
1045
1046 }//End class
1047}//End namespace
Note: See TracBrowser for help on using the repository browser.