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

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

Absorbed all changed from Radiology Support branch.
Patient and Provider classes now serializable to address new bug: Availablity slots cannot be saved b/c these classes are not serializable.

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