source: Scheduling/trunk/cs/bsdx0200GUISourceCode/CGAVDocument.cs@ 975

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

CGAVDocument contains changes for start day of grid based on weekday locale and colummns
CGAVView: Shortcut keys; correct updating when number of columns is changed in grid
CGDocument: changes for start day of grid. Modified algorithm.
DAccessTemplate: Takes any weekday now for applying a template, not just Monday. Then calculation of start day is done in CGAVView based on locale in the same algorithm that the rest of the GUI uses.
DAppointPage: Now says Mobile/Cell instead of Cell Phone.

File size: 16.5 KB
Line 
1using System;
2using System.Collections;
3using System.Data;
4//using System.Data.OleDb;
5using System.Diagnostics;
6using System.Drawing;
7using System.Windows.Forms;
8using IndianHealthService.BMXNet;
9
10namespace IndianHealthService.ClinicalScheduling
11{
12 /// <summary>
13 /// Contains array of availability blocks for a scheduling resource
14 /// </summary>
15 public class CGAVDocument : System.Object
16 {
17 public CGAVDocument()
18 {
19 m_AVBlocks = new CGAppointments();
20 m_sResourcesArray = new ArrayList();
21 }
22
23 #region Member Variables
24
25 public int m_nColumnCount; //todo: this should point to the view's member for column count
26 public int m_nTimeUnits;
27 public string m_sSecondary;
28 private string m_sDocName;
29 public ArrayList m_sResourcesArray;
30 public ScheduleType m_ScheduleType;
31 private DateTime m_dSelectedDate; //Holds the user's selection from the dtpicker
32 private DateTime m_dStartDate; //Beginning date of document data
33 private DateTime m_dEndDate; //Ending date of document data
34 public CGAppointments m_AVBlocks;
35 private CGDocumentManager m_DocManager;
36 private int m_nDocID; //Resource IEN in ^BSDXRES
37
38 #endregion
39
40 #region Properties
41
42 /// <summary>
43 /// Resource IEN in ^BSDXRES
44 /// </summary>
45 public int ResourceID
46 {
47 get
48 {
49 return m_nDocID;
50 }
51 set
52 {
53 m_nDocID = value;
54 }
55 }
56
57 /// <summary>
58 /// The list of Resource names
59 /// </summary>
60 public ArrayList Resources
61 {
62 get
63 {
64 return this.m_sResourcesArray;
65 }
66 set
67 {
68 this.m_sResourcesArray = value;
69 }
70 }
71
72 public CGDocumentManager DocManager
73 {
74 get
75 {
76 return m_DocManager;
77 }
78 set
79 {
80 m_DocManager = value;
81 }
82 }
83
84 /// <summary>
85 /// Contains the hashtable of Availability Blocks
86 /// </summary>
87 public CGAppointments AVBlocks
88 {
89 get
90 {
91 return m_AVBlocks;
92 }
93 set
94 {
95 m_AVBlocks = value;
96 }
97 }
98
99 /// <summary>
100 /// Holds the date selected by the user in CGView.dateTimePicker1
101 /// </summary>
102 public DateTime SelectedDate
103 {
104 get
105 {
106 return this.m_dSelectedDate;
107 }
108 set
109 {
110 this.m_dSelectedDate = value;
111 bool bRet = false;
112 if (m_ScheduleType == ScheduleType.Resource)
113 {
114 bRet = this.WeekNeedsRefresh(1, m_dSelectedDate, out this.m_dStartDate, out this.m_dEndDate);
115 }
116 else
117 {
118 this.m_dStartDate = m_dSelectedDate;
119 this.m_dEndDate = m_dSelectedDate;
120 this.m_dEndDate = this.m_dEndDate.AddHours(23);
121 this.m_dEndDate = this.m_dEndDate.AddMinutes(59);
122 this.m_dEndDate = this.m_dEndDate.AddSeconds(59);
123 }
124
125 bRet = this.RefreshDaysSchedule();
126 }
127 }
128
129 /// <summary>
130 /// Contains the beginning date of the appointment document
131 /// </summary>
132 public DateTime StartDate
133 {
134 get
135 {
136 return this.m_dStartDate;
137 }
138 }
139
140 public string DocName
141 {
142 get
143 {
144 return this.m_sDocName;
145 }
146 set
147 {
148 this.m_sDocName = value;
149 }
150 }
151
152 #endregion
153
154 #region Methods
155
156 public void ChangeAppointmentTime(CGAppointment pAppt, DateTime dNewStart, DateTime dNewEnd, string sResource)
157 {
158 try
159 {
160 DateTime dOldStart = pAppt.StartTime;
161 DateTime dOldEnd = pAppt.EndTime;
162 if ((dOldStart == dNewStart) && (dOldEnd == dNewEnd))
163 { //no change in time
164 return;
165 }
166
167 foreach (CGAppointment a in m_AVBlocks.AppointmentTable.Values)
168 {
169 DateTime sStart2 = a.StartTime;
170 DateTime sEnd2 = a.EndTime;
171 if ((a.AppointmentKey != pAppt.AppointmentKey) && (CGSchedLib.TimesOverlap(dNewStart, dNewEnd, a.StartTime, a.EndTime)))
172 {
173 MessageBox.Show("Access blocks may not overlap.","Clinical Scheduling", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
174 return;
175 }
176 }
177
178 this.DeleteAvailability(pAppt.AppointmentKey);
179 pAppt.StartTime = dNewStart;
180 pAppt.EndTime = dNewEnd;
181 pAppt.Resource = sResource;
182 this.CreateAppointment(pAppt);
183
184 }
185 catch(Exception e)
186 {
187 MessageBox.Show("CGDocument::ChangeAppointmentTime failed: " + e.Message);
188 return;
189 }
190 }
191
192 public void DeleteAvailability(int nApptID)
193 {
194 if (this.m_AVBlocks.AppointmentTable.ContainsKey(nApptID))
195 {
196 string sSql = "BSDX CANCEL AVAILABILITY^" + nApptID.ToString();
197 DataTable dtAppt =m_DocManager.RPMSDataTable(sSql, "DeleteAvailability");
198 int nErrorID;
199 Debug.Assert(dtAppt.Rows.Count == 1);
200 DataRow r = dtAppt.Rows[0];
201 nErrorID = Convert.ToInt32(r["ERRORID"]);
202 this.m_AVBlocks.RemoveAppointment(nApptID);
203 UpdateAllViews();
204 }
205 }
206
207 /// <summary>
208 /// Called by LoadTemplate to create Access Block
209 /// Returns the IEN of the availability block in the RPMS BSDX AVAILABILITY file.
210 /// </summary>
211 public int CreateAppointmentAuto(CGAppointment rApptInfo)
212 {
213 try
214 {
215 string sStart;
216 string sEnd;
217 string sResource;
218 string sNote;
219 string sTypeID;
220 string sSlots;
221
222 //sStart = rApptInfo.StartTime.ToString("M-d-yyyy@HH:mm");
223 //sEnd = rApptInfo.EndTime.ToString("M-d-yyyy@HH:mm");
224 // i18n support
225 sStart = FMDateTime.Create(rApptInfo.StartTime).FMDateString;
226 sEnd = FMDateTime.Create(rApptInfo.EndTime).FMDateString;
227 sNote = rApptInfo.Note;
228 sResource = rApptInfo.Resource;
229 sTypeID = rApptInfo.AccessTypeID.ToString();
230 sSlots = rApptInfo.Slots.ToString();
231
232 CGAppointment aCopy = new CGAppointment();
233 aCopy.CreateAppointment(rApptInfo.StartTime, rApptInfo.EndTime, sNote, 0, sResource);
234 aCopy.AccessTypeID = rApptInfo.AccessTypeID;
235 aCopy.Slots = rApptInfo.Slots;
236 aCopy.IsAccessBlock = true;
237
238 string sSql = "BSDX ADD NEW AVAILABILITY^" + sStart + "^" + sEnd + "^" + sTypeID + "^" + sResource + "^" + sSlots + "^" + sNote;
239 DataTable dtAppt = m_DocManager.RPMSDataTable(sSql, "NewAvailability");
240
241 int nApptID;
242 int nErrorID;
243
244 Debug.Assert(dtAppt.Rows.Count == 1);
245 DataRow r = dtAppt.Rows[0];
246 nApptID =Convert.ToInt32(r["AVAILABILITYID"]);
247 nErrorID = Convert.ToInt32(r["ERRORID"]);
248 if (nErrorID != -1)
249 {
250 throw new Exception("VistA Error");
251 }
252 Debug.Write("CreateAvailabilityAuto -- new AV block created\n");
253
254 UpdateAllViews();
255
256 aCopy.AppointmentKey = nApptID;
257 return nApptID;
258 }
259 catch (Exception ex)
260 {
261 Debug.Write("CGAVDocument.CreateAppointmentAuto Failed: " + ex.Message);
262 return -1;
263 }
264 }
265
266
267 public int CreateAppointment(CGAppointment rApptInfo)
268 {
269 try
270 {
271 string sStart;
272 string sEnd;
273 string sResource;
274 string sNote;
275 string sTypeID;
276 string sSlots;
277
278 //sStart = rApptInfo.StartTime.ToString("M-d-yyyy@HH:mm");
279 //sEnd = rApptInfo.EndTime.ToString("M-d-yyyy@HH:mm");
280 // i18n support
281 sStart = FMDateTime.Create(rApptInfo.StartTime).FMDateString;
282 sEnd = FMDateTime.Create(rApptInfo.EndTime).FMDateString;
283 sNote = rApptInfo.Note;
284 sResource = rApptInfo.Resource;
285 sTypeID = rApptInfo.AccessTypeID.ToString();
286 sSlots = rApptInfo.Slots.ToString();
287
288 CGAppointment aCopy = new CGAppointment();
289 aCopy.CreateAppointment(rApptInfo.StartTime, rApptInfo.EndTime, sNote, 0, sResource);
290 aCopy.AccessTypeID = rApptInfo.AccessTypeID;
291 aCopy.Slots = rApptInfo.Slots;
292 aCopy.IsAccessBlock = true;
293
294 aCopy.AccessTypeName = this.AccessNameFromID(aCopy.AccessTypeID);
295
296 foreach (CGAppointment a in this.m_AVBlocks.AppointmentTable.Values)
297 {
298 DateTime sStart2 = a.StartTime;
299 DateTime sEnd2 = a.EndTime;
300 if (CGSchedLib.TimesOverlap(aCopy.StartTime, aCopy.EndTime, a.StartTime, a.EndTime))
301 {
302 // throw new Exception("Access blocks may not overlap.");
303 MessageBox.Show("Access blocks may not overlap.","Clinical Scheduling", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
304 return -1;
305 }
306
307 }
308
309 string sSql = "BSDX ADD NEW AVAILABILITY^" + sStart + "^" + sEnd + "^" + sTypeID + "^" + sResource + "^" + sSlots + "^" + sNote;
310 DataTable dtAppt =m_DocManager.RPMSDataTable(sSql, "NewAvailability");
311
312 int nApptID;
313 int nErrorID;
314
315 Debug.Assert(dtAppt.Rows.Count == 1);
316 DataRow r = dtAppt.Rows[0];
317 nApptID =Convert.ToInt32(r["AVAILABILITYID"]);
318 nErrorID = Convert.ToInt32(r["ERRORID"]);
319 if (nErrorID != -1)
320 {
321 throw new Exception("VistA Error");
322 }
323 Debug.Write("CreateAvailability -- new AV block created\n");
324
325 aCopy.AppointmentKey = nApptID;
326
327 this.m_AVBlocks.AddAppointment(aCopy);
328
329 UpdateAllViews();
330
331 return nApptID;
332 }
333 catch (Exception ex)
334 {
335 Debug.Write("CGAVDocument.CreateAppointment Failed: " + ex.Message);
336 return -1;
337 }
338 }
339
340 private int GetTotalMinutes(DateTime dDate)
341 {
342 return ((dDate.Hour * 60) + dDate.Minute);
343 }
344
345 private string AccessNameFromID(int nAccessTypeID)
346 {
347 DataView dvTypes = new DataView(this.DocManager.GlobalDataSet.Tables["AccessTypes"]);
348 dvTypes.Sort = "BMXIEN ASC";
349 int nRow = dvTypes.Find(nAccessTypeID);
350 DataRowView drv = dvTypes[nRow];
351 string sAccessTypeName = drv["ACCESS_TYPE_NAME"].ToString();
352 return sAccessTypeName;
353 }
354
355
356 /// <summary>
357 /// Update availability block schedule based on info in RPMS
358 /// </summary>
359 public bool RefreshDaysSchedule()
360 {
361 DateTime dStart;
362 DateTime dEnd;
363 int nKeyID;
364 string sNote;
365 string sResource;
366 string sAccessType;
367 string sSlots;
368 CGAppointment pAppointment;
369 CGDocumentManager pApp = CGDocumentManager.Current;
370 DataTable rAppointmentSchedule;
371
372 this.m_AVBlocks.ClearAllAppointments();
373
374 ArrayList apptTypeIDs = new ArrayList();
375
376 rAppointmentSchedule = CGSchedLib.CreateAssignedSlotSchedule(m_DocManager, (string) m_sResourcesArray[0], this.m_dStartDate, this.m_dEndDate, apptTypeIDs,/* */ this.m_ScheduleType, "0");
377 CGSchedLib.OutputArray(rAppointmentSchedule, "rAppointmentSchedule");
378 foreach (DataRow r in rAppointmentSchedule.Rows)
379 {
380 nKeyID = Convert.ToInt32(r["AVAILABILITYID"].ToString());
381 if (nKeyID > 0)
382 {
383 dStart = (DateTime) r["START_TIME"];
384 dEnd = (DateTime) r["END_TIME"];
385 sNote = r["NOTE"].ToString();
386 sResource = r["RESOURCE"].ToString();
387 sAccessType = r["ACCESS_TYPE"].ToString();
388 sSlots = r["SLOTS"].ToString();
389
390 pAppointment = new CGAppointment();
391 pAppointment.CreateAppointment(dStart, dEnd, sNote, nKeyID, sResource);
392 pAppointment.AccessTypeID = Convert.ToInt16(sAccessType);
393 pAppointment.Slots = Convert.ToInt16(sSlots);
394 pAppointment.IsAccessBlock = true;
395 pAppointment.AccessTypeName = this.AccessNameFromID(pAppointment.AccessTypeID);
396
397 this.m_AVBlocks.AddAppointment(pAppointment);
398 }
399 }
400 return true;
401 }
402
403 /// <summary>
404 /// Given a selected date,
405 /// Calculates StartDay and End Day and returns them in output params.
406 /// nWeeks == number of Weeks to display
407 /// nColumnCount is number of days displayed per week.
408 /// If 5 columns, begin on Second Day of Week
409 /// If 7 Columns, begin on First Day of Week
410 /// (this is a change from the hardcoded behavior for US-based calendars)
411 ///
412 /// Returns TRUE if the document's data needs refreshing based on
413 /// this newly selected date.
414 /// </summary>
415 /// TODO: This is a duplicate of the method in CGDocument. We need to put them together.
416 public bool WeekNeedsRefresh(int nWeeks, DateTime SelectedDate,
417 out DateTime WeekStartDay, out DateTime WeekEndDay)
418 {
419 DateTime OldStartDay = m_dStartDate;
420 DateTime OldEndDay = m_dEndDate;
421 // Week start based on thread locale
422 int nStartWeekDay = (int)System.Threading.Thread.CurrentThread.CurrentCulture.DateTimeFormat.FirstDayOfWeek;
423 // Current Day
424 int nWeekDay = (int)SelectedDate.DayOfWeek; //0 == Sunday
425
426 // this offset gets approrpriate day based on locale.
427 int nOff = (nStartWeekDay + 1) % 7;
428 TimeSpan ts = new TimeSpan(nWeekDay - nOff, 0, 0, 0); //d,h,m,s
429
430 // if ts is negative, we will jump to the next week in the logic.
431 // to show the correct week, add 7. Confusing, I know.
432 if (ts < new TimeSpan()) ts = ts + new TimeSpan(7, 0, 0, 0);
433
434 if (m_nColumnCount == 1) // if one column start and end on the same day.
435 {
436 ts = new TimeSpan(0, 23, 59, 59);
437 WeekStartDay = SelectedDate;
438 WeekEndDay = WeekStartDay + ts;
439 }
440 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.
441 {
442 // if picked day is start of week (Sunday in US), start in the next day since that's the first day of work week
443 // else, just substract the calculated time span to get to the start of week (first work day)
444 WeekStartDay = (nWeekDay == nStartWeekDay) ? SelectedDate + new TimeSpan(1, 0, 0, 0) : SelectedDate - ts;
445 // End day calculation
446 int nEnd = 3;
447 ts = new TimeSpan((7 * nWeeks) - nEnd, 23, 59, 59);
448 WeekEndDay = WeekStartDay + ts;
449 }
450 else // if 7 column start at the 1st day of this week and end in 6:23:59:59 days.
451 {
452 // 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.
453 WeekStartDay = (nWeekDay == nStartWeekDay) ? SelectedDate : SelectedDate - ts - new TimeSpan(1, 0, 0, 0);
454 // End day calculation
455 int nEnd = 1;
456 ts = new TimeSpan((7 * nWeeks) - nEnd, 23, 59, 59);
457 WeekEndDay = WeekStartDay + ts;
458 }
459
460 bool bRet = ((WeekStartDay.Date != OldStartDay.Date) || (WeekEndDay.Date != OldEndDay.Date));
461 return bRet;
462 }
463
464 public void OnOpenDocument()
465 {
466 //Create new Document
467 // DateTime dStart;
468 // DateTime dEnd;
469
470 Debug.Assert(m_sResourcesArray.Count > 0);
471
472 m_sSecondary = "";
473
474 m_ScheduleType = (m_sResourcesArray.Count == 1) ? ScheduleType.Resource: ScheduleType.Clinic;
475
476 bool bRet = false;
477 //Set initial From and To dates based on current day
478 // DateTime dDate = new DateTime(2001,12,05); //test line
479 DateTime dDate = DateTime.Today;
480 if (m_ScheduleType == ScheduleType.Resource)
481 {
482 bRet = this.WeekNeedsRefresh(1,dDate, out this.m_dStartDate, out this.m_dEndDate);
483 }
484 else
485 {
486 this.m_dStartDate = dDate;
487 this.m_dEndDate = dDate;
488 this.m_dEndDate = this.m_dEndDate.AddHours(23);
489 this.m_dEndDate = this.m_dEndDate.AddMinutes(59);
490 this.m_dEndDate = this.m_dEndDate.AddSeconds(59);
491 }
492
493 bRet = this.RefreshDaysSchedule();
494
495 CGAVView view = null;
496 //If this document already has a view, the use it
497 Hashtable h = CGDocumentManager.Current.AvailabilityViews;
498 CGAVDocument d;
499 bool bReuseView = false;
500 foreach (CGAVView v in h.Keys)
501 {
502 d = (CGAVDocument) h[v];
503 if (d == this)
504 {
505 view = v;
506 bReuseView = true;
507 break;
508 }
509 }
510
511 //Otherwise, create new View
512 if (bReuseView == false)
513 {
514 view = new CGAVView();
515
516 view.DocManager = this.DocManager;
517 view.StartDate = m_dStartDate;
518
519 //Assign the document to the view
520 view.Document = this;
521
522 //Link the calendargrid's appointments table to the document's table
523 view.AVBlocks = this.AVBlocks;
524
525 view.Text = "Edit Availability - " + this.DocName;
526 view.Show();
527 }
528
529 this.UpdateAllViews();
530
531 }
532
533 public void AddResource(string sResource)
534 {
535 //TODO: Test that resource is not currently in list, that it IS a resource, etc
536 this.m_sResourcesArray.Add(sResource);
537 this.UpdateAllViews();
538 }
539
540 /// <summary>
541 /// Calls each AVview associated with this AVdocument and tells it to update itself
542 /// </summary>
543 public void UpdateAllViews()
544 {
545 //iterate through all views and call update.
546 Hashtable h = CGDocumentManager.Current.AvailabilityViews;
547
548 CGAVDocument d;
549 foreach (CGAVView v in h.Keys)
550 {
551 d = (CGAVDocument) h[v];
552 if (d == this)
553 {
554 v.UpdateArrays();
555 }
556 }
557
558 }
559
560 #endregion
561
562 }//End class
563}
Note: See TracBrowser for help on using the repository browser.