1 """This widgets lets you manage laboratory requests
2
3 - add requests
4 - keep track of pending requests
5 - see import errors
6 - review newly imported lab results
7 """
8
9
10 __version__ = "$Revision: 1.33 $"
11 __author__ = "Sebastian Hilbert <Sebastian.Hilbert@gmx.net>"
12
13 import os.path, sys, os, re as regex, random, logging
14
15
16
17 import wx
18 import wx.lib.mixins.listctrl as listmixins
19
20
21 from Gnumed.pycommon import gmI18N, gmPG2, gmCfg, gmExceptions, gmMatchProvider, gmDispatcher
22 from Gnumed.business import gmPerson, gmClinicalRecord, gmPathLab
23 from Gnumed.wxpython import gmGuiHelpers, gmPhraseWheel
24
25 _log = gmLog.gmDefLog
26 if __name__ == '__main__':
27 _log.SetAllLogLevels(gmLog.lData)
28 _log.Log(gmLog.lInfo, __version__)
29
30 [ wx.ID_LAB_GRID,
31 wx.ID_NB_LabJournal,
32 wx.ID_LBOX_pending_results,
33 wx.ID_PHRWH_labs,
34 wx.ID_TextCtrl_req_id,
35 wx.ID_BTN_save_request_ID,
36 wx.ID_BTN_select_all,
37 wx.ID_BTN_mark_reviewed,
38 wx.ID_pending_requests,
39 wx.ID_lbox_errors,
40 wx.ID_grid_unreviewed_results
41 ] = map(lambda _init_ctrls: wx.NewId(), range(11))
42
46
47 - def Draw(self, grid, attr, dc, rect, row, col, isSelected):
48 dc.SetBackgroundMode(wx.SOLID)
49 dc.SetBrush(wx.Brush(wx.BLACK, wx.SOLID))
50 dc.SetPen(wx.TRANSPARENT_PEN)
51 dc.DrawRectangle(rect.x, rect.y, rect.width, rect.height)
52
53 dc.SetBackgroundMode(wx.TRANSPARENT)
54 dc.SetFont(attr.GetFont())
55
56 text = grid.GetCellValue(row, col)
57 colors = [wxRED, wx.WHITE, wx.CYAN]
58 x = rect.x + 1
59 y = rect.y + 1
60 for ch in text:
61 dc.SetTextForeground(random.choice(colors))
62 dc.DrawText(ch, x, y)
63 w, h = dc.GetTextExtent(ch)
64 x = x + w
65 if x > rect.right - 5:
66 break
67
68
70 text = grid.GetCellValue(row, col)
71 dc.SetFont(attr.GetFont())
72 w, h = dc.GetTextExtent(text)
73 return wx.Size(w, h)
74
75
78
82
83 - def Draw(self, grid, attr, dc, rect, row, col, isSelected):
84 dc.SetBackgroundMode(wx.SOLID)
85 dc.SetBrush(wx.Brush(wx.BLACK, wx.SOLID))
86 dc.SetPen(wx.TRANSPARENT_PEN)
87 dc.DrawRectangle(rect.x, rect.y, rect.width, rect.height)
88 dc.SetBackgroundMode(wx.TRANSPARENT)
89 dc.SetFont(attr.GetFont())
90
91 text = grid.GetCellValue(row, col)
92 colors = [wxRED, wx.WHITE, wx.CYAN]
93 x = rect.x + 1
94 y = rect.y + 1
95 for ch in text:
96 dc.SetTextForeground(random.choice(colors))
97 dc.DrawText(ch, x, y)
98 w, h = dc.GetTextExtent(ch)
99 x = x + w
100 if x > rect.right - 5:
101 break
102
103
105 """This wx.Grid derivative displays lab data that has not yet been reviewed by a clinician.
106 """
108 """Set up our specialised grid.
109 """
110 wx.Grid.__init__(
111 self,
112 parent,
113 id,
114 pos = wx.DefaultPosition,
115 size = wx.DefaultSize,
116 style= wx.WANTS_CHARS
117 )
118
121 query = """
122 select pk, internal_name
123 from test_org
124 """
125 mp = gmMatchProvider.cMatchProvider_SQL2([query])
126 mp.setThresholds(aWord=2, aSubstring=4)
127
128 gmPhraseWheel.cPhraseWheel.__init__(
129 self,
130 parent = parent,
131 id = -1,
132 size = wx.DefaultSize,
133 pos = wx.DefaultPosition
134 )
135 self.SetToolTipString(_('choose which lab will process the probe with the specified ID'))
136 self.matcher = mp
137
138
140 - def __init__(self, parent, id, pos=wx.DefaultPosition, size=wx.DefaultSize, style=0):
141 wx.ListCtrl.__init__(self, parent, id, pos, size, style)
142 wx.ListCtrlAutoWidthMixin.__init__(self)
143
144
146 """This wx.Notebook derivative displays 'records still due' and lab-import related errors.
147 """
149 """Set up our specialised notebook.
150 """
151 wx.Notebook.__init__(
152 self,
153 parent,
154 id,
155 wx.DefaultPosition,
156 wx.DefaultSize,
157 0
158 )
159
160 self.__pat = gmPerson.gmCurrentPatient()
161
162 self.__do_layout_requests_page()
163 self.__do_layout_errors_page()
164 self.__do_layout_review_page()
165 self.__do_layout_config_page()
166
167 self.__register_events()
168
170 pnl_page = wx.Panel(self, -1)
171
172
173
174 szr_page = wx.BoxSizer(wx.VERTICAL)
175
176
177
178 pnl_page.SetAutoLayout(True)
179 pnl_page.SetSizer(szr_page)
180 szr_page.Fit(pnl_page)
181 szr_page.SetSizeHints(pnl_page)
182
183 self.AddPage(pnl_page, _("lab config"))
184
186
187 pnl_page = wx.Panel(self, -1)
188
189
190 hbszr = wx.StaticBoxSizer(
191 wx.StaticBox(
192 pnl_page,
193 -1,
194 _("add new request for current patient")
195 ),
196 wx.HORIZONTAL
197 )
198
199 lab_label = wx.StaticText(
200 name = 'lablabel',
201 parent = pnl_page,
202 id = -1,
203 label = _('Lab')
204 )
205
206 self.lab_wheel = cLabWheel(pnl_page)
207 self.lab_wheel.on_resize (None)
208 self.lab_wheel.add_callback_on_selection(self.on_lab_selected)
209
210 req_id_label = wx.StaticText(
211 name = 'req_id_label',
212 parent = pnl_page,
213 id = -1,
214 label = _("Specimen ID")
215 )
216
217 self.fld_request_id = wx.TextCtrl (
218 pnl_page,
219 wx.ID_TextCtrl_req_id,
220 "",
221 wx.DefaultPosition,
222 wx.Size(80,-1),
223 0
224 )
225
226 self.BTN_save_request_ID = wx.Button(
227 name = 'BTN_save_request_ID',
228 parent = pnl_page,
229 id = wx.ID_BTN_save_request_ID,
230 label = _("save lab request")
231 )
232 self.BTN_save_request_ID.SetToolTipString(_('associate chosen lab and ID with current patient'))
233
234 hbszr.Add(lab_label, 0, wx.ALIGN_CENTER | wx.ALL, 5)
235 hbszr.Add(self.lab_wheel, 0, wx.ALIGN_CENTER | wx.ALL, 5)
236 hbszr.Add(req_id_label, 0, wx.ALIGN_CENTER | wx.ALL, 5)
237 hbszr.Add(self.fld_request_id, 0, wx.ALIGN_CENTER| wx.ALL, 5)
238 hbszr.Add(self.BTN_save_request_ID, 0, wx.ALIGN_CENTER | wx.ALL, 5)
239
240
241 self.lbox_pending = cLabIDListCtrl(
242 pnl_page,
243 wx.ID_pending_requests,
244 size = wx.DefaultSize,
245 style = wx.LC_REPORT | wx.SUNKEN_BORDER | wx.LC_VRULES
246 )
247
248 self.lbox_pending.InsertColumn(0, _("date"))
249 self.lbox_pending.InsertColumn(1, _("lab"))
250 self.lbox_pending.InsertColumn(2, _("sample id"))
251 self.lbox_pending.InsertColumn(3, _("patient"))
252 self.lbox_pending.InsertColumn(4, _("status"))
253
254 szr_page = wx.BoxSizer(wx.VERTICAL)
255 szr_page.Add(hbszr,0, wx.ALIGN_LEFT | wx.ALL, 5)
256 szr_page.Add(self.lbox_pending, 1, wxEXPAND | wx.ALIGN_CENTER | wx.ALL, 5)
257
258
259 pnl_page.SetAutoLayout(True)
260 pnl_page.SetSizer(szr_page)
261 szr_page.Fit(pnl_page)
262 szr_page.SetSizeHints(pnl_page)
263
264 self.AddPage(pnl_page, _("pending requests"))
265
267 pnl_page = wx.Panel( self, -1)
268
269 self.lbox_errors = cLabIDListCtrl (
270 parent = pnl_page,
271 id = wx.ID_lbox_errors,
272 size = wx.DefaultSize,
273 style = wx.LC_REPORT | wx.SUNKEN_BORDER | wx.LC_VRULES
274 )
275 self.lbox_errors.InsertColumn(0, _("noticed when"))
276 self.lbox_errors.InsertColumn(1, _("problem"))
277 self.lbox_errors.InsertColumn(2, _("solution"))
278 self.lbox_errors.InsertColumn(3, _("context"))
279
280 szr_page = wx.BoxSizer(wx.VERTICAL)
281 szr_page.Add(self.lbox_errors, 1, wxEXPAND| wx.ALIGN_CENTER | wx.ALL, 5)
282
283
284 pnl_page.SetAutoLayout(True)
285 pnl_page.SetSizer(szr_page)
286 szr_page.Fit(pnl_page)
287 szr_page.SetSizeHints(pnl_page)
288
289 self.AddPage(pnl_page, _("lab errors"))
290
292 pnl_page = wx.Panel( self, -1)
293
294
295 self.__grid_unreviewed_results = cLabReviewGrid(
296 pnl_page,
297 wx.ID_grid_unreviewed_results
298 )
299 self.__grid_unreviewed_results.CreateGrid(0, 8, wx.Grid.wx.GridSelectCells)
300 self.__grid_unreviewed_results.SetDefaultCellAlignment(wx.ALIGN_LEFT, wx.ALIGN_CENTRE)
301
302 self.__grid_unreviewed_results.AutoSizeColumns(True)
303 self.__grid_unreviewed_results.AutoSizeRows(True)
304
305 renderer = apply(cLabJournalCellRenderer, ())
306 self.__grid_unreviewed_results.SetDefaultRenderer(renderer)
307
308
309
310
311
312
313
314
315
316
317
318 self.__grid_unreviewed_results.SetColLabelValue(0, _('reviewed'))
319 self.__grid_unreviewed_results.SetColLabelValue(1, _('relevant'))
320 self.__grid_unreviewed_results.SetColLabelValue(2, _('patient'))
321 self.__grid_unreviewed_results.SetColLabelValue(3, _('facility'))
322 self.__grid_unreviewed_results.SetColLabelValue(4, _('analysis'))
323 self.__grid_unreviewed_results.SetColLabelValue(5, _('result'))
324 self.__grid_unreviewed_results.SetColLabelValue(6, _('range'))
325 self.__grid_unreviewed_results.SetColLabelValue(7, _('info provided by lab'))
326
327 self.__grid_unreviewed_results.SetRowLabelSize(0)
328 self.__grid_unreviewed_results.AutoSize()
329
330
331
332 self.BTN_select_all = wx.Button(
333 name = 'BTN_select_all',
334 parent = pnl_page,
335 id = wx.ID_BTN_select_all,
336 label = _("select all requests")
337 )
338 self.BTN_select_all.SetToolTipString(_('select all requests'))
339
340 self.BTN_mark_reviewed = wx.Button(
341 name = 'BTN_mark_reviewed',
342 parent = pnl_page,
343 id = wx.ID_BTN_mark_reviewed,
344 label = _("mark selected requests as reviewed")
345 )
346 self.BTN_mark_reviewed.SetToolTipString(_('mark selected requests as reviewed'))
347
348 szr_buttons = wx.BoxSizer(wx.HORIZONTAL)
349 szr_buttons.Add(self.BTN_select_all, 0, wx.ALIGN_CENTER_VERTICAL, 1)
350 szr_buttons.Add(self.BTN_mark_reviewed, 0, wx.ALIGN_CENTER_VERTICAL, 1)
351
352
353 szr_page = wx.BoxSizer(wx.VERTICAL)
354 szr_page.Add(self.__grid_unreviewed_results, 1, wxEXPAND | wx.ALIGN_CENTER | wx.ALL, 5)
355 szr_page.Add(szr_buttons, 0, wxEXPAND | wx.ALIGN_CENTER | wx.ALL, 5)
356
357 pnl_page.SetAutoLayout(True)
358 pnl_page.SetSizer(szr_page)
359 szr_page.Fit(pnl_page)
360 szr_page.SetSizeHints(pnl_page)
361
362 self.AddPage(pnl_page, _("unreviewed results"))
363
365 wx.EVT_BUTTON(self.BTN_save_request_ID, wx.ID_BTN_save_request_ID, self.on_save_request_ID)
366 wx.EVT_BUTTON(self.BTN_select_all, wx.ID_BTN_select_all, self.on_select_all)
367 wx.EVT_BUTTON(self.BTN_mark_reviewed, wx.ID_BTN_mark_reviewed, self._on_mark_reviewed)
368
369 wx.EVT_GRID_CELL_LEFT_CLICK(self.__grid_unreviewed_results, self.OnLeftSClick)
370 wx.EVT_GRID_CELL_LEFT_DCLICK(self.__grid_unreviewed_results, self.OnLeftDClick)
371
372 wx.EVT_KEY_UP(self.__grid_unreviewed_results, self.OnKeyPressed)
373
375 if self.__pat['pk'] is None:
376 gmGuiHelpers.gm_show_error(
377 aMessage = _('Cannot load lab journal.\nYou first need to select a patient.'),
378 aTitle = _('loading lab journal')
379 )
380 return None
381
382 if self.__populate_notebook() is None:
383 return None
384 return 1
385
387
388 self.fld_request_id.Clear()
389 self.lab_wheel.Clear()
390
391
392
393 too_many, pending_requests = gmPathLab.get_pending_requests(limit=250)
394
395 self.lbox_pending.DeleteAllItems()
396
397 for request in pending_requests:
398 item_idx = self.lbox_pending.InsertItem(info=wx.ListItem())
399
400 self.lbox_pending.SetStringItem(index = item_idx, col=0, label=request['sampled_when'].date)
401
402 lab = self.__get_labname(request['pk_test_org'])
403 self.lbox_pending.SetStringItem(index = item_idx, col=1, label=lab[0][0])
404
405 self.lbox_pending.SetStringItem(index = item_idx, col=2, label=request['request_id'])
406
407 pat = request.get_patient()
408 self.lbox_pending.SetStringItem(index = item_idx, col=3, label="%s %s (%s)" % (pat[2], pat[3], pat[4].date))
409 self.lbox_pending.SetStringItem(index = item_idx, col=4, label=_('pending'))
410
411
412
413 lab_errors = self.__get_import_errors()
414
415 self.lbox_errors.DeleteAllItems()
416
417 for lab_error in lab_errors:
418 item_idx = self.lbox_errors.InsertItem(info=wx.ListItem())
419
420 self.lbox_errors.SetStringItem(index = item_idx, col=0, label=lab_error[1].date)
421
422 self.lbox_errors.SetStringItem(index = item_idx, col=1, label=lab_error[4])
423
424 self.lbox_errors.SetStringItem(index = item_idx, col=2, label=lab_error[5])
425
426 self.lbox_errors.SetStringItem(index = item_idx, col=3, label=lab_error[6])
427
428
429
430 more_avail, self.dict_unreviewed_results = gmPathLab.get_unreviewed_results(limit=50)
431
432
433
434
435 self.__grid_unreviewed_results.ClearGrid()
436
437 if self.__grid_unreviewed_results.GetNumberRows() == 0:
438 self.__grid_unreviewed_results.AppendRows(len(self.dict_unreviewed_results))
439
440 for item_idx in range(len(self.dict_unreviewed_results)):
441 result = self.dict_unreviewed_results[item_idx]
442
443
444 renderer = apply(wx.GridCellBoolRenderer, ())
445 self.__grid_unreviewed_results.SetCellRenderer(item_idx, 0 , renderer)
446 self.__grid_unreviewed_results.SetCellRenderer(item_idx, 1 , renderer)
447
448 self.__grid_unreviewed_results.SetReadOnly(item_idx, 0, 1)
449 self.__grid_unreviewed_results.SetReadOnly(item_idx, 1, 1)
450
451 self.__grid_unreviewed_results.EnableGridLines(0)
452
453 try:
454 self.__grid_unreviewed_results.SetColSize(0, self.__grid_unreviewed_results.GetColMinimalAcceptableWidth())
455 except AttributeError:
456 pass
457 self.__grid_unreviewed_results.SetCellValue(item_idx, 0, '0')
458
459 try:
460 self.__grid_unreviewed_results.SetColSize(1, self.__grid_unreviewed_results.GetColMinimalAcceptableWidth())
461 except AttributeError:
462 pass
463 self.__grid_unreviewed_results.SetCellValue(item_idx, 1, '0')
464
465 if (result['abnormal'] is not None) and (result['abnormal'].strip() != ''):
466 self.__grid_unreviewed_results.SetCellTextColour(item_idx,2,wx.RED)
467 self.__grid_unreviewed_results.SetCellTextColour(item_idx,3,wx.RED)
468 self.__grid_unreviewed_results.SetCellTextColour(item_idx,4,wx.RED)
469 self.__grid_unreviewed_results.SetCellTextColour(item_idx,5,wx.RED)
470 self.__grid_unreviewed_results.SetCellTextColour(item_idx,6,wx.RED)
471 self.__grid_unreviewed_results.SetCellTextColour(item_idx,7,wx.RED)
472
473 info = '(%s)' % result['abnormal']
474
475 self.__grid_unreviewed_results.SetCellValue(item_idx, 1, '1')
476 else:
477 info = ''
478
479 self.__grid_unreviewed_results.SetCellValue(item_idx, 1, '0')
480
481 pat = result.get_patient()
482 self.__grid_unreviewed_results.SetCellValue(item_idx, 2, "%s %s (%s)" % (pat[2], pat[3], pat[4].date))
483 self.__grid_unreviewed_results.SetColSize(2,200)
484
485 self.__grid_unreviewed_results.SetCellValue(item_idx, 3, result['lab_rxd_when'].date)
486 self.__grid_unreviewed_results.SetColSize(3,80)
487
488 self.__grid_unreviewed_results.SetCellValue(item_idx, 4, result['unified_name'])
489 self.__grid_unreviewed_results.SetColSize(4,100)
490
491
492 self.__grid_unreviewed_results.SetCellValue(item_idx, 5, '%s %s' % (result['unified_val'], info))
493 self.__grid_unreviewed_results.SetColSize(5,80)
494
495 if result['val_normal_range'] is None:
496 self.__grid_unreviewed_results.SetCellValue(item_idx, 6, '')
497 else:
498 self.__grid_unreviewed_results.SetCellValue(item_idx, 6, '%s %s' % (result['val_normal_range'], result['val_unit']))
499 self.__grid_unreviewed_results.SetColSize(6,80)
500
501
502 if result['note_provider'] is None:
503 self.__grid_unreviewed_results.SetCellValue(item_idx, 7, '')
504 else:
505 self.__grid_unreviewed_results.SetCellValue(item_idx, 7, result['note_provider'])
506
507
508 if more_avail:
509 gmDispatcher.send(signal = 'statustext', msg =_('More unreviewed results available. Review some to see more.'))
510
512 query = """select * from housekeeping_todo where category='lab'"""
513 import_errors = gmPG.run_ro_query('historica', query)
514 return import_errors
515
517
518 query= """select internal_name from test_org where pk=%s"""
519 labs = gmPG.run_ro_query('historica', query, None, data)
520 return labs
521
522
523
524
526 self.OnSelectCell(event, selector='LSClick')
527 event.Skip()
528
530 self.OnSelectCell(event, selector='LDClick')
531 event.Skip()
532
534
535
536
537 print "only stub for Crosscheck - please fix"
538
540 if selector is None:
541
542 return None
543
544 if selector in ['SelKEY', 'LDClick']:
545
546 col = self.__grid_unreviewed_results.GetGridCursorCol()
547 row = self.__grid_unreviewed_results.GetGridCursorRow()
548 if selector in ['LSClick']:
549
550 col = event.GetCol()
551 row = event.GetRow()
552
553 if col in [0,1]:
554 if self.__grid_unreviewed_results.GetCellValue(row,col) == '1':
555 self.__grid_unreviewed_results.SetCellValue(row,col, '0')
556 else:
557 self.__grid_unreviewed_results.SetCellValue(row,col,'1')
558 self.CrosscheckRelevant()
559 event.Skip()
560
562 """Is called when a key is pressed."""
563
564
565
566 if key.GetKeyCode() == WXK_DOWN:
567 key.Skip()
568
569 return
570
571 if key.GetKeyCode() == wx.WXK_UP:
572 key.Skip()
573
574 return
575
576
577
578
579 if key.GetKeyCode() == WXK_SPACE:
580 self.OnSelectCell(key,selector='SelKEY')
581 return
582
584 req_id = self.fld_request_id.GetValue()
585 if (req_id is None) or (req_id.strip() == ''):
586 gmGuiHelpers.gm_show_error (
587 _('You must type in a request ID !\n\nUsually you will find the request ID written on\nthe barcode sticker on your probe container.'),
588 _('saving request id')
589 )
590 return None
591 emr = self.__pat.get_emr()
592 request = emr.add_lab_request(lab=int(self.lab), req_id = req_id)
593 if request is None:
594 gmDispatcher.send(signal = 'statustext', msg =_('Cannot save lab request.'))
595 return None
596
597
598
599
600 self.__populate_notebook()
601
603 for item_idx in range(self.__grid_unreviewed_results.GetNumberRows()):
604 self.__grid_unreviewed_results.SetCellValue(item_idx, 0, '1')
605
607 reviewed_results = []
608 for row in range(self.__grid_unreviewed_results.GetNumberRows()):
609 if self.__grid_unreviewed_results.GetCellValue(row, 0) == '1':
610
611 result = self.dict_unreviewed_results[row]
612 reviewed_results.append(result)
613
614 relevant = self.__grid_unreviewed_results.GetCellValue(row, 1)
615 if relevant == '1':
616 result['relevant'] = 'true'
617 else:
618 result['relevant'] = 'false'
619
620 if len(reviewed_results) == 0:
621 gmGuiHelpers.beep_status_text(_('No results marked as reviewed.'))
622 event.Skip()
623 return None
624
625 for result in reviewed_results:
626 result['reviewed'] = 'true'
627 result['pk_reviewer'] = gmPerson.gmCurrentProvider()['pk_staff']
628 if not result['abnormal']:
629 result['abnormal'] = ''
630 successfull, error = result.save_payload()
631
632 if successfull:
633 self.__populate_notebook()
634 else:
635 _log.Log(gmLog.lErr, 'setting result status to reviewed failed %s' % error)
636 gmGuiHelpers.gm_show_error (
637 aMessage = _('Cannot mark results as "reviewed":\n%s') % error,
638 aTitle = _('update result status')
639 )
640 return None
641
642 event.Skip()
643
646
658
659
661 """This wx.Grid derivative displays a grid view of stored lab data.
662 """
664 """Set up our specialised grid.
665 """
666
667 self.__backend = gmPG.ConnectionPool()
668 self.__defconn = self.__backend.GetConnection('blobs')
669 if self.__defconn is None:
670 _log.Log(gmLog.lErr, "Cannot retrieve lab data without database connection !")
671 raise gmExceptions.ConstructorError, "cLabDataGrid.__init__(): need db conn"
672
673
674 self.__dbcfg = gmCfg.cCfgSQL(
675 aConn = self.__backend.GetConnection('default'),
676 aDBAPI = gmPG.dbapi
677 )
678
679 wx.Grid.__init__(
680 self,
681 parent,
682 id,
683 pos = wx.DefaultPosition,
684 size = wx.DefaultSize,
685 style= wx.WANTS_CHARS
686 )
687
688 self.__pat = gmPerson.gmCurrentPatient()
689
690
691
692
693 self.__grid_unreviewed_results = self.CreateGrid(0, 0, wx.Grid.wx.GridSelectCells )
694 self.SetDefaultCellAlignment(wx.ALIGN_RIGHT,wx.ALIGN_CENTRE)
695
696 renderer = apply(cLabDataGridCellRenderer, ())
697 self.SetDefaultRenderer(renderer)
698
699
700 self.AutoSizeColumns(True)
701 self.AutoSizeRows(True)
702
703
704 font = self.GetFont()
705
706 attr = wx.GridCellAttr()
707 attr.SetFont(font)
708
709 attr.SetReadOnly(True)
710
711
712
713
714
715
716
718 if self.CanEnableCellControl():
719 self.EnableCellEditControl()
720
721
723 if self.__pat['pk'] is None:
724 _log.Log(gmLog.lErr, 'need patient for update')
725 gmGuiHelpers.gm_show_error(
726 aMessage = _('Cannot load lab data.\nYou first need to select a patient.'),
727 aTitle = _('loading lab data')
728 )
729 return None
730
731 if self.__populate_grid() is None:
732 return None
733
734 return 1
735
736
738 """Fill grid with data.
739
740 sorting:
741 1) check user's preferred way of sorting
742 none defaults to smart sorting
743 2) check if user defined lab profiles
744 - add a notebook tab for each profile
745 - postpone profile dependent stats until tab is selected
746 sort modes :
747 1: no profiles -> smart sorting only
748 2: profile -> smart sorting first
749 3: profile -> user defined profile order
750 """
751 emr = self.__pat.get_emr()
752
753 results = emr.get_lab_results()
754 if results is None:
755 name = self.__pat.get_names()
756 gmGuiHelpers.gm_show_error (
757 aMessage = _('Error loading lab data for patient\n[%s %s].') % (name['firstnames'], name['lastnames']),
758 aTitle = _('loading lab data')
759 )
760 return None
761 if len(results) == 0:
762 gmDispatcher.send(signal = 'statustext', msg =_('No lab data available.'))
763 return None
764
765 dates, test_names = self.__compile_stats(results)
766
767
768 sort_mode = 1
769
770 if sort_mode == 1:
771 """
772 2) look at the the most recent date a test was performed on
773 move these tests to the top
774 3) sort by runs starting with most recent date
775 a run is a series of consecutive dates a particular test was done on
776 sort by length of the runs
777 longest run will move to the top
778 """
779 pass
780
781
782 self.ClearGrid()
783
784 if self.GetNumberCols() == 0:
785 self.AppendCols(len(dates))
786
787 for i in range(len(dates)):
788 self.SetColLabelValue(i, dates[i])
789
790 if self.GetNumberRows() == 0:
791 self.AppendRows(len(test_names))
792
793 for i in range(len(test_names)):
794 self.SetRowLabelValue(i, test_names[i])
795
796 cells = []
797 for result in results:
798
799 x = dates.index(result['val_when'].date)
800 y = test_names.index(result['unified_name'])
801 cell_data = self.GetCellValue(x, y)
802 if cell_data == '':
803 self.SetCellValue(x, y, '%s %s' % (result['unified_val'], result['val_unit']))
804 else:
805 self.SetCellValue(x, y, '%s\n%s %s' % (cell_data, result['unified_val'], result['val_unit']))
806
807
808
809
810
811 self.AutoSize()
812 return 1
813
815
816 dates = []
817 test_names = []
818 for result in lab_results:
819 if result['val_when'].date not in dates:
820 dates.append(result['val_when'].date)
821 if result['unified_name'] not in test_names:
822 test_names.append(result['unified_name'])
823 dates.sort()
824
825 return dates, test_names
826
827
828
829
830
831
832
833
834
837
838
839
840
841
842 if __name__ == '__main__':
843 _log.Log (gmLog.lInfo, "starting lab journal")
844
845
846 try:
847 application = wxPyWidgetTester(size=(640,480))
848 application.SetWidget(cStandalonePanel,-1)
849 application.MainLoop()
850 except:
851 _log.LogException("unhandled exception caught !", sys.exc_info(), 1)
852
853 raise
854
855 _log.Log (gmLog.lInfo, "closing lab journal")
856
857