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

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

CalendarGrid: Many changes:

  1. Dragover handler to handle auto scrolling when dragging. Also highlights destination cell in dragging.
  2. Solution for the click-right click problem by better handling of right click issues.
  3. New method OnRButtonDown()
  4. Extra comments everywhere.
  5. Fix for single column being enabled when there are multiple resources. Columns property now calls this.SetColumnInfo() to rectify that problem.

CGDocument:

  1. EditAppoitment Used to send request a refresh from the DB and update the view itself, rather than letting the view handle that. That's now changed.

CGDocumentManager:

  1. MessageBox displayed during login splash now are shown BY the splash form.

CGView:

  1. Shortcuts and some display text updated.
  2. Splash screen when updating now removed.
  3. If print appointment slip checkbox is checked when EditAppointment is chosen, now it will print the routing slip.
  4. Tiny change in appointment structure generated during drag and drop (added Patient member, as it was causing a crash)

DApptSearch:

  1. Change of name of Appointment to Slot, for better user understanding.

DSplash:

  1. RemoteMessage box methods and associated delegates for mickey mousing the form from another thread.

Updated release exes and dlls

File size: 54.4 KB
RevLine 
[614]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;
[1097]9using System.Linq;
[1106]10using System.Collections.Generic;
[614]11
12namespace IndianHealthService.ClinicalScheduling
13{
[1071]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
[614]33
[1071]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 }
[614]52
53
[1071]54 #region Properties
[614]55
[1071]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 }
[614]66
[1071]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 }
[614]81
[1071]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 }
[614]92
[1071]93 public CGDocumentManager DocManager
94 {
95 get
96 {
97 return m_DocManager;
98 }
99 set
100 {
101 m_DocManager = value;
102 }
103 }
[614]104
[1071]105 /// <summary>
106 /// Contains the hashtable of appointments
107 /// </summary>
108 public CGAppointments Appointments
109 {
110 get
111 {
112 return m_appointments;
113 }
114 }
[614]115
[1071]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 }
[614]130
[1071]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 }
[614]141
[1071]142 public string DocName
143 {
144 get
145 {
146 return this.m_sDocName;
147 }
148 set
149 {
150 this.m_sDocName = value;
151 }
152 }
[614]153
[1071]154 #endregion
[614]155
[1071]156 #region Methods
[614]157
[1071]158 public void UpdateAllViews()
159 {
160 //iterate through all views and call update.
161 Hashtable h = CGDocumentManager.Current.Views;
[614]162
[1071]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 }
[614]172
[1071]173 }
174
175 /// <summary>
176 /// Update schedule based on info in RPMS
[1095]177 /// <returns>Clears and repopluates m_appointments</returns>
[1071]178 /// </summary>
[1110]179 private bool RefreshAppointments()
[1071]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
[821]202 //Nice to know that it gets set here!!!
[1071]203 m_dLastRefresh = DateTime.Now;
[614]204
[1095]205 //Clear appointments associated with this document
[1071]206 this.m_appointments.ClearAllAppointments();
[614]207
[850]208 // calls RPC to get appointments
[1071]209 rAppointmentSchedule = CGSchedLib.CreateAppointmentSchedule(m_DocManager, m_sResourcesArray, this.m_dStartDate, this.m_dEndDate);
210
[1095]211 // loop through datatable: Create CGAppointment and add to CGAppointments
[1071]212 foreach (DataRow r in rAppointmentSchedule.Rows)
213 {
[614]214
[1071]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();
[614]228
[1071]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;
[614]240
[1110]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
[1071]251 pAppointment = new CGAppointment();
[1110]252 pAppointment.Patient = pt;
[1071]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);
[614]265
[1071]266 }
[614]267
[1071]268 return true;
269 }
270 catch (Exception Ex)
271 {
272 Debug.Write("CGDocument.RefreshDaysSchedule error: " + Ex.Message + "\n");
273 return false;
274 }
275 }
[614]276
277
[1071]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 }
[614]283
[1073]284 //sam: This is a test that duplicates RefreshDocument, but without the UpdateAllViews,
285 // as that has to be done synchornously.
[1083]286 //XXX: Needs to be refactored obviously, but now for testing.
287 //XXX: Tested extensively enough. Less refactoring now. 2011-01-26
[1073]288 public void RefreshDocumentAsync()
289 {
[1083]290 Debug.WriteLine("IN REFERSH DOCUMENT ASYNC\n\n");
291
[1073]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 }
[1071]307
[1073]308 bRet = RefreshSchedule();
309 }
310
311
[1071]312 public void RefreshDocument()
313 {
[1070]314 bool bRet = false;
[1071]315 if (m_sResourcesArray.Count == 0)
316 return;
[1070]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 }
[614]329
[1071]330 bRet = RefreshSchedule();
[1073]331
[1071]332 this.UpdateAllViews();
333 }
[614]334
[1106]335 public void OnOpenDocument(DateTime dDate)
[1071]336 {
337 try
338 {
[1123]339 this.SelectedDate = dDate.Date;
340
[1071]341 m_ScheduleType = (m_sResourcesArray.Count == 1) ? ScheduleType.Resource : ScheduleType.Clinic;
342 bool bRet = false;
[1106]343
[1071]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 }
[614]356
[1071]357 bRet = RefreshSchedule();
[614]358
[1071]359 CGView view = null;
360 //If this document already has a view, the use it
[1070]361 //SAM: Why do this again???
[1124]362 //SAM: I think it's not needed; b/c
[1071]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 }
[614]377
[1071]378 //Otherwise, create new View
379 if (bReuseView == false)
380 {
381 view = new CGView();
[614]382
[1071]383 view.InitializeDocView(this,
384 this.DocManager,
385 m_dStartDate,
386 this.DocName);
[614]387
[1071]388 view.Show();
389 view.SyncTree();
[614]390
[1071]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 }
[614]403
[1065]404 /// <summary>
405 /// Refreshes Availablility and Schedules from RPMS.
406 /// </summary>
407 /// <returns>Success or Failure. Should be always Success.</returns>
[1128]408 public bool RefreshSchedule()
[1071]409 {
[1106]410 this.RefreshAvailabilitySchedule();
[1110]411 this.RefreshAppointments();
[1106]412 return true;
[1071]413 }
[614]414
[1071]415 private bool RefreshAvailabilitySchedule()
416 {
417 try
418 {
419 ArrayList saryApptTypes = new ArrayList();
[1095]420
[1071]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");
[614]424
[1095]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
[1071]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);
[1095]468
[1071]469 if (j == 0)
470 {
471 rTypeSchedule = dtTemp;
472 }
473 else
474 {
475 rTypeSchedule = CGSchedLib.UnionBlocks(rTypeSchedule, dtTemp);
476 }
477 }
[614]478
[1071]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;
[614]489
[1083]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)
[1071]495 {
[1083]496 m_pAvArray.Clear();
[614]497
[1083]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"];
[614]503
[1083]504 //TODO: Fix this slots datatype problem
505 string sSlots = rTemp["SLOTS"].ToString();
506 nSlots = Convert.ToInt16(sSlots);
[614]507
[1083]508 sResourceList = rTemp["RESOURCE"].ToString();
509 sAccessRuleList = rTemp["ACCESS_TYPE"].ToString();
[614]510
[1083]511 string sNote = rTemp["NOTE"].ToString();
512
513 if ((nSlots < -1000) || (sAccessRuleList == ""))
[1071]514 {
[1083]515 nApptTypeID = 0;
516 }
517 else
518 {
519 foreach (DataRow rType in rTypeSchedule.Rows)
520 {
[614]521
[1083]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))
[1071]527 {
[1083]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 }
[1071]543 }
[1083]544 }//end foreach datarow rType
545 }
[614]546
547
[1095]548 //AddAvailability(dStart, dEnd, nApptTypeID, nSlots, sResourceList, sAccessRuleList, sNote);
[1083]549 }//end foreach datarow rTemp
550 }//end lock
[1071]551 return true;
[1095]552 */
[1071]553 }
554 catch (Exception ex)
555 {
556 Debug.Write("CGDocument.RefreshAvailabilitySchedule error: " + ex.Message + "\n");
557 return false;
558 }
559 }
[614]560
[1071]561 private int GetTotalMinutes(DateTime dDate)
562 {
563 return ((dDate.Hour * 60) + dDate.Minute);
564 }
[614]565
[1083]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>
[1095]578 public int AddAvailability(DateTime StartTime, DateTime EndTime, int nType, int nSlots, string sResourceList, string sAccessRuleList, string sNote)
[1071]579 {
580 //adds it to the object array
581 //Returns the index in the array
[614]582
[1071]583 CGAvailability pNewAv = new CGAvailability();
584 pNewAv.Create(StartTime, EndTime, nType, nSlots, sResourceList, sAccessRuleList);
[614]585
[1071]586 pNewAv.Note = sNote;
[614]587
[1071]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;
[614]607
[1071]608 string sName = dRow["ACCESS_TYPE_NAME"].ToString();
609 pNewAv.AccessTypeName = sName;
610 }
[614]611
[1071]612 int nIndex = 0;
613 nIndex = m_pAvArray.Add(pNewAv);
[1095]614
[1071]615 return nIndex;
616 }
[614]617
[1071]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 }
[614]624
[1097]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>
[1106]634 public int SlotsAvailable(DateTime dSelStart, DateTime dSelEnd, string sResource, int viewTimeScale, out CGAvailability resultantAV)
[1071]635 {
[1097]636
[1106]637 resultantAV = null;
[1097]638
639 double slotsAvailable = 0; //defalut return value
640
[1106]641 double effectiveSlotsAvailable = 0; //Slots available based on the time scale.
642
643
[1097]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.
[1106]658 //Availabilites cannot overlap each other (enforced at the DB level)
[1097]659 //If selection hits multiple blocks, get the block with the most slots (reflected by the sorting here)
[1106]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();
[1097]663
[1106]664 //if we don't have any availabilities, then return with zero slots.
665 if (lstAV.Count == 0) return 0;
666
667 CGAvailability pAV;
[1097]668
[1106]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.
[1097]675
[1106]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
[1097]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...
[1106]730 where (sResource == appt.Resource && CalendarGrid.TimesOverlap(pAV.StartTime, pAV.EndTime, appt.StartTime, appt.EndTime))
[1097]731 // if appt starttime is before avail start time, only count against the avail starting from the availability start time
[1106]732 let startTimeToCountAgainstBlock = appt.StartTime < pAV.StartTime ? pAV.StartTime : appt.StartTime
[1097]733 // if appt endtime is after the avail ends, only count against the avail up to where the avail ends
[1106]734 let endTimeToCountAgainstBlock = appt.EndTime > pAV.EndTime ? pAV.EndTime : appt.EndTime
[1097]735 // theoretical minutes per slot for the availability
[1106]736 let minPerSlot = (pAV.EndTime - pAV.StartTime).TotalMinutes / pAV.Slots
[1097]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();
[1106]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
[1097]751 }
[1106]752
753 //round it down.
754 return (int)effectiveSlotsAvailable;
[1097]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
[1071]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;
[614]818
[1083]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)
[1071]830 {
[1083]831 //loop thru m_pAvArray
832 //Compare the start time and end time of eachblock
833 while (i < m_pAvArray.Count)
[1071]834 {
[1083]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)))
[1071]840 {
[1083]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)
[1071]846 {
[1083]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;
[614]858
[1083]859 }
860 }//end if
861 }//end if
862 i++;
863 }//end while
864 }//end lock
865
[1071]866 if (nAvailableSlots == 999)
867 {
868 nAvailableSlots = 0;
869 }
870 return nAvailableSlots;
[1097]871 */
[1071]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.
[886]879 /// If 5 columns, begin on Second Day of Week
[1071]880 /// If 7 Columns, begin on First Day of Week
[886]881 /// (this is a change from the hardcoded behavior for US-based calendars)
[1071]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;
[908]891 // Week start based on thread locale
892 int nStartWeekDay = (int)System.Threading.Thread.CurrentThread.CurrentCulture.DateTimeFormat.FirstDayOfWeek;
[913]893 // Current Day
[1071]894 int nWeekDay = (int)SelectedDate.DayOfWeek; //0 == Sunday
[614]895
[1071]896 // this offset gets approrpriate day based on locale.
[886]897 int nOff = (nStartWeekDay + 1) % 7;
[1071]898 TimeSpan ts = new TimeSpan(nWeekDay - nOff, 0, 0, 0); //d,h,m,s
[614]899
[913]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.
[1071]902 if (ts < new TimeSpan()) ts = ts + new TimeSpan(7, 0, 0, 0);
[913]903
[1071]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;
[913]908 WeekEndDay = WeekStartDay + ts;
[1071]909 }
[913]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)
[1071]914 WeekStartDay = (nWeekDay == nStartWeekDay) ? SelectedDate + new TimeSpan(1, 0, 0, 0) : SelectedDate - ts;
[913]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.
[1071]923 WeekStartDay = (nWeekDay == nStartWeekDay) ? SelectedDate : SelectedDate - ts - new TimeSpan(1, 0, 0, 0);
[913]924 // End day calculation
925 int nEnd = 1;
926 ts = new TimeSpan((7 * nWeeks) - nEnd, 23, 59, 59);
927 WeekEndDay = WeekStartDay + ts;
928 }
929
[1071]930 bool bRet = ((WeekStartDay.Date != OldStartDay.Date) || (WeekEndDay.Date != OldEndDay.Date));
931 return bRet;
932 }
[614]933
[1071]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 }
[614]945
[1071]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 {
[1124]954 // i18n code -- Use culture neutral FMDates
955 string sStart = FMDateTime.Create(rApptInfo.StartTime).FMDateString;
956 string sEnd = FMDateTime.Create(rApptInfo.EndTime).FMDateString;
[864]957
[1124]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;
[1071]963
[1124]964 string sApptID;
[864]965
[1071]966 if (bWalkin == true)
967 {
968 sApptID = "WALKIN";
969 }
970 else
971 {
972 sApptID = rApptInfo.AccessTypeID.ToString();
973 }
[614]974
[1071]975 string sSql = "BSDX ADD NEW APPOINTMENT^" + sStart + "^" + sEnd + "^" + sPatID + "^" + sResource + "^" + sLen + "^" + sNote + "^" + sApptID;
976 System.Data.DataTable dtAppt = m_DocManager.RPMSDataTable(sSql, "NewAppointment");
[614]977
[1071]978 Debug.Assert(dtAppt.Rows.Count == 1);
979 DataRow r = dtAppt.Rows[0];
[1124]980 int nApptID = Convert.ToInt32(r["APPOINTMENTID"]);
[1071]981 string sErrorID;
982 sErrorID = r["ERRORID"].ToString();
983 if ((sErrorID != "") || (nApptID < 1))
[1084]984 {
[1071]985 throw new Exception(sErrorID);
[1084]986 }
[1124]987
988 //next line is probably done elsewhere
989 rApptInfo.WalkIn = bWalkin ? true : false;
[1112]990 rApptInfo.AppointmentKey = nApptID;
991
[1124]992 this.m_appointments.AddAppointment(rApptInfo);
993
[1083]994 //Have make appointment from CGView responsible for requesting an update for the avialability.
995 //bool bRet = RefreshAvailabilitySchedule();
[614]996
[1083]997 //Sam: don't think this is needed as it is called from CGView.
998 //Make CGView responsible for all drawing.
999 //UpdateAllViews();
[614]1000
[1071]1001 return nApptID;
1002 }
[614]1003
[1071]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;
[614]1010
[1071]1011 System.Data.DataTable dtAppt = m_DocManager.RPMSDataTable(sSql, "EditAppointment");
[614]1012
[1071]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 catch (Exception ex)
1020 {
1021 Debug.Write("CGDocument.EditAppointment Failed: " + ex.Message);
1022 }
1023 }
[614]1024
[1071]1025 public void CheckInAppointment(int nApptID, DateTime dCheckIn)
1026 {
1027 string sCheckIn = FMDateTime.Create(dCheckIn).FMDateString;
1028
[1062]1029 string sSql = "BSDX CHECKIN APPOINTMENT^" + nApptID.ToString() + "^" + sCheckIn; // +"^";
[1071]1030 //sSql += ClinicStopIEN + "^" + ProviderIEN + "^" + PrintRouteSlip + "^";
1031 //sSql += PCCClinicIEN + "^" + PCCFormIEN + "^" + PCCOutGuide;
[614]1032
[1071]1033 System.Data.DataTable dtAppt = m_DocManager.RPMSDataTable(sSql, "CheckInAppointment");
[614]1034
[1071]1035 Debug.Assert(dtAppt.Rows.Count == 1);
1036 DataRow r = dtAppt.Rows[0];
1037 string sErrorID = r["ERRORID"].ToString();
1038 }
[614]1039
[1071]1040 public string DeleteAppointment(int nApptID)
1041 {
1042 return DeleteAppointment(nApptID, true, 0, "");
1043 }
[614]1044
[1071]1045 public string DeleteAppointment(int nApptID, bool bClinicCancelled, int nReason, string sRemarks)
1046 {
1047 //Returns "" if deletion successful
1048 //Otherwise, returns reason for failure
[614]1049
[1071]1050 string sClinicCancelled = (bClinicCancelled == true) ? "C" : "PC";
1051 string sReasonID = nReason.ToString();
1052 string sSql = "BSDX CANCEL APPOINTMENT^" + nApptID.ToString();
1053 sSql += "^" + sClinicCancelled;
1054 sSql += "^" + sReasonID;
1055 sSql += "^" + sRemarks;
1056 DataTable dtAppt = m_DocManager.RPMSDataTable(sSql, "DeleteAppointment");
[614]1057
[1071]1058 Debug.Assert(dtAppt.Rows.Count == 1);
1059 DataRow r = dtAppt.Rows[0];
1060 string sErrorID = r["ERRORID"].ToString();
1061 if (sErrorID != "")
1062 return sErrorID;
[614]1063
[1071]1064 if (this.m_appointments.AppointmentTable.ContainsKey(nApptID))
1065 {
1066 this.m_appointments.RemoveAppointment(nApptID);
[1084]1067
1068 // View responsible for deciding to redraw the grid; not the document now.
1069 //bool bRet = RefreshAvailabilitySchedule();
1070 //UpdateAllViews();
[1071]1071 }
1072 return "";
1073 }
[614]1074
[1071]1075 public string AutoRebook(CGAppointment a, int nSearchType, int nMinimumDays, int nMaximumDays, out CGAppointment aRebook)
1076 {
1077 //If successful Returns "1" and new start date and time returned in aRebook
1078 //Otherwise, returns error message
[614]1079
[1071]1080 CGAppointment aCopy = new CGAppointment();
1081 aCopy.CreateAppointment(a.StartTime, a.EndTime, a.Note, 0, a.Resource);
1082 aCopy.PatientID = a.PatientID;
1083 aCopy.PatientName = a.PatientName;
1084 aCopy.HealthRecordNumber = a.HealthRecordNumber;
1085 aCopy.AccessTypeID = a.AccessTypeID;
1086 aRebook = aCopy;
[614]1087
[1071]1088 //Determine Rebook access type
1089 //nSearchType = -1: use current, -2: use any non-zero type, >0 use this access type id
1090 int nAVType = 0;
[614]1091
[1071]1092 switch (nSearchType)
1093 {
1094 case -1:
1095 nAVType = a.AccessTypeID;
1096 break;
1097 case -2:
1098 nAVType = 0;
1099 break;
1100 default:
1101 nAVType = nSearchType;
1102 break;
1103 }
[614]1104
[1071]1105 int nSlots = 0;
1106 string sSlots = "";
1107 int nAccessTypeID; //To compare with nAVType
[614]1108
[1071]1109 DateTime dResult = new DateTime(); //StartTime of access block to autorebook into
[614]1110
[1071]1111 //Next two are empty, but needed to pass to CreateAvailabilitySchedule
1112 ArrayList alAccessTypes = new ArrayList();
1113 string sSearchInfo = "";
[614]1114
[1071]1115 //Find the StartTime of first availability block of this type for this clinic
1116 //between nMinimumDays and nMaximumDays
[614]1117
[1071]1118 string sAVStart = a.StartTime.AddDays(nMinimumDays).ToString("M/d/yyyy@H:mm");
[614]1119
[1071]1120 //dtAVEnd is the last day to search
1121 DateTime dtAVEnd = a.StartTime.AddDays(nMinimumDays + nMaximumDays);
1122 string sAVEnd = dtAVEnd.ToString("M/d/yyyy@H:mm");
1123
1124 //Increment start day to search a week (or so) at a time
1125 //30 is a test increment. Need to test different values for performance
1126 int nIncrement = (nMaximumDays < 30) ? nMaximumDays : 30;
1127
1128 //nCount and nCountEnd are the 'moving' counters
1129 //that I add to start and end to get the bracket
1130 //At the beginning of the DO loop, nCount and nCountEnd are already set
1131 bool bFinished = false;
1132 bool bFound = false;
1133
1134 DateTime dStart = a.StartTime.AddDays(nMinimumDays);
[864]1135 // v 1.3 i18n support - FM Date passed insated of American Date
1136 string sStart = FMDateTime.Create(dStart).DateOnly.FMDateString;
[1071]1137 DateTime dEnd = dStart.AddDays(nIncrement);
1138 do
1139 {
1140 string sSql = "BSDX REBOOK NEXT BLOCK^" + sStart + "^" + a.Resource + "^" + nAVType.ToString();
1141 DataTable dtNextBlock = this.DocManager.RPMSDataTable(sSql, "NextBlock");
1142 Debug.Assert(dtNextBlock.Rows.Count == 1);
1143 DataRow drNextBlockRow = dtNextBlock.Rows[0];
[614]1144
[1071]1145 object oNextBlock;
1146 oNextBlock = drNextBlockRow["NEXTBLOCK"];
1147 if (oNextBlock.GetType() == typeof(System.DBNull))
1148 break;
1149 DateTime dNextBlock = (DateTime)drNextBlockRow["NEXTBLOCK"];
1150 if (dNextBlock > dtAVEnd)
1151 {
1152 break;
1153 }
[614]1154
[1071]1155 dStart = dNextBlock;
1156 dEnd = dStart.AddDays(nIncrement);
1157 if (dEnd > dtAVEnd)
1158 dEnd = dtAVEnd;
[614]1159
[1071]1160 DataTable dtResult = CGSchedLib.CreateAvailabilitySchedule(m_DocManager, this.Resources, dStart, dEnd, alAccessTypes, ScheduleType.Resource, sSearchInfo);
1161 //Loop thru dtResult looking for a slot having the required availability type.
1162 //If found, set bFinished = true;
1163 foreach (DataRow dr in dtResult.Rows)
1164 {
[614]1165
[1071]1166 sSlots = dr["SLOTS"].ToString();
1167 if (sSlots == "")
1168 sSlots = "0";
1169 nSlots = Convert.ToInt16(sSlots);
1170 if (nSlots > 0)
1171 {
1172 nAccessTypeID = 0; //holds the access type id of the availability block
1173 if (dr["ACCESS_TYPE"].ToString() != "")
1174 nAccessTypeID = Convert.ToInt16(dr["ACCESS_TYPE"].ToString());
1175 if ((nSearchType == -2) && (nAccessTypeID > 0)) //Match on any non-zero type
1176 {
1177 bFinished = true;
1178 bFound = true;
1179 dResult = (DateTime)dr["START_TIME"];
1180 break;
1181 }
1182 if (nAccessTypeID == nAVType)
1183 {
1184 bFinished = true;
1185 bFound = true;
1186 dResult = (DateTime)dr["START_TIME"];
1187 break;
1188 }
1189 }
1190 }
1191 dStart = dEnd.AddDays(1);
1192 dEnd = dStart.AddDays(nIncrement);
1193 if (dEnd > dtAVEnd)
1194 dEnd = dtAVEnd;
1195 } while (bFinished == false);
[614]1196
[1071]1197 if (bFound == true)
1198 {
1199 aCopy.StartTime = dResult;
1200 aCopy.EndTime = dResult.AddMinutes(a.Duration);
1201 //Create the appointment
1202 //Set the AUTOREBOOKED flag
1203 //and store the "AutoRebooked To DateTime"
1204 //in each autorebooked appointment
1205 this.CreateAppointment(aCopy);
1206 SetAutoRebook(a, dResult);
1207 return "1";
1208 }
1209 else
1210 {
1211 return "0";
1212 }
1213 }
1214
1215 private void SetAutoRebook(CGAppointment a, DateTime dtRebookedTo)
1216 {
1217 string sApptKey = a.AppointmentKey.ToString();
1218 //string sRebookedTo = dtRebookedTo.ToString("M/d/yyyy@HH:mm");
[864]1219 // i18n
1220 string sRebookedTo = FMDateTime.Create(dtRebookedTo).FMDateString;
[1071]1221 string sSql = "BSDX REBOOK SET^" + sApptKey + "^" + sRebookedTo;
1222 System.Data.DataTable dtRebook = m_DocManager.RPMSDataTable(sSql, "AutoRebook");
[614]1223
[1071]1224 }
[614]1225
[1117]1226 public string AppointmentNoShow(CGAppointment a, bool bNoShow)
[1071]1227 {
1228 /*
1229 * BSDX NOSHOW RPC Returns 1 in ERRORID if successfully sets NOSHOW flag in BSDX APPOINTMENT and, if applicable, File 2
1230 *Otherwise, returns negative numbers for failure and errormessage in ERRORTXT
1231 *
1232 */
[1117]1233 int nApptID = a.AppointmentKey;
[1071]1234 string sTest = bNoShow.ToString();
1235 string sNoShow = (bNoShow == true) ? "1" : "0";
1236 string sSql = "BSDX NOSHOW^" + nApptID.ToString();
1237 sSql += "^";
1238 sSql += sNoShow;
[614]1239
[1071]1240 DataTable dtAppt = m_DocManager.RPMSDataTable(sSql, "AppointmentNoShow");
[614]1241
[1071]1242 Debug.Assert(dtAppt.Rows.Count == 1);
1243 DataRow r = dtAppt.Rows[0];
1244 string sErrorID = r["ERRORID"].ToString();
1245 if (sErrorID != "1")
1246 {
1247 return r["ERRORTEXT"].ToString();
1248 }
[614]1249
[1117]1250 //All okay over here... then set appointment noshow or not no show...
1251 a.NoShow = bNoShow ? true : false;
[614]1252
[1117]1253 //bool bRet = RefreshSchedule();
1254
[1071]1255 return sErrorID;
1256 }
1257
[1117]1258 public bool AppointmentUndoCheckin(CGAppointment a, out string msg)
1259 {
1260 msg = "";
1261 //zero good, anything else bad
1262 DataTable dt = CGDocumentManager.Current.DAL.RemoveCheckIn(a.AppointmentKey);
1263 if (dt.Rows[0][0].ToString() == "0")
1264 {
1265 a.CheckInTime = DateTime.MinValue; // remove check-in time.
1266 return true;
1267 }
1268
1269 else
1270 {
1271 msg = dt.Rows[0][0].ToString();
1272 return false;
1273 }
1274 }
1275
[1122]1276 //DON'T USE OBVIOUSLY. JUST FOR TESTING.
1277 public void ThrowException()
1278 {
1279 throw new Exception("Hello World. I am an Exception.");
1280 }
1281
[1071]1282 #endregion Methods
1283
1284 }//End class
[614]1285}//End namespace
Note: See TracBrowser for help on using the repository browser.