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

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

Updated Release exes.
CGDocument: Appointment Creation Code now reuses appt object passed in rather than creating a new one.
CGView:
ctxPrintScheduleT3 added. Print schedule in 3 days. For weekday after weekend.
Scaling of grid now restricted. You can't scale down from the original TimeScale, but you can scale up.
DCheckIn: Remove unused variables.
DResource: Remove unused variables.

File size: 54.6 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;
9using System.Linq;
10using System.Collections.Generic;
11
12namespace IndianHealthService.ClinicalScheduling
13{
14 /// <summary>
15 /// Contains the array of appointments and availabily that make up the document class
16 /// </summary>
17 public class CGDocument
18 {
19 #region Member Variables
20 public int m_nColumnCount; //todo: this should point to the view's member for column count
21 public int m_nTimeUnits; //?
22 private string m_sDocName; //Document Name ?
23 public ArrayList m_sResourcesArray; //keeps the resources
24 public ScheduleType m_ScheduleType; //Either a Resource or a Clinic (Group of Resources)
25 private DateTime m_dSelectedDate; //Holds the user's selection from the dtpicker
26 private DateTime m_dStartDate; //Beginning date of document data
27 private DateTime m_dEndDate; //Ending date of document data
28 public CGAppointments m_appointments; //Appointment List
29 private ArrayList m_pAvArray; //Availability List
30 private CGDocumentManager m_DocManager; //Holds a reference to the document manager
31 private DateTime m_dLastRefresh = DateTime.Now; //Holds last refersh date
32 #endregion
33
34 /// <summary>
35 /// Constructor. Initialize State Data:
36 /// 3 Arrays (Appointments, Availabilities, and Resources)
37 /// Schedule Type is Resource not Clinic
38 /// Selected Date is Today
39 /// Start Date is Today
40 /// End Date is 7 days from Today
41 /// </summary>
42 public CGDocument()
43 {
44 m_appointments = new CGAppointments(); // Holds Appointments
45 m_pAvArray = new ArrayList(); // Holds Availabilites
46 m_sResourcesArray = new ArrayList(); // Holds Resources
47 m_ScheduleType = ScheduleType.Resource; // Default Schedule Type is a Resource
48 m_dSelectedDate = DateTime.Today; // Default Selected Date is Today
49 m_dStartDate = DateTime.Today; // Default Start Date is Today
50 m_dEndDate = DateTime.Today.AddDays(7); // Default End Date is 7 days from Today.
51 }
52
53
54 #region Properties
55
56 /// <summary>
57 /// Returns the latest refresh time for this document
58 /// </summary>
59 public DateTime LastRefreshed
60 {
61 get
62 {
63 return m_dLastRefresh;
64 }
65 }
66
67 /// <summary>
68 /// The list of Resource names
69 /// </summary>
70 public ArrayList Resources
71 {
72 get
73 {
74 return this.m_sResourcesArray;
75 }
76 set
77 {
78 this.m_sResourcesArray = value;
79 }
80 }
81
82 /// <summary>
83 /// The array of CGAvailabilities that contains appt type and slots
84 /// </summary>
85 public ArrayList AvailabilityArray
86 {
87 get
88 {
89 return this.m_pAvArray;
90 }
91 }
92
93 public CGDocumentManager DocManager
94 {
95 get
96 {
97 return m_DocManager;
98 }
99 set
100 {
101 m_DocManager = value;
102 }
103 }
104
105 /// <summary>
106 /// Contains the hashtable of appointments
107 /// </summary>
108 public CGAppointments Appointments
109 {
110 get
111 {
112 return m_appointments;
113 }
114 }
115
116 /// <summary>
117 /// Holds the date selected by the user in CGView.dateTimePicker1
118 /// </summary>
119 public DateTime SelectedDate
120 {
121 get
122 {
123 return this.m_dSelectedDate;
124 }
125 set
126 {
127 this.m_dSelectedDate = value;
128 }
129 }
130
131 /// <summary>
132 /// Contains the beginning date of the appointment document
133 /// </summary>
134 public DateTime StartDate
135 {
136 get
137 {
138 return this.m_dStartDate;
139 }
140 }
141
142 public string DocName
143 {
144 get
145 {
146 return this.m_sDocName;
147 }
148 set
149 {
150 this.m_sDocName = value;
151 }
152 }
153
154 #endregion
155
156 #region Methods
157
158 public void UpdateAllViews()
159 {
160 //iterate through all views and call update.
161 Hashtable h = CGDocumentManager.Current.Views;
162
163 CGDocument d;
164 foreach (CGView v in h.Keys)
165 {
166 d = (CGDocument)h[v];
167 if (d == this)
168 {
169 v.UpdateArrays();
170 }
171 }
172
173 }
174
175 /// <summary>
176 /// Update schedule based on info in RPMS
177 /// <returns>Clears and repopluates m_appointments</returns>
178 /// </summary>
179 private bool RefreshAppointments()
180 {
181 try
182 {
183 string sPatientName;
184 string sPatientID;
185 DateTime dStart;
186 DateTime dEnd;
187 DateTime dCheckIn;
188 DateTime dAuxTime;
189 int nKeyID;
190 string sNote;
191 string sResource;
192 bool bNoShow = false;
193 string sNoShow = "0";
194 string sHRN = "";
195 int nAccessTypeID; //used in autorebook
196 string sWalkIn = "0";
197 bool bWalkIn;
198 CGAppointment pAppointment;
199 CGDocumentManager pApp = CGDocumentManager.Current;
200 DataTable rAppointmentSchedule;
201
202 //Nice to know that it gets set here!!!
203 m_dLastRefresh = DateTime.Now;
204
205 //Clear appointments associated with this document
206 this.m_appointments.ClearAllAppointments();
207
208 // calls RPC to get appointments
209 rAppointmentSchedule = CGSchedLib.CreateAppointmentSchedule(m_DocManager, m_sResourcesArray, this.m_dStartDate, this.m_dEndDate);
210
211 // loop through datatable: Create CGAppointment and add to CGAppointments
212 foreach (DataRow r in rAppointmentSchedule.Rows)
213 {
214
215 if (r["APPOINTMENTID"].ToString() == "0")
216 {
217 string sMsg = r["NOTE"].ToString();
218 throw new BMXNetException(sMsg);
219 }
220 nKeyID = Convert.ToInt32(r["APPOINTMENTID"].ToString());
221 sResource = r["RESOURCENAME"].ToString();
222 sPatientName = r["PATIENTNAME"].ToString();
223 sPatientID = r["PATIENTID"].ToString();
224 dStart = (DateTime)r["START_TIME"];
225 dEnd = (DateTime)r["END_TIME"];
226 dCheckIn = new DateTime();
227 dAuxTime = new DateTime();
228
229 if (r["CHECKIN"].GetType() != typeof(System.DBNull))
230 dCheckIn = (DateTime)r["CHECKIN"];
231 if (r["AUXTIME"].GetType() != typeof(System.DBNull))
232 dCheckIn = (DateTime)r["AUXTIME"];
233 sNote = r["NOTE"].ToString();
234 sNoShow = r["NOSHOW"].ToString();
235 bNoShow = (sNoShow == "1") ? true : false;
236 sHRN = r["HRN"].ToString();
237 nAccessTypeID = (int)r["ACCESSTYPEID"];
238 sWalkIn = r["WALKIN"].ToString();
239 bWalkIn = (sWalkIn == "1") ? true : false;
240
241 Patient pt = new Patient()
242 {
243 DFN = Convert.ToInt32(sPatientID),
244 Name = sPatientName,
245 DOB = (DateTime)r["DOB"],
246 ID = r["PID"].ToString(),
247 HRN = sHRN,
248 Sex = r["SEX"].ToString() == "MALE" ? Sex.Male : Sex.Female
249 };
250
251 pAppointment = new CGAppointment();
252 pAppointment.Patient = pt;
253 pAppointment.CreateAppointment(dStart, dEnd, sNote, nKeyID, sResource);
254 pAppointment.PatientName = sPatientName;
255 pAppointment.PatientID = Convert.ToInt32(sPatientID);
256 if (dCheckIn.Ticks > 0)
257 pAppointment.CheckInTime = dCheckIn;
258 if (dAuxTime.Ticks > 0)
259 pAppointment.AuxTime = dAuxTime;
260 pAppointment.NoShow = bNoShow;
261 pAppointment.HealthRecordNumber = sHRN;
262 pAppointment.AccessTypeID = nAccessTypeID;
263 pAppointment.WalkIn = bWalkIn;
264 this.m_appointments.AddAppointment(pAppointment);
265
266 }
267
268 return true;
269 }
270 catch (Exception Ex)
271 {
272 Debug.Write("CGDocument.RefreshDaysSchedule error: " + Ex.Message + "\n");
273 return false;
274 }
275 }
276
277
278 public bool IsRefreshNeeded()
279 {
280 if (m_sResourcesArray.Count == 0) return false;
281 return this.WeekNeedsRefresh(1, m_dSelectedDate, out this.m_dStartDate, out this.m_dEndDate);
282 }
283
284 //sam: This is a test that duplicates RefreshDocument, but without the UpdateAllViews,
285 // as that has to be done synchornously.
286 //XXX: Needs to be refactored obviously, but now for testing.
287 //XXX: Tested extensively enough. Less refactoring now. 2011-01-26
288 public void RefreshDocumentAsync()
289 {
290 Debug.WriteLine("IN REFERSH DOCUMENT ASYNC\n\n");
291
292 bool bRet = false;
293 if (m_sResourcesArray.Count == 0)
294 return;
295 if (m_sResourcesArray.Count == 1)
296 {
297 bRet = this.WeekNeedsRefresh(1, m_dSelectedDate, out this.m_dStartDate, out this.m_dEndDate);
298 }
299 else
300 {
301 this.m_dStartDate = m_dSelectedDate;
302 this.m_dEndDate = m_dSelectedDate;
303 this.m_dEndDate = this.m_dEndDate.AddHours(23);
304 this.m_dEndDate = this.m_dEndDate.AddMinutes(59);
305 this.m_dEndDate = this.m_dEndDate.AddSeconds(59);
306 }
307
308 bRet = RefreshSchedule();
309 }
310
311
312 public void RefreshDocument()
313 {
314 bool bRet = false;
315 if (m_sResourcesArray.Count == 0)
316 return;
317 if (m_sResourcesArray.Count == 1)
318 {
319 bRet = this.WeekNeedsRefresh(1, m_dSelectedDate, out this.m_dStartDate, out this.m_dEndDate);
320 }
321 else
322 {
323 this.m_dStartDate = m_dSelectedDate;
324 this.m_dEndDate = m_dSelectedDate;
325 this.m_dEndDate = this.m_dEndDate.AddHours(23);
326 this.m_dEndDate = this.m_dEndDate.AddMinutes(59);
327 this.m_dEndDate = this.m_dEndDate.AddSeconds(59);
328 }
329
330 bRet = RefreshSchedule();
331
332 this.UpdateAllViews();
333 }
334
335 public void OnOpenDocument(DateTime dDate)
336 {
337 try
338 {
339 this.SelectedDate = dDate.Date;
340
341 m_ScheduleType = (m_sResourcesArray.Count == 1) ? ScheduleType.Resource : ScheduleType.Clinic;
342 bool bRet = false;
343
344 if (m_ScheduleType == ScheduleType.Resource)
345 {
346 bRet = this.WeekNeedsRefresh(1, dDate, out this.m_dStartDate, out this.m_dEndDate);
347 }
348 else
349 {
350 this.m_dStartDate = dDate;
351 this.m_dEndDate = dDate;
352 this.m_dEndDate = this.m_dEndDate.AddHours(23);
353 this.m_dEndDate = this.m_dEndDate.AddMinutes(59);
354 this.m_dEndDate = this.m_dEndDate.AddSeconds(59);
355 }
356
357 bRet = RefreshSchedule();
358
359 CGView view = null;
360 //If this document already has a view, the use it
361 //SAM: Why do this again???
362 //SAM: I think it's not needed; b/c
363 Hashtable h = CGDocumentManager.Current.Views;
364 CGDocument d;
365 bool bReuseView = false;
366 foreach (CGView v in h.Keys)
367 {
368 d = (CGDocument)h[v];
369 if (d == this)
370 {
371 view = v;
372 bReuseView = true;
373 v.InitializeDocView(this.DocName);
374 break;
375 }
376 }
377
378 //Otherwise, create new View
379 if (bReuseView == false)
380 {
381 view = new CGView();
382
383 view.InitializeDocView(this,
384 this.DocManager,
385 m_dStartDate,
386 this.DocName);
387
388 view.Show();
389 view.SyncTree();
390
391 }
392 this.UpdateAllViews();
393 }
394 catch (BMXNetException bmxEx)
395 {
396 throw bmxEx;
397 }
398 catch (Exception ex)
399 {
400 throw new BMXNet.BMXNetException("ClinicalScheduling.OnOpenDocument error: " + ex.Message);
401 }
402 }
403
404 /// <summary>
405 /// Refreshes Availablility and Schedules from RPMS.
406 /// </summary>
407 /// <returns>Success or Failure. Should be always Success.</returns>
408 private bool RefreshSchedule()
409 {
410 this.RefreshAvailabilitySchedule();
411 this.RefreshAppointments();
412 return true;
413 }
414
415 private bool RefreshAvailabilitySchedule()
416 {
417 try
418 {
419 ArrayList saryApptTypes = new ArrayList();
420
421 //Refresh Availability schedules
422 DataTable rAvailabilitySchedule;
423 rAvailabilitySchedule = CGSchedLib.CreateAvailabilitySchedule(m_DocManager, m_sResourcesArray, this.m_dStartDate, this.m_dEndDate, saryApptTypes,/**/ m_ScheduleType, "0");
424
425 ////NEW
426 //NOTE: This lock makes sure that availabilities aren't queried for slots when the array is an intermediate
427 //state. The other place that has this lock is SlotsAvailable function.
428 lock (this.m_pAvArray)
429 {
430 m_pAvArray.Clear();
431 foreach (DataRow rTemp in rAvailabilitySchedule.Rows)
432 {
433 DateTime dStart = (DateTime)rTemp["START_TIME"];
434 DateTime dEnd = (DateTime)rTemp["END_TIME"];
435
436 //TODO: Fix this slots datatype problem
437 string sSlots = rTemp["SLOTS"].ToString();
438 int nSlots = Convert.ToInt16(sSlots);
439
440 string sResourceList = rTemp["RESOURCE"].ToString();
441 string sAccessRuleList = rTemp["ACCESS_TYPE"].ToString();
442 string sNote = rTemp["NOTE"].ToString();
443
444 int nApptTypeID;
445
446 if ((nSlots < -1000) || (sAccessRuleList == ""))
447 {
448 nApptTypeID = 0;
449 }
450 else
451 {
452 nApptTypeID = Int32.Parse(rTemp["ACCESS_TYPE"].ToString());
453 }
454
455 AddAvailability(dStart, dEnd, nApptTypeID, nSlots, sResourceList, sAccessRuleList, sNote);
456 }
457 }
458 return true;
459
460 /* NOT USED
461 //Refresh Type Schedule
462 string sResourceName = "";
463 DataTable rTypeSchedule = new DataTable(); ;
464 for (int j = 0; j < m_sResourcesArray.Count; j++)
465 {
466 sResourceName = m_sResourcesArray[j].ToString();
467 DataTable dtTemp = CGSchedLib.CreateAssignedTypeSchedule(m_DocManager, sResourceName, this.m_dStartDate, this.m_dEndDate, m_ScheduleType);
468
469 if (j == 0)
470 {
471 rTypeSchedule = dtTemp;
472 }
473 else
474 {
475 rTypeSchedule = CGSchedLib.UnionBlocks(rTypeSchedule, dtTemp);
476 }
477 }
478
479 DateTime dStart;
480 DateTime dEnd;
481 DateTime dTypeStart;
482 DateTime dTypeEnd;
483 int nSlots;
484 Rectangle crRectA = new Rectangle(0, 0, 1, 0);
485 Rectangle crRectB = new Rectangle(0, 0, 1, 0);
486 bool bIsect;
487 string sResourceList;
488 string sAccessRuleList;
489
490 //smh: moved clear availabilities down here.
491 //smh: Temporary solution to make sure that people don't touch the availability table at the same time!!!
492 //NOTE: This lock makes sure that availabilities aren't queried for slots when the array is an intermediate
493 //state. The other place that has this lock is SlotsAvailable function.
494 lock (this.m_pAvArray)
495 {
496 m_pAvArray.Clear();
497
498 foreach (DataRow rTemp in rAvailabilitySchedule.Rows)
499 {
500 //get StartTime, EndTime and Slots
501 dStart = (DateTime)rTemp["START_TIME"];
502 dEnd = (DateTime)rTemp["END_TIME"];
503
504 //TODO: Fix this slots datatype problem
505 string sSlots = rTemp["SLOTS"].ToString();
506 nSlots = Convert.ToInt16(sSlots);
507
508 sResourceList = rTemp["RESOURCE"].ToString();
509 sAccessRuleList = rTemp["ACCESS_TYPE"].ToString();
510
511 string sNote = rTemp["NOTE"].ToString();
512
513 if ((nSlots < -1000) || (sAccessRuleList == ""))
514 {
515 nApptTypeID = 0;
516 }
517 else
518 {
519 foreach (DataRow rType in rTypeSchedule.Rows)
520 {
521
522 dTypeStart = (DateTime)rType["StartTime"];
523 dTypeEnd = (DateTime)rType["EndTime"];
524 //if start & end times overlap, then
525 string sTypeResource = rType["ResourceName"].ToString();
526 if ((dTypeStart.DayOfYear == dStart.DayOfYear) && (sResourceList == sTypeResource))
527 {
528 crRectA.Y = GetTotalMinutes(dStart);
529 crRectA.Height = GetTotalMinutes(dEnd) - crRectA.Top;
530 crRectB.Y = GetTotalMinutes(dTypeStart);
531 crRectB.Height = GetTotalMinutes(dTypeEnd) - crRectB.Top;
532 bIsect = crRectA.IntersectsWith(crRectB);
533 if (bIsect == true)
534 {
535 //TODO: This code:
536 // nApptTypeID = (int) rType["AppointmentTypeID"];
537 //Causes this exception:
538 //Unhandled Exception: System.InvalidCastException: Specified cast is not valid.
539 string sTemp = rType["AppointmentTypeID"].ToString();
540 nApptTypeID = Convert.ToInt16(sTemp);
541 break;
542 }
543 }
544 }//end foreach datarow rType
545 }
546
547
548 //AddAvailability(dStart, dEnd, nApptTypeID, nSlots, sResourceList, sAccessRuleList, sNote);
549 }//end foreach datarow rTemp
550 }//end lock
551 return true;
552 */
553 }
554 catch (Exception ex)
555 {
556 Debug.Write("CGDocument.RefreshAvailabilitySchedule error: " + ex.Message + "\n");
557 return false;
558 }
559 }
560
561 private int GetTotalMinutes(DateTime dDate)
562 {
563 return ((dDate.Hour * 60) + dDate.Minute);
564 }
565
566 /// <summary>
567 /// Adds Availability to Availability Array held by document
568 /// </summary>
569 /// <param name="StartTime">Self-Explan</param>
570 /// <param name="EndTime">Self-Explan</param>
571 /// <param name="nType"></param>
572 /// <param name="nSlots"></param>
573 /// <param name="UpdateView"></param>
574 /// <param name="sResourceList"></param>
575 /// <param name="sAccessRuleList"></param>
576 /// <param name="sNote"></param>
577 /// <returns></returns>
578 public int AddAvailability(DateTime StartTime, DateTime EndTime, int nType, int nSlots, string sResourceList, string sAccessRuleList, string sNote)
579 {
580 //adds it to the object array
581 //Returns the index in the array
582
583 CGAvailability pNewAv = new CGAvailability();
584 pNewAv.Create(StartTime, EndTime, nType, nSlots, sResourceList, sAccessRuleList);
585
586 pNewAv.Note = sNote;
587
588 //Look up the color and type name using the AppointmentTypes datatable
589 DataTable dtType = this.m_DocManager.GlobalDataSet.Tables["AccessTypes"];
590 DataRow dRow = dtType.Rows.Find(nType.ToString());
591 if (dRow != null)
592 {
593 string sColor = dRow["DISPLAY_COLOR"].ToString();
594 pNewAv.DisplayColor = sColor;
595 string sTemp = dRow["RED"].ToString();
596 sTemp = (sTemp == "") ? "0" : sTemp;
597 int nRed = Convert.ToInt16(sTemp);
598 pNewAv.Red = nRed;
599 sTemp = dRow["GREEN"].ToString();
600 sTemp = (sTemp == "") ? "0" : sTemp;
601 int nGreen = Convert.ToInt16(sTemp);
602 pNewAv.Green = nGreen;
603 sTemp = dRow["BLUE"].ToString();
604 sTemp = (sTemp == "") ? "0" : sTemp;
605 int nBlue = Convert.ToInt16(sTemp);
606 pNewAv.Blue = nBlue;
607
608 string sName = dRow["ACCESS_TYPE_NAME"].ToString();
609 pNewAv.AccessTypeName = sName;
610 }
611
612 int nIndex = 0;
613 nIndex = m_pAvArray.Add(pNewAv);
614
615 return nIndex;
616 }
617
618
619 public void AddResource(string sResource)
620 {
621 //TODO: Test that resource is not currently in list, that it IS a resource, etc
622 this.m_sResourcesArray.Add(sResource);
623 }
624
625 /// <summary>
626 /// Gets number of slots left in a certain selection on the grid. Used in Multiple Places.
627 /// </summary>
628 /// <param name="dSelStart">Selection Start Date</param>
629 /// <param name="dSelEnd">Selection End Date</param>
630 /// <param name="sResource">Resource Name</param>
631 /// <param name="sAccessType">Out: Name of Access Type</param>
632 /// <param name="sAvailabilityMessage">Out: Access Note</param>
633 /// <returns>Number of slots</returns>
634 public int SlotsAvailable(DateTime dSelStart, DateTime dSelEnd, string sResource, int viewTimeScale, out CGAvailability resultantAV)
635 {
636
637 resultantAV = null;
638
639 double slotsAvailable = 0; //defalut return value
640
641 double effectiveSlotsAvailable = 0; //Slots available based on the time scale.
642
643
644 //NOTE: What's this lock? This lock makes sure that nobody is editing the availability array
645 //when we are looking at it. Since the availability array could potentially be updated on
646 //a different thread, we are can be potentially left stuck with an empty array.
647 //
648 //The other place that uses this lock is the RefershAvailabilitySchedule method
649 //
650 //This is a temporary fix until I figure out how to divorce the availbilities here from those drawn
651 //on the calendar. Appointments are cloned b/c they are in an object that supports that; and b/c I
652 //don't need to suddenly query them at runtime like I do with Availabilities.
653
654 //Let's Try Linq
655 lock (this.m_pAvArray)
656 {
657 //This foreach loop looks for an availability that overlaps where the user clicked.
658 //Availabilites cannot overlap each other (enforced at the DB level)
659 //If selection hits multiple blocks, get the block with the most slots (reflected by the sorting here)
660 List<CGAvailability> lstAV = (from avail in this.m_pAvArray.Cast<CGAvailability>()
661 where (sResource == avail.ResourceList && CalendarGrid.TimesOverlap(dSelStart, dSelEnd, avail.StartTime, avail.EndTime))
662 select avail).ToList();
663
664 //if we don't have any availabilities, then return with zero slots.
665 if (lstAV.Count == 0) return 0;
666
667 CGAvailability pAV;
668
669 //if there is just one, that's it.
670 if (lstAV.Count == 1) pAV = lstAV.First();
671 //otherwise...
672 else
673 {
674 //if availabilities are contigous to each other, need to join them together.
675
676 //First, are they the same?
677 string firsttype = lstAV.First().AccessTypeName;
678 bool bAllSameType = lstAV.All(av => av.AccessTypeName == firsttype);
679
680 //Second are they ALL contigous?
681 DateTime lastEndTime = DateTime.Today; //bogus value to please compiler who wants it assigned.
682 int index = 0;
683
684 bool bContigous = lstAV.OrderBy(av => av.StartTime)
685 .All(av =>
686 {
687 index++;
688 if (index == 1)
689 {
690 lastEndTime = av.EndTime;
691 return true;
692 }
693 if (av.StartTime == lastEndTime)
694 {
695 lastEndTime = av.EndTime;
696 return true;
697 }
698
699 return false;
700 });
701
702
703
704 if (bContigous && bAllSameType)
705 {
706 var enumAVOrdered = lstAV.OrderBy(av => av.StartTime);
707
708 pAV = new CGAvailability
709 {
710 StartTime = enumAVOrdered.First().StartTime,
711 EndTime = enumAVOrdered.Last().EndTime,
712 Slots = enumAVOrdered.Sum(av => av.Slots),
713 AccessTypeName = enumAVOrdered.First().AccessTypeName,
714 Note = enumAVOrdered.First().Note
715 };
716 }
717 else
718 {
719 pAV = lstAV.OrderByDescending(av => av.Slots).First();
720 }
721 }
722
723 resultantAV = pAV; // out var
724
725 slotsAvailable = pAV.Slots;
726
727 //Subtract total slots current appointments take up.
728 slotsAvailable -= (from appt in this.Appointments.AppointmentTable.Values.Cast<CGAppointment>()
729 //If the resource is the same and the user selection overlaps, then...
730 where (sResource == appt.Resource && CalendarGrid.TimesOverlap(pAV.StartTime, pAV.EndTime, appt.StartTime, appt.EndTime))
731 // if appt starttime is before avail start time, only count against the avail starting from the availability start time
732 let startTimeToCountAgainstBlock = appt.StartTime < pAV.StartTime ? pAV.StartTime : appt.StartTime
733 // if appt endtime is after the avail ends, only count against the avail up to where the avail ends
734 let endTimeToCountAgainstBlock = appt.EndTime > pAV.EndTime ? pAV.EndTime : appt.EndTime
735 // theoretical minutes per slot for the availability
736 let minPerSlot = (pAV.EndTime - pAV.StartTime).TotalMinutes / pAV.Slots
737 // how many minutes does this appointment take away from the slot
738 let minPerAppt = (endTimeToCountAgainstBlock - startTimeToCountAgainstBlock).TotalMinutes
739 // how many slots the appointment takes up using this availability's scale
740 let slotsConsumed = minPerAppt / minPerSlot
741 select slotsConsumed)
742 // add up SlotsConsumed to substract from slotsAvailable
743 .Sum();
744
745 //theoretical minutes per slot for the availability
746 double minPerSlot2 = (pAV.EndTime - pAV.StartTime).TotalMinutes / pAV.Slots;
747
748 //Convert it to the view's time scale.
749 effectiveSlotsAvailable = (minPerSlot2 / viewTimeScale) * slotsAvailable;
750
751 }
752
753 //round it down.
754 return (int)effectiveSlotsAvailable;
755
756 /* OLD ALGOTHRIM 2
757
758 lock (this.m_pAvArray)
759 {
760 //This foreach loop looks for an availability that overlaps where the user clicked.
761 //There can only be one, as availabilites cannot overlap each other (enforced at the DB level)
762 //Therefore, we loop, and once we find it, we break.
763 foreach (CGAvailability pAV in this.m_pAvArray)
764 {
765 //If the resource is the same and the user selection overlaps, then...
766 if (sResource == pAV.ResourceList && CalendarGrid.TimesOverlap(dSelStart, dSelEnd, pAV.StartTime, pAV.EndTime))
767 {
768 slotsAvailable = pAV.Slots; //variable now holds the total number of slots
769 sAccessType = pAV.AccessTypeName; //Access Name
770 sAvailabilityMessage = pAV.Note; //Access Block Note
771
772 //Here we substract each appointment weight in slots from slotsAvailable
773 foreach (DictionaryEntry apptDict in this.m_appointments.AppointmentTable)
774 {
775 CGAppointment appt = (CGAppointment)apptDict.Value;
776 //If the appointment is in the same resource and overlaps with this availablity
777 if (sResource == appt.Resource && CalendarGrid.TimesOverlap(pAV.StartTime, pAV.EndTime, appt.StartTime, appt.EndTime))
778 {
779 // if appt starttime is before avail start time, only count against the avail starting from the availability start time
780 DateTime startTimeToCountAgainstBlock = appt.StartTime < pAV.StartTime ? pAV.StartTime : appt.StartTime;
781 // if appt endtime is after the avail ends, only count against the avail up to where the avail ends
782 DateTime endTimeToCountAgainstBlock = appt.EndTime > pAV.EndTime ? pAV.EndTime : appt.EndTime;
783 // theoretical minutes per slot for the availability
784 double minPerSlot = (pAV.EndTime - pAV.StartTime).TotalMinutes/pAV.Slots;
785 // how many minutes does this appointment take away from the slot
786 double minPerAppt = (endTimeToCountAgainstBlock - startTimeToCountAgainstBlock).TotalMinutes;
787 // how many slots the appointment takes up using this availability's scale
788 double slotsConsumed = minPerAppt / minPerSlot;
789 // subscract that from the total slots for the availability
790 slotsAvailable -= slotsConsumed;
791 } //end if
792 //now go to the next appointment in foreach
793 }
794 // As I said above, we can match only one availability. Once we found it and substracted from it; we are done.
795 break;
796 }
797 }
798 // We return the integer portion of the variable for display to the user or for calculations.
799 // That means, if 2.11 slots are left, the user sees 2. If 2.66, still 2.
800 return (int)slotsAvailable;
801 }
802 */
803
804 /* ORIGINAL ALGORITHM
805 sAccessType = "";
806 sAvailabilityMessage = "";
807 DateTime dStart;
808 DateTime dEnd;
809 int nAvailableSlots = 999;
810 int nSlots = 0;
811 int i = 0;
812 CGAvailability pAv;
813 Rectangle crRectA = new Rectangle(0, 0, 1, 0);
814 Rectangle crRectB = new Rectangle(0, 0, 1, 0);
815 bool bIsect;
816 crRectB.Y = GetTotalMinutes(dSelStart);
817 crRectB.Height = GetTotalMinutes(dSelEnd) - crRectB.Y;
818
819 //NOTE: What's this lock? This lock makes sure that nobody is editing the availability array
820 //when we are looking at it. Since the availability array could potentially be updated on
821 //a different thread, we are can be potentially left stuck with an empty array.
822 //
823 //The other place that uses this lock is the RefershAvailabilitySchedule method
824 //
825 //This is a temporary fix until I figure out how to divorce the availbilities here from those drawn
826 //on the calendar. Appointments are cloned b/c they are in an object that supports that; and b/c I
827 //don't need to suddenly query them at runtime like I do with Availabilities.
828
829 lock (this.m_pAvArray)
830 {
831 //loop thru m_pAvArray
832 //Compare the start time and end time of eachblock
833 while (i < m_pAvArray.Count)
834 {
835 pAv = (CGAvailability)m_pAvArray[i];
836 dStart = pAv.StartTime;
837 dEnd = pAv.EndTime;
838 if ((sResource == pAv.ResourceList) &&
839 ((dSelStart.Date == dStart.Date) || (dSelStart.Date == dEnd.Date)))
840 {
841 crRectA.Y = (dStart.Date < dSelStart.Date) ? 0 : GetTotalMinutes(dStart);
842 crRectA.Height = (dEnd.Date > dSelEnd.Date) ? 1440 : GetTotalMinutes(dEnd);
843 crRectA.Height = crRectA.Height - crRectA.Y;
844 bIsect = crRectA.IntersectsWith(crRectB);
845 if (bIsect != false)
846 {
847 nSlots = pAv.Slots;
848 if (nSlots < 1)
849 {
850 nAvailableSlots = 0;
851 break;
852 }
853 if (nSlots < nAvailableSlots)
854 {
855 nAvailableSlots = nSlots;
856 sAccessType = pAv.AccessTypeName;
857 sAvailabilityMessage = pAv.Note;
858
859 }
860 }//end if
861 }//end if
862 i++;
863 }//end while
864 }//end lock
865
866 if (nAvailableSlots == 999)
867 {
868 nAvailableSlots = 0;
869 }
870 return nAvailableSlots;
871 */
872 }
873
874 /// <summary>
875 /// Given a selected date,
876 /// Calculates StartDay and End Day and returns them in output params.
877 /// nWeeks == number of Weeks to display
878 /// nColumnCount is number of days displayed per week.
879 /// If 5 columns, begin on Second Day of Week
880 /// If 7 Columns, begin on First Day of Week
881 /// (this is a change from the hardcoded behavior for US-based calendars)
882 ///
883 /// Returns TRUE if the document's data needs refreshing based on
884 /// this newly selected date.
885 /// </summary>
886 public bool WeekNeedsRefresh(int nWeeks, DateTime SelectedDate,
887 out DateTime WeekStartDay, out DateTime WeekEndDay)
888 {
889 DateTime OldStartDay = m_dStartDate;
890 DateTime OldEndDay = m_dEndDate;
891 // Week start based on thread locale
892 int nStartWeekDay = (int)System.Threading.Thread.CurrentThread.CurrentCulture.DateTimeFormat.FirstDayOfWeek;
893 // Current Day
894 int nWeekDay = (int)SelectedDate.DayOfWeek; //0 == Sunday
895
896 // this offset gets approrpriate day based on locale.
897 int nOff = (nStartWeekDay + 1) % 7;
898 TimeSpan ts = new TimeSpan(nWeekDay - nOff, 0, 0, 0); //d,h,m,s
899
900 // if ts is negative, we will jump to the next week in the logic.
901 // to show the correct week, add 7. Confusing, I know.
902 if (ts < new TimeSpan()) ts = ts + new TimeSpan(7, 0, 0, 0);
903
904 if (m_nColumnCount == 1) // if one column start and end on the same day.
905 {
906 ts = new TimeSpan(0, 23, 59, 59);
907 WeekStartDay = SelectedDate;
908 WeekEndDay = WeekStartDay + ts;
909 }
910 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.
911 {
912 // if picked day is start of week (Sunday in US), start in the next day since that's the first day of work week
913 // else, just substract the calculated time span to get to the start of week (first work day)
914 WeekStartDay = (nWeekDay == nStartWeekDay) ? SelectedDate + new TimeSpan(1, 0, 0, 0) : SelectedDate - ts;
915 // End day calculation
916 int nEnd = 3;
917 ts = new TimeSpan((7 * nWeeks) - nEnd, 23, 59, 59);
918 WeekEndDay = WeekStartDay + ts;
919 }
920 else // if 7 column start at the 1st day of this week and end in 6:23:59:59 days.
921 {
922 // 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.
923 WeekStartDay = (nWeekDay == nStartWeekDay) ? SelectedDate : SelectedDate - ts - new TimeSpan(1, 0, 0, 0);
924 // End day calculation
925 int nEnd = 1;
926 ts = new TimeSpan((7 * nWeeks) - nEnd, 23, 59, 59);
927 WeekEndDay = WeekStartDay + ts;
928 }
929
930 bool bRet = ((WeekStartDay.Date != OldStartDay.Date) || (WeekEndDay.Date != OldEndDay.Date));
931 return bRet;
932 }
933
934 /// <summary>
935 /// Calls RPMS to create appointment then
936 /// adds appointment to the m_appointments collection
937 /// Returns the IEN of the appointment in the RPMS BSDX APPOINTMENT file.
938 /// </summary>
939 /// <param name="rApptInfo"></param>
940 /// <returns></returns>
941 public int CreateAppointment(CGAppointment rApptInfo)
942 {
943 return CreateAppointment(rApptInfo, false);
944 }
945
946 /// <summary>
947 /// Use this overload to create a walkin appointment
948 /// </summary>
949 /// <param name="rApptInfo"></param>
950 /// <param name="bWalkin"></param>
951 /// <returns></returns>
952 public int CreateAppointment(CGAppointment rApptInfo, bool bWalkin)
953 {
954 // i18n code -- Use culture neutral FMDates
955 string sStart = FMDateTime.Create(rApptInfo.StartTime).FMDateString;
956 string sEnd = FMDateTime.Create(rApptInfo.EndTime).FMDateString;
957
958 TimeSpan sp = rApptInfo.EndTime - rApptInfo.StartTime;
959 string sLen = sp.TotalMinutes.ToString();
960 string sPatID = rApptInfo.PatientID.ToString();
961 string sNote = rApptInfo.Note;
962 string sResource = rApptInfo.Resource;
963
964 string sApptID;
965
966 if (bWalkin == true)
967 {
968 sApptID = "WALKIN";
969 }
970 else
971 {
972 sApptID = rApptInfo.AccessTypeID.ToString();
973 }
974
975 string sSql = "BSDX ADD NEW APPOINTMENT^" + sStart + "^" + sEnd + "^" + sPatID + "^" + sResource + "^" + sLen + "^" + sNote + "^" + sApptID;
976 System.Data.DataTable dtAppt = m_DocManager.RPMSDataTable(sSql, "NewAppointment");
977
978 Debug.Assert(dtAppt.Rows.Count == 1);
979 DataRow r = dtAppt.Rows[0];
980 int nApptID = Convert.ToInt32(r["APPOINTMENTID"]);
981 string sErrorID;
982 sErrorID = r["ERRORID"].ToString();
983 if ((sErrorID != "") || (nApptID < 1))
984 {
985 throw new Exception(sErrorID);
986 }
987
988 //next line is probably done elsewhere
989 rApptInfo.WalkIn = bWalkin ? true : false;
990 rApptInfo.AppointmentKey = nApptID;
991
992 this.m_appointments.AddAppointment(rApptInfo);
993
994 //Have make appointment from CGView responsible for requesting an update for the avialability.
995 //bool bRet = RefreshAvailabilitySchedule();
996
997 //Sam: don't think this is needed as it is called from CGView.
998 //Make CGView responsible for all drawing.
999 //UpdateAllViews();
1000
1001 return nApptID;
1002 }
1003
1004 public void EditAppointment(CGAppointment pAppt, string sNote)
1005 {
1006 try
1007 {
1008 int nApptID = pAppt.AppointmentKey;
1009 string sSql = "BSDX EDIT APPOINTMENT^" + nApptID.ToString() + "^" + sNote;
1010
1011 System.Data.DataTable dtAppt = m_DocManager.RPMSDataTable(sSql, "EditAppointment");
1012
1013 Debug.Assert(dtAppt.Rows.Count == 1);
1014 DataRow r = dtAppt.Rows[0];
1015 string sErrorID = r["ERRORID"].ToString();
1016 if (sErrorID == "-1")
1017 pAppt.Note = sNote;
1018
1019 if (this.m_appointments.AppointmentTable.ContainsKey(nApptID))
1020 {
1021 bool bRet = RefreshAvailabilitySchedule();
1022 UpdateAllViews();
1023 }
1024 }
1025 catch (Exception ex)
1026 {
1027 Debug.Write("CGDocument.EditAppointment Failed: " + ex.Message);
1028 }
1029 }
1030
1031 public void CheckInAppointment(int nApptID, DateTime dCheckIn)
1032 {
1033 string sCheckIn = FMDateTime.Create(dCheckIn).FMDateString;
1034
1035 string sSql = "BSDX CHECKIN APPOINTMENT^" + nApptID.ToString() + "^" + sCheckIn; // +"^";
1036 //sSql += ClinicStopIEN + "^" + ProviderIEN + "^" + PrintRouteSlip + "^";
1037 //sSql += PCCClinicIEN + "^" + PCCFormIEN + "^" + PCCOutGuide;
1038
1039 System.Data.DataTable dtAppt = m_DocManager.RPMSDataTable(sSql, "CheckInAppointment");
1040
1041 Debug.Assert(dtAppt.Rows.Count == 1);
1042 DataRow r = dtAppt.Rows[0];
1043 string sErrorID = r["ERRORID"].ToString();
1044 }
1045
1046 public string DeleteAppointment(int nApptID)
1047 {
1048 return DeleteAppointment(nApptID, true, 0, "");
1049 }
1050
1051 public string DeleteAppointment(int nApptID, bool bClinicCancelled, int nReason, string sRemarks)
1052 {
1053 //Returns "" if deletion successful
1054 //Otherwise, returns reason for failure
1055
1056 string sClinicCancelled = (bClinicCancelled == true) ? "C" : "PC";
1057 string sReasonID = nReason.ToString();
1058 string sSql = "BSDX CANCEL APPOINTMENT^" + nApptID.ToString();
1059 sSql += "^" + sClinicCancelled;
1060 sSql += "^" + sReasonID;
1061 sSql += "^" + sRemarks;
1062 DataTable dtAppt = m_DocManager.RPMSDataTable(sSql, "DeleteAppointment");
1063
1064 Debug.Assert(dtAppt.Rows.Count == 1);
1065 DataRow r = dtAppt.Rows[0];
1066 string sErrorID = r["ERRORID"].ToString();
1067 if (sErrorID != "")
1068 return sErrorID;
1069
1070 if (this.m_appointments.AppointmentTable.ContainsKey(nApptID))
1071 {
1072 this.m_appointments.RemoveAppointment(nApptID);
1073
1074 // View responsible for deciding to redraw the grid; not the document now.
1075 //bool bRet = RefreshAvailabilitySchedule();
1076 //UpdateAllViews();
1077 }
1078 return "";
1079 }
1080
1081 public string AutoRebook(CGAppointment a, int nSearchType, int nMinimumDays, int nMaximumDays, out CGAppointment aRebook)
1082 {
1083 //If successful Returns "1" and new start date and time returned in aRebook
1084 //Otherwise, returns error message
1085
1086 CGAppointment aCopy = new CGAppointment();
1087 aCopy.CreateAppointment(a.StartTime, a.EndTime, a.Note, 0, a.Resource);
1088 aCopy.PatientID = a.PatientID;
1089 aCopy.PatientName = a.PatientName;
1090 aCopy.HealthRecordNumber = a.HealthRecordNumber;
1091 aCopy.AccessTypeID = a.AccessTypeID;
1092 aRebook = aCopy;
1093
1094 //Determine Rebook access type
1095 //nSearchType = -1: use current, -2: use any non-zero type, >0 use this access type id
1096 int nAVType = 0;
1097
1098 switch (nSearchType)
1099 {
1100 case -1:
1101 nAVType = a.AccessTypeID;
1102 break;
1103 case -2:
1104 nAVType = 0;
1105 break;
1106 default:
1107 nAVType = nSearchType;
1108 break;
1109 }
1110
1111 int nSlots = 0;
1112 string sSlots = "";
1113 int nAccessTypeID; //To compare with nAVType
1114
1115 DateTime dResult = new DateTime(); //StartTime of access block to autorebook into
1116
1117 //Next two are empty, but needed to pass to CreateAvailabilitySchedule
1118 ArrayList alAccessTypes = new ArrayList();
1119 string sSearchInfo = "";
1120
1121 //Find the StartTime of first availability block of this type for this clinic
1122 //between nMinimumDays and nMaximumDays
1123
1124 string sAVStart = a.StartTime.AddDays(nMinimumDays).ToString("M/d/yyyy@H:mm");
1125
1126 //dtAVEnd is the last day to search
1127 DateTime dtAVEnd = a.StartTime.AddDays(nMinimumDays + nMaximumDays);
1128 string sAVEnd = dtAVEnd.ToString("M/d/yyyy@H:mm");
1129
1130 //Increment start day to search a week (or so) at a time
1131 //30 is a test increment. Need to test different values for performance
1132 int nIncrement = (nMaximumDays < 30) ? nMaximumDays : 30;
1133
1134 //nCount and nCountEnd are the 'moving' counters
1135 //that I add to start and end to get the bracket
1136 //At the beginning of the DO loop, nCount and nCountEnd are already set
1137 bool bFinished = false;
1138 bool bFound = false;
1139
1140 DateTime dStart = a.StartTime.AddDays(nMinimumDays);
1141 // v 1.3 i18n support - FM Date passed insated of American Date
1142 string sStart = FMDateTime.Create(dStart).DateOnly.FMDateString;
1143 DateTime dEnd = dStart.AddDays(nIncrement);
1144 do
1145 {
1146 string sSql = "BSDX REBOOK NEXT BLOCK^" + sStart + "^" + a.Resource + "^" + nAVType.ToString();
1147 DataTable dtNextBlock = this.DocManager.RPMSDataTable(sSql, "NextBlock");
1148 Debug.Assert(dtNextBlock.Rows.Count == 1);
1149 DataRow drNextBlockRow = dtNextBlock.Rows[0];
1150
1151 object oNextBlock;
1152 oNextBlock = drNextBlockRow["NEXTBLOCK"];
1153 if (oNextBlock.GetType() == typeof(System.DBNull))
1154 break;
1155 DateTime dNextBlock = (DateTime)drNextBlockRow["NEXTBLOCK"];
1156 if (dNextBlock > dtAVEnd)
1157 {
1158 break;
1159 }
1160
1161 dStart = dNextBlock;
1162 dEnd = dStart.AddDays(nIncrement);
1163 if (dEnd > dtAVEnd)
1164 dEnd = dtAVEnd;
1165
1166 DataTable dtResult = CGSchedLib.CreateAvailabilitySchedule(m_DocManager, this.Resources, dStart, dEnd, alAccessTypes, ScheduleType.Resource, sSearchInfo);
1167 //Loop thru dtResult looking for a slot having the required availability type.
1168 //If found, set bFinished = true;
1169 foreach (DataRow dr in dtResult.Rows)
1170 {
1171
1172 sSlots = dr["SLOTS"].ToString();
1173 if (sSlots == "")
1174 sSlots = "0";
1175 nSlots = Convert.ToInt16(sSlots);
1176 if (nSlots > 0)
1177 {
1178 nAccessTypeID = 0; //holds the access type id of the availability block
1179 if (dr["ACCESS_TYPE"].ToString() != "")
1180 nAccessTypeID = Convert.ToInt16(dr["ACCESS_TYPE"].ToString());
1181 if ((nSearchType == -2) && (nAccessTypeID > 0)) //Match on any non-zero type
1182 {
1183 bFinished = true;
1184 bFound = true;
1185 dResult = (DateTime)dr["START_TIME"];
1186 break;
1187 }
1188 if (nAccessTypeID == nAVType)
1189 {
1190 bFinished = true;
1191 bFound = true;
1192 dResult = (DateTime)dr["START_TIME"];
1193 break;
1194 }
1195 }
1196 }
1197 dStart = dEnd.AddDays(1);
1198 dEnd = dStart.AddDays(nIncrement);
1199 if (dEnd > dtAVEnd)
1200 dEnd = dtAVEnd;
1201 } while (bFinished == false);
1202
1203 if (bFound == true)
1204 {
1205 aCopy.StartTime = dResult;
1206 aCopy.EndTime = dResult.AddMinutes(a.Duration);
1207 //Create the appointment
1208 //Set the AUTOREBOOKED flag
1209 //and store the "AutoRebooked To DateTime"
1210 //in each autorebooked appointment
1211 this.CreateAppointment(aCopy);
1212 SetAutoRebook(a, dResult);
1213 return "1";
1214 }
1215 else
1216 {
1217 return "0";
1218 }
1219 }
1220
1221 private void SetAutoRebook(CGAppointment a, DateTime dtRebookedTo)
1222 {
1223 string sApptKey = a.AppointmentKey.ToString();
1224 //string sRebookedTo = dtRebookedTo.ToString("M/d/yyyy@HH:mm");
1225 // i18n
1226 string sRebookedTo = FMDateTime.Create(dtRebookedTo).FMDateString;
1227 string sSql = "BSDX REBOOK SET^" + sApptKey + "^" + sRebookedTo;
1228 System.Data.DataTable dtRebook = m_DocManager.RPMSDataTable(sSql, "AutoRebook");
1229
1230 }
1231
1232 public string AppointmentNoShow(CGAppointment a, bool bNoShow)
1233 {
1234 /*
1235 * BSDX NOSHOW RPC Returns 1 in ERRORID if successfully sets NOSHOW flag in BSDX APPOINTMENT and, if applicable, File 2
1236 *Otherwise, returns negative numbers for failure and errormessage in ERRORTXT
1237 *
1238 */
1239 int nApptID = a.AppointmentKey;
1240 string sTest = bNoShow.ToString();
1241 string sNoShow = (bNoShow == true) ? "1" : "0";
1242 string sSql = "BSDX NOSHOW^" + nApptID.ToString();
1243 sSql += "^";
1244 sSql += sNoShow;
1245
1246 DataTable dtAppt = m_DocManager.RPMSDataTable(sSql, "AppointmentNoShow");
1247
1248 Debug.Assert(dtAppt.Rows.Count == 1);
1249 DataRow r = dtAppt.Rows[0];
1250 string sErrorID = r["ERRORID"].ToString();
1251 if (sErrorID != "1")
1252 {
1253 return r["ERRORTEXT"].ToString();
1254 }
1255
1256 //All okay over here... then set appointment noshow or not no show...
1257 a.NoShow = bNoShow ? true : false;
1258
1259 //bool bRet = RefreshSchedule();
1260
1261 return sErrorID;
1262 }
1263
1264 public bool AppointmentUndoCheckin(CGAppointment a, out string msg)
1265 {
1266 msg = "";
1267 //zero good, anything else bad
1268 DataTable dt = CGDocumentManager.Current.DAL.RemoveCheckIn(a.AppointmentKey);
1269 if (dt.Rows[0][0].ToString() == "0")
1270 {
1271 a.CheckInTime = DateTime.MinValue; // remove check-in time.
1272 return true;
1273 }
1274
1275 else
1276 {
1277 msg = dt.Rows[0][0].ToString();
1278 return false;
1279 }
1280 }
1281
1282 //DON'T USE OBVIOUSLY. JUST FOR TESTING.
1283 public void ThrowException()
1284 {
1285 throw new Exception("Hello World. I am an Exception.");
1286 }
1287
1288 #endregion Methods
1289
1290 }//End class
1291}//End namespace
Note: See TracBrowser for help on using the repository browser.