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

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

CalendarGrid:

  • Support for Autoscrolling corrected.
  • A little optimization: Grid is only drawn once now when starting, not twice (don't know why original code did that).

CGAppointment:

  • Added member Patient (new Class)

CGDocument:

  • OnOpenDocument now accepts input of DateTime to decide where to open document.
  • SlotsAvailable algorithm now includes code for scaling according to timescale and code to merge Blocks if they are adjacent.

CGDocumentManager:

  • Fix bug having to do with canceling log-in after first retry. BMX lib threw an exception which was not caught.

CGView: Many changes:

  • SlotsAvailable signature changed in CGDocument. All references to it had to be changed.
  • Opening a node in the tvSchedules by clicking on the plus sign did not select it. Code changes to make it select it.
  • UpdateStatusBar now uses a string builder; and shows a more comprehensive message on the availability in the Status Bar.
  • Focus issues on various controls.
  • Support for printing a slip after an appointment is made automatically has been added.

CustomPrinting:

  • now includes a method to print a single appointment slip

DAppointPage:

  • Checkbox to decide whether to print appt slip added.
  • New readonly property to get the appointment that has been made (of type CGAppointment).

DApptSearch:

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