source: Scheduling/branches/Radiology-Support/cs/bsdx0200GUISourceCode/CGDocument.cs@ 1154

Last change on this file since 1154 was 1140, checked in by Sam Habiel, 14 years ago

DRadExamsSelect: New form to let user select exam.
RadiologyExam: Class for a Radiology Exam
DAL: new DB communication methods: GetRadiologyExamsForPatientinHL and ScheduleRadiologyExam
CGView:

  1. New context menus for Radiology; context menu popup has logic for which menus to display;
  2. Helper method IsThisARadiologyResource used by ctxCalendarGrid_Popup to decide which menus to display
  3. Handler ctxCalGridMkRadAppt_Click to make the Radiology Appointment.

CGDocument:

  1. CreateAppointment now saves RadiologyExamIEN to the DB
  2. RefreshAppointments now gets RadiologyExamIEN from the DB

CGAppointment:

  1. Class completely refactored to use auto props rather than old style properties
  2. Added property RadiologyExamIEN

CalendarGrid: Class was wrongly using supposed private members of CGAppointment. Refactored to fix that as private members don't exist anymore.

Last but not least, new exe,dll

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