| Home | Trees | Indices | Help |
|
|---|
|
|
1 # coding: utf8
2 """GNUmed billing handling widgets."""
3
4 #================================================================
5 __author__ = "Karsten Hilbert <Karsten.Hilbert@gmx.net>"
6 __license__ = "GPL v2 or later"
7
8 import logging
9 import sys
10
11
12 import wx
13
14
15 if __name__ == '__main__':
16 sys.path.insert(0, '../../')
17 from Gnumed.pycommon import gmTools
18 from Gnumed.pycommon import gmDateTime
19 from Gnumed.pycommon import gmMatchProvider
20 from Gnumed.pycommon import gmDispatcher
21 from Gnumed.pycommon import gmPG2
22 from Gnumed.pycommon import gmCfg
23 from Gnumed.pycommon import gmPrinting
24 from Gnumed.pycommon import gmNetworkTools
25
26 from Gnumed.business import gmBilling
27 from Gnumed.business import gmPerson
28 from Gnumed.business import gmStaff
29 from Gnumed.business import gmDocuments
30 from Gnumed.business import gmPraxis
31 from Gnumed.business import gmForms
32 from Gnumed.business import gmDemographicRecord
33
34 from Gnumed.wxpython import gmListWidgets
35 from Gnumed.wxpython import gmRegetMixin
36 from Gnumed.wxpython import gmPhraseWheel
37 from Gnumed.wxpython import gmGuiHelpers
38 from Gnumed.wxpython import gmEditArea
39 from Gnumed.wxpython import gmPersonContactWidgets
40 from Gnumed.wxpython import gmPatSearchWidgets
41 from Gnumed.wxpython import gmMacro
42 from Gnumed.wxpython import gmFormWidgets
43 from Gnumed.wxpython import gmDocumentWidgets
44 from Gnumed.wxpython import gmDataPackWidgets
45
46
47 _log = logging.getLogger('gm.ui')
48
49 #================================================================
51 ea = cBillableEAPnl(parent = parent, id = -1)
52 ea.data = billable
53 ea.mode = gmTools.coalesce(billable, 'new', 'edit')
54 dlg = gmEditArea.cGenericEditAreaDlg2 (
55 parent = parent,
56 id = -1,
57 edit_area = ea,
58 single_entry = gmTools.bool2subst((billable is None), False, True)
59 )
60 dlg.SetTitle(gmTools.coalesce(billable, _('Adding new billable'), _('Editing billable')))
61 if dlg.ShowModal() == wx.ID_OK:
62 dlg.Destroy()
63 return True
64 dlg.Destroy()
65 return False
66
67 #----------------------------------------------------------------
69
70 if parent is None:
71 parent = wx.GetApp().GetTopWindow()
72
73 #------------------------------------------------------------
74 def edit(billable=None):
75 return edit_billable(parent = parent, billable = billable)
76 #------------------------------------------------------------
77 def delete(billable):
78 if billable.is_in_use:
79 gmDispatcher.send(signal = 'statustext', msg = _('Cannot delete this billable item. It is in use.'), beep = True)
80 return False
81 return gmBilling.delete_billable(pk_billable = billable['pk_billable'])
82 #------------------------------------------------------------
83 def get_tooltip(item):
84 if item is None:
85 return None
86 return item.format()
87 #------------------------------------------------------------
88 def refresh(lctrl):
89 billables = gmBilling.get_billables()
90 items = [ [
91 b['billable_code'],
92 b['billable_description'],
93 u'%(currency)s%(raw_amount)s' % b,
94 u'%s (%s)' % (b['catalog_short'], b['catalog_version']),
95 gmTools.coalesce(b['comment'], u''),
96 b['pk_billable']
97 ] for b in billables ]
98 lctrl.set_string_items(items)
99 lctrl.set_data(billables)
100 #------------------------------------------------------------
101 def manage_data_packs(billable):
102 gmDataPackWidgets.manage_data_packs(parent = parent)
103 return True
104 #------------------------------------------------------------
105 def browse_catalogs(billable):
106 dbcfg = gmCfg.cCfgSQL()
107 url = dbcfg.get2 (
108 option = 'external.urls.schedules_of_fees',
109 workplace = gmPraxis.gmCurrentPraxisBranch().active_workplace,
110 bias = 'user',
111 default = u'http://www.e-bis.de/goae/defaultFrame.htm'
112 )
113 gmNetworkTools.open_url_in_browser(url = url)
114 return False
115 #------------------------------------------------------------
116 msg = _('\nThese are the items for billing registered with GNUmed.\n')
117
118 gmListWidgets.get_choices_from_list (
119 parent = parent,
120 msg = msg,
121 caption = _('Showing billable items.'),
122 columns = [_('Code'), _('Description'), _('Value'), _('Catalog'), _('Comment'), u'#'],
123 single_selection = True,
124 new_callback = edit,
125 edit_callback = edit,
126 delete_callback = delete,
127 refresh_callback = refresh,
128 middle_extra_button = (
129 _('Data packs'),
130 _('Browse and install billing catalog (schedule of fees) data packs'),
131 manage_data_packs
132 ),
133 right_extra_button = (
134 _('Catalogs (WWW)'),
135 _('Browse billing catalogs (schedules of fees) on the web'),
136 browse_catalogs
137 ),
138 list_tooltip_callback = get_tooltip
139 )
140
141 #----------------------------------------------------------------
143
145 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
146 query = u"""
147 SELECT -- DISTINCT ON (label)
148 r_vb.pk_billable
149 AS data,
150 r_vb.billable_code || ': ' || r_vb.billable_description || ' (' || r_vb.catalog_short || ' - ' || r_vb.catalog_version || ')'
151 AS list_label,
152 r_vb.billable_code || ' (' || r_vb.catalog_short || ' - ' || r_vb.catalog_version || ')'
153 AS field_label
154 FROM
155 ref.v_billables r_vb
156 WHERE
157 r_vb.active
158 AND (
159 r_vb.billable_code %(fragment_condition)s
160 OR
161 r_vb.billable_description %(fragment_condition)s
162 )
163 ORDER BY list_label
164 LIMIT 20
165 """
166 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query)
167 mp.setThresholds(1, 2, 4)
168 self.matcher = mp
169 #------------------------------------------------------------
172 #------------------------------------------------------------
174 if self.GetData() is None:
175 return None
176 billable = gmBilling.cBillable(aPK_obj = self._data.values()[0]['data'])
177 return billable.format()
178 #------------------------------------------------------------
180 val = u'%s (%s - %s)' % (
181 instance['billable_code'],
182 instance['catalog_short'],
183 instance['catalog_version']
184 )
185 self.SetText(value = val, data = instance['pk_billable'])
186 #------------------------------------------------------------
189
190 #----------------------------------------------------------------
191 from Gnumed.wxGladeWidgets import wxgBillableEAPnl
192
194
196
197 try:
198 data = kwargs['billable']
199 del kwargs['billable']
200 except KeyError:
201 data = None
202
203 wxgBillableEAPnl.wxgBillableEAPnl.__init__(self, *args, **kwargs)
204 gmEditArea.cGenericEditAreaMixin.__init__(self)
205
206 # Code using this mixin should set mode and data
207 # after instantiating the class:
208 self.mode = 'new'
209 self.data = data
210 if data is not None:
211 self.mode = 'edit'
212
213 #self.__init_ui()
214 #----------------------------------------------------------------
215 # def __init_ui(self):
216 # # adjust phrasewheels etc
217 #----------------------------------------------------------------
218 # generic Edit Area mixin API
219 #----------------------------------------------------------------
221
222 validity = True
223
224 vat = self._TCTRL_vat.GetValue().strip()
225 if vat == u'':
226 self.display_tctrl_as_valid(tctrl = self._TCTRL_vat, valid = True)
227 else:
228 success, vat = gmTools.input2decimal(initial = vat)
229 if success:
230 self.display_tctrl_as_valid(tctrl = self._TCTRL_vat, valid = True)
231 else:
232 validity = False
233 self.display_tctrl_as_valid(tctrl = self._TCTRL_vat, valid = False)
234 self.status_message = _('VAT must be empty or a number.')
235 self._TCTRL_vat.SetFocus()
236
237 currency = self._TCTRL_currency.GetValue().strip()
238 if currency == u'':
239 validity = False
240 self.display_tctrl_as_valid(tctrl = self._TCTRL_currency, valid = False)
241 self.status_message = _('Currency is missing.')
242 self._TCTRL_currency.SetFocus()
243 else:
244 self.display_tctrl_as_valid(tctrl = self._TCTRL_currency, valid = True)
245
246 success, val = gmTools.input2decimal(initial = self._TCTRL_amount.GetValue())
247 if success:
248 self.display_tctrl_as_valid(tctrl = self._TCTRL_amount, valid = True)
249 else:
250 validity = False
251 self.display_tctrl_as_valid(tctrl = self._TCTRL_amount, valid = False)
252 self.status_message = _('Value is missing.')
253 self._TCTRL_amount.SetFocus()
254
255 if self._TCTRL_description.GetValue().strip() == u'':
256 validity = False
257 self.display_tctrl_as_valid(tctrl = self._TCTRL_description, valid = False)
258 self.status_message = _('Description is missing.')
259 self._TCTRL_description.SetFocus()
260 else:
261 self.display_tctrl_as_valid(tctrl = self._TCTRL_description, valid = True)
262
263 if self._PRW_coding_system.GetData() is None:
264 validity = False
265 self._PRW_coding_system.display_as_valid(False)
266 self.status_message = _('Coding system is missing.')
267 self._PRW_coding_system.SetFocus()
268 else:
269 self._PRW_coding_system.display_as_valid(True)
270
271 if self._TCTRL_code.GetValue().strip() == u'':
272 validity = False
273 self.display_tctrl_as_valid(tctrl = self._TCTRL_code, valid = False)
274 self.status_message = _('Code is missing.')
275 self._TCTRL_code.SetFocus()
276 else:
277 self.display_tctrl_as_valid(tctrl = self._TCTRL_code, valid = True)
278
279 return validity
280 #----------------------------------------------------------------
282 data = gmBilling.create_billable (
283 code = self._TCTRL_code.GetValue().strip(),
284 term = self._TCTRL_description.GetValue().strip(),
285 data_source = self._PRW_coding_system.GetData(),
286 return_existing = False
287 )
288 if data is None:
289 self.status_message = _('Billable already exists.')
290 return False
291
292 val = self._TCTRL_amount.GetValue().strip()
293 if val != u'':
294 tmp, val = gmTools.input2decimal(val)
295 data['raw_amount'] = val
296 val = self._TCTRL_currency.GetValue().strip()
297 if val != u'':
298 data['currency'] = val
299 vat = self._TCTRL_vat.GetValue().strip()
300 if vat != u'':
301 tmp, vat = gmTools.input2decimal(vat)
302 data['vat_multiplier'] = vat / 100
303 data['comment'] = self._TCTRL_comment.GetValue().strip()
304 data['active'] = self._CHBOX_active.GetValue()
305
306 data.save()
307
308 self.data = data
309
310 return True
311 #----------------------------------------------------------------
313 self.data['billable_description'] = self._TCTRL_description.GetValue().strip()
314 tmp, self.data['raw_amount'] = gmTools.input2decimal(self._TCTRL_amount.GetValue())
315 self.data['currency'] = self._TCTRL_currency.GetValue().strip()
316 vat = self._TCTRL_vat.GetValue().strip()
317 if vat == u'':
318 vat = 0
319 else:
320 tmp, vat = gmTools.input2decimal(vat)
321 self.data['vat_multiplier'] = vat / 100
322 self.data['comment'] = self._TCTRL_comment.GetValue().strip()
323 self.data['active'] = self._CHBOX_active.GetValue()
324 self.data.save()
325 return True
326 #----------------------------------------------------------------
328 self._TCTRL_code.SetValue(u'')
329 self._PRW_coding_system.SetText(u'', None)
330 self._TCTRL_description.SetValue(u'')
331 self._TCTRL_amount.SetValue(u'')
332 self._TCTRL_currency.SetValue(u'')
333 self._TCTRL_vat.SetValue(u'')
334 self._TCTRL_comment.SetValue(u'')
335 self._CHBOX_active.SetValue(True)
336
337 self._TCTRL_code.SetFocus()
338 #----------------------------------------------------------------
341 #----------------------------------------------------------------
343 self._TCTRL_code.SetValue(self.data['billable_code'])
344 self._TCTRL_code.Enable(False)
345 self._PRW_coding_system.SetText(u'%s (%s)' % (self.data['catalog_short'], self.data['catalog_version']), self.data['pk_data_source'])
346 self._PRW_coding_system.Enable(False)
347 self._TCTRL_description.SetValue(self.data['billable_description'])
348 self._TCTRL_amount.SetValue(u'%s' % self.data['raw_amount'])
349 self._TCTRL_currency.SetValue(self.data['currency'])
350 self._TCTRL_vat.SetValue(u'%s' % (self.data['vat_multiplier'] * 100))
351 self._TCTRL_comment.SetValue(gmTools.coalesce(self.data['comment'], u''))
352 self._CHBOX_active.SetValue(self.data['active'])
353
354 self._TCTRL_description.SetFocus()
355 #----------------------------------------------------------------
356
357 #================================================================
358 # invoice related widgets
359 #----------------------------------------------------------------
361
362 if parent is None:
363 parent = wx.GetApp().GetTopWindow()
364
365 template = gmFormWidgets.manage_form_templates (
366 parent = parent,
367 template_types = ['invoice']
368 )
369
370 if template is None:
371 gmDispatcher.send(signal = 'statustext', msg = _('No invoice template configured.'), beep = True)
372 return None
373
374 if template['engine'] not in [u'L', u'X']:
375 gmDispatcher.send(signal = 'statustext', msg = _('No invoice template configured.'), beep = True)
376 return None
377
378 if with_vat:
379 option = u'form_templates.invoice_with_vat'
380 else:
381 option = u'form_templates.invoice_no_vat'
382
383 dbcfg = gmCfg.cCfgSQL()
384 dbcfg.set (
385 workplace = gmPraxis.gmCurrentPraxisBranch().active_workplace,
386 option = option,
387 value = u'%s - %s' % (template['name_long'], template['external_version'])
388 )
389
390 return template
391 #----------------------------------------------------------------
393
394 dbcfg = gmCfg.cCfgSQL()
395 if with_vat:
396 option = u'form_templates.invoice_with_vat'
397 else:
398 option = u'form_templates.invoice_no_vat'
399
400 template = dbcfg.get2 (
401 option = option,
402 workplace = gmPraxis.gmCurrentPraxisBranch().active_workplace,
403 bias = 'user'
404 )
405
406 if template is None:
407 template = configure_invoice_template(parent = parent, with_vat = with_vat)
408 if template is None:
409 gmGuiHelpers.gm_show_error (
410 aMessage = _('There is no invoice template configured.'),
411 aTitle = _('Getting invoice template')
412 )
413 return None
414 else:
415 try:
416 name, ver = template.split(u' - ')
417 except:
418 _log.exception('problem splitting invoice template name [%s]', template)
419 gmDispatcher.send(signal = 'statustext', msg = _('Problem loading invoice template.'), beep = True)
420 return None
421 template = gmForms.get_form_template(name_long = name, external_version = ver)
422 if template is None:
423 gmGuiHelpers.gm_show_error (
424 aMessage = _('Cannot load invoice template [%s - %s]') % (name, ver),
425 aTitle = _('Getting invoice template')
426 )
427 return None
428
429 return template
430
431 #================================================================
432 # per-patient bill related widgets
433 #----------------------------------------------------------------
435
436 if bill is None:
437 # manually creating bills is not yet supported
438 return
439
440 ea = cBillEAPnl(parent = parent, id = -1)
441 ea.data = bill
442 ea.mode = gmTools.coalesce(bill, 'new', 'edit')
443 dlg = gmEditArea.cGenericEditAreaDlg2(parent = parent, id = -1, edit_area = ea, single_entry = single_entry)
444 dlg.SetTitle(gmTools.coalesce(bill, _('Adding new bill'), _('Editing bill')))
445 if dlg.ShowModal() == wx.ID_OK:
446 dlg.Destroy()
447 return True
448 dlg.Destroy()
449 return False
450 #----------------------------------------------------------------
452
453 if len(bill_items) == 0:
454 return None
455
456 item = bill_items[0]
457 currency = item['currency']
458 vat = item['vat_multiplier']
459 pat = item['pk_patient']
460
461 # check item consistency
462 has_errors = False
463 for item in bill_items:
464 if (item['currency'] != currency) or (
465 item['vat_multiplier'] != vat) or (
466 item['pk_patient'] != pat
467 ):
468 msg = _(
469 'All items to be included with a bill must\n'
470 'coincide on currency, VAT, and patient.\n'
471 '\n'
472 'This item does not:\n'
473 '\n'
474 '%s\n'
475 ) % item.format()
476 has_errors = True
477
478 if item['pk_bill'] is not None:
479 msg = _(
480 'This item is already invoiced:\n'
481 '\n'
482 '%s\n'
483 '\n'
484 'Cannot put it on a second bill.'
485 ) % item.format()
486 has_errors = True
487
488 if has_errors:
489 gmGuiHelpers.gm_show_warning(aTitle = _('Checking invoice items'), aMessage = msg)
490 return None
491
492 # create bill
493 bill = gmBilling.create_bill(invoice_id = gmBilling.get_invoice_id(pk_patient = pat))
494 _log.info('created bill [%s]', bill['invoice_id'])
495 bill.add_items(items = bill_items)
496 bill.set_missing_address_from_default()
497
498 return bill
499 #----------------------------------------------------------------
501
502 bill_patient_not_active = False
503 # do we have a current patient ?
504 curr_pat = gmPerson.gmCurrentPatient()
505 if curr_pat.connected:
506 # is the bill about the current patient, too ?
507 # (because that's what the new invoice would get
508 # created for and attached to)
509 if curr_pat.ID != bill['pk_patient']:
510 bill_patient_not_active = True
511 else:
512 bill_patient_not_active = True
513
514 # FIXME: could ask whether to set fk_receiver_identity
515 # FIXME: but this would need enabling the bill EA to edit same
516 if bill_patient_not_active:
517 activate_patient = gmGuiHelpers.gm_show_question (
518 title = _('Creating invoice'),
519 question = _(
520 'Cannot find an existing invoice PDF for this bill.\n'
521 '\n'
522 'Active patient: %s\n'
523 'Patient on bill: #%s\n'
524 '\n'
525 'Activate patient on bill so invoice PDF can be created ?'
526 ) % (
527 gmTools.coalesce(curr_pat.ID, u'', u'#%s'),
528 bill['pk_patient']
529 )
530 )
531 if not activate_patient:
532 return False
533 if not gmPatSearchWidgets.set_active_patient(patient = bill['pk_patient']):
534 gmGuiHelpers.gm_show_error (
535 aTitle = _('Creating invoice'),
536 aMessage = _('Cannot activate patient #%s.') % bill['pk_patient']
537 )
538 return False
539
540 if None in [ bill['close_date'], bill['pk_receiver_address'] ]:
541 edit_bill(parent = parent, bill = bill, single_entry = True)
542 # cannot invoice open bills
543 if bill['close_date'] is None:
544 _log.error('cannot create invoice from bill, bill not closed')
545 gmGuiHelpers.gm_show_warning (
546 aTitle = _('Creating invoice'),
547 aMessage = _(
548 'Cannot create invoice from bill.\n'
549 '\n'
550 'The bill is not closed.'
551 )
552 )
553 return False
554 # cannot create invoice if no receiver address
555 if bill['pk_receiver_address'] is None:
556 _log.error('cannot create invoice from bill, lacking receiver address')
557 gmGuiHelpers.gm_show_warning (
558 aTitle = _('Creating invoice'),
559 aMessage = _(
560 'Cannot create invoice from bill.\n'
561 '\n'
562 'There is no receiver address.'
563 )
564 )
565 return False
566
567 # find template
568 template = get_invoice_template(parent = parent, with_vat = bill['apply_vat'])
569 if template is None:
570 gmGuiHelpers.gm_show_warning (
571 aTitle = _('Creating invoice'),
572 aMessage = _(
573 'Cannot create invoice from bill\n'
574 'without an invoice template.'
575 )
576 )
577 return False
578
579 # process template
580 try:
581 invoice = template.instantiate()
582 except KeyError:
583 _log.exception('cannot instantiate invoice template [%s]', template)
584 gmGuiHelpers.gm_show_error (
585 aMessage = _('Invalid invoice template [%s - %s (%s)]') % (name, ver, template['engine']),
586 aTitle = _('Printing medication list')
587 )
588 return False
589
590 ph = gmMacro.gmPlaceholderHandler()
591 #ph.debug = True
592 ph.set_cache_value('bill', bill)
593 invoice.substitute_placeholders(data_source = ph)
594 ph.unset_cache_value('bill')
595 pdf_name = invoice.generate_output()
596 if pdf_name is None:
597 gmGuiHelpers.gm_show_error (
598 aMessage = _('Error generating invoice PDF.'),
599 aTitle = _('Creating invoice')
600 )
601 return False
602
603 # keep a copy
604 if keep_a_copy:
605 files2import = []
606 files2import.extend(invoice.final_output_filenames)
607 files2import.extend(invoice.re_editable_filenames)
608 doc = gmDocumentWidgets.save_files_as_new_document (
609 parent = parent,
610 filenames = files2import,
611 document_type = template['instance_type'],
612 review_as_normal = True,
613 reference = bill['invoice_id']
614 )
615 bill['pk_doc'] = doc['pk_doc']
616 bill.save()
617
618 if not print_it:
619 return True
620
621 # print template
622 printed = gmPrinting.print_files(filenames = [pdf_name], jobtype = 'invoice')
623 if not printed:
624 gmGuiHelpers.gm_show_error (
625 aMessage = _('Error printing the invoice.'),
626 aTitle = _('Printing invoice')
627 )
628 return True
629
630 return True
631
632 #----------------------------------------------------------------
634
635 if parent is None:
636 parent = wx.GetApp().GetTopWindow()
637
638 dlg = gmGuiHelpers.c3ButtonQuestionDlg (
639 parent, -1,
640 caption = _('Deleting bill'),
641 question = _(
642 'When deleting the bill [%s]\n'
643 'do you want to keep its items (effectively \"unbilling\" them)\n'
644 'or do you want to also delete the bill items from the patient ?\n'
645 ) % bill['invoice_id'],
646 button_defs = [
647 {'label': _('Delete + keep'), 'tooltip': _('Delete the bill but keep ("unbill") its items.'), 'default': True},
648 {'label': _('Delete all'), 'tooltip': _('Delete both the bill and its items from the patient.')}
649 ],
650 show_checkbox = True,
651 checkbox_msg = _('Also remove invoice PDF'),
652 checkbox_tooltip = _('Also remove the invoice PDF from the document archive (because it will not correspond to the bill anymore).')
653 )
654 button_pressed = dlg.ShowModal()
655 delete_invoice = dlg.checkbox_is_checked()
656 dlg.Destroy()
657
658 if button_pressed == wx.ID_CANCEL:
659 return False
660
661 if button_pressed == wx.ID_YES:
662 for item in bill.bill_items:
663 item['pk_bill'] = None
664 item.save()
665
666 if button_pressed == wx.ID_NO:
667 for item in bill.bill_items:
668 item['pk_bill'] = None
669 item.save()
670 gmBilling.delete_bill_item(pk_bill_item = item['pk_bill_item'])
671
672 if delete_invoice:
673 if bill['pk_doc'] is not None:
674 gmDocuments.delete_document (
675 document_id = bill['pk_doc'],
676 encounter_id = gmPerson.cPatient(aPK_obj = bill['pk_patient']).emr.active_encounter['pk_encounter']
677 )
678
679 return gmBilling.delete_bill(pk_bill = bill['pk_bill'])
680
681 #----------------------------------------------------------------
683
684 if bill is None:
685 return False
686
687 list_data = bill.bill_items
688 if len(list_data) == 0:
689 return False
690
691 if parent is None:
692 parent = wx.GetApp().GetTopWindow()
693
694 list_items = [ [
695 gmDateTime.pydt_strftime(b['date_to_bill'], '%Y %b %d', accuracy = gmDateTime.acc_days),
696 b['unit_count'],
697 u'%s: %s%s' % (b['billable_code'], b['billable_description'], gmTools.coalesce(b['item_detail'], u'', u' - %s')),
698 u'%(curr)s %(total_val)s (%(count)s %(x)s %(unit_val)s%(x)s%(val_multiplier)s)' % {
699 'curr': b['currency'],
700 'total_val': b['total_amount'],
701 'count': b['unit_count'],
702 'x': gmTools.u_multiply,
703 'unit_val': b['net_amount_per_unit'],
704 'val_multiplier': b['amount_multiplier']
705 },
706 u'%(curr)s%(vat)s (%(perc_vat)s%%)' % {
707 'vat': b['vat'],
708 'curr': b['currency'],
709 'perc_vat': b['vat_multiplier'] * 100
710 },
711 u'%s (%s)' % (b['catalog_short'], b['catalog_version']),
712 b['pk_bill_item']
713 ] for b in list_data ]
714
715 msg = _('Select the items you want to remove from bill [%s]:\n') % bill['invoice_id']
716 items2remove = gmListWidgets.get_choices_from_list (
717 parent = parent,
718 msg = msg,
719 caption = _('Removing items from bill'),
720 columns = [_('Date'), _('Count'), _('Description'), _('Value'), _('VAT'), _('Catalog'), u'#'],
721 single_selection = False,
722 choices = list_items,
723 data = list_data
724 )
725
726 if items2remove is None:
727 return False
728
729 dlg = gmGuiHelpers.c3ButtonQuestionDlg (
730 parent, -1,
731 caption = _('Removing items from bill'),
732 question = _(
733 '%s items selected from bill [%s]\n'
734 '\n'
735 'Do you want to only remove the selected items\n'
736 'from the bill ("unbill" them) or do you want\n'
737 'to delete them entirely from the patient ?\n'
738 '\n'
739 'Note that neither action is reversible.'
740 ) % (
741 len(items2remove),
742 bill['invoice_id']
743 ),
744 button_defs = [
745 {'label': _('"Unbill"'), 'tooltip': _('Only "unbill" items (remove from bill but do not delete from patient).'), 'default': True},
746 {'label': _('Delete'), 'tooltip': _('Completely delete items from the patient.')}
747 ],
748 show_checkbox = True,
749 checkbox_msg = _('Also remove invoice PDF'),
750 checkbox_tooltip = _('Also remove the invoice PDF from the document archive (because it will not correspond to the bill anymore).')
751 )
752 button_pressed = dlg.ShowModal()
753 delete_invoice = dlg.checkbox_is_checked()
754 dlg.Destroy()
755
756 if button_pressed == wx.ID_CANCEL:
757 return False
758
759 # remember this because unlinking/deleting the items
760 # will remove the patient PK from the bill
761 pk_patient = bill['pk_patient']
762
763 for item in items2remove:
764 item['pk_bill'] = None
765 item.save()
766 if button_pressed == wx.ID_NO:
767 gmBilling.delete_bill_item(pk_bill_item = item['pk_bill_item'])
768
769 if delete_invoice:
770 if bill['pk_doc'] is not None:
771 gmDocuments.delete_document (
772 document_id = bill['pk_doc'],
773 encounter_id = gmPerson.cPatient(aPK_obj = pk_patient).emr.active_encounter['pk_encounter']
774 )
775
776 # delete bill, too, if empty
777 if len(bill.bill_items) == 0:
778 gmBilling.delete_bill(pk_bill = bill['pk_bill'])
779
780 return True
781 #----------------------------------------------------------------
783
784 if parent is None:
785 parent = wx.GetApp().GetTopWindow()
786
787 #------------------------------------------------------------
788 def show_pdf(bill):
789 if bill is None:
790 return False
791
792 # find invoice
793 invoice = bill.invoice
794 if invoice is not None:
795 success, msg = invoice.parts[-1].display_via_mime()
796 if not success:
797 gmGuiHelpers.gm_show_error(aMessage = msg, aTitle = _('Displaying invoice'))
798 return False
799
800 # create it ?
801 create_it = gmGuiHelpers.gm_show_question (
802 title = _('Displaying invoice'),
803 question = _(
804 'Cannot find an existing\n'
805 'invoice PDF for this bill.\n'
806 '\n'
807 'Do you want to create one ?'
808 ),
809 )
810 if not create_it:
811 return False
812
813 # prepare invoicing
814 if not bill.set_missing_address_from_default():
815 gmGuiHelpers.gm_show_warning (
816 aTitle = _('Creating invoice'),
817 aMessage = _(
818 'There is no pre-configured billing address.\n'
819 '\n'
820 'Select the address you want to send the bill to.'
821 )
822 )
823 edit_bill(parent = parent, bill = bill, single_entry = True)
824 if bill['pk_receiver_address'] is None:
825 return False
826 if bill['close_date'] is None:
827 bill['close_date'] = gmDateTime.pydt_now_here()
828 bill.save()
829
830 return create_invoice_from_bill(parent = parent, bill = bill, print_it = True, keep_a_copy = True)
831 #------------------------------------------------------------
832 def edit(bill):
833 return edit_bill(parent = parent, bill = bill, single_entry = True)
834 #------------------------------------------------------------
835 def delete(bill):
836 return delete_bill(parent = parent, bill = bill)
837 #------------------------------------------------------------
838 def remove_items(bill):
839 return remove_items_from_bill(parent = parent, bill = bill)
840 #------------------------------------------------------------
841 def get_tooltip(item):
842 if item is None:
843 return None
844 return item.format()
845 #------------------------------------------------------------
846 def refresh(lctrl):
847 if patient is None:
848 bills = gmBilling.get_bills()
849 else:
850 bills = gmBilling.get_bills(pk_patient = patient.ID)
851 items = []
852 for b in bills:
853 if b['close_date'] is None:
854 close_date = _('<open>')
855 else:
856 close_date = gmDateTime.pydt_strftime(b['close_date'], '%Y %b %d')
857 if b['total_amount'] is None:
858 amount = _('no items on bill')
859 else:
860 amount = gmTools.bool2subst (
861 b['apply_vat'],
862 _('%(currency)s%(total_amount_with_vat)s (with %(percent_vat)s%% VAT)') % b,
863 u'%(currency)s%(total_amount)s' % b
864 )
865 items.append ([
866 close_date,
867 b['invoice_id'],
868 amount,
869 gmTools.coalesce(b['comment'], u'')
870 ])
871 lctrl.set_string_items(items)
872 lctrl.set_data(bills)
873 #------------------------------------------------------------
874 return gmListWidgets.get_choices_from_list (
875 parent = parent,
876 caption = _('Showing bills.'),
877 columns = [_('Close date'), _('Invoice ID'), _('Value'), _('Comment')],
878 single_selection = True,
879 edit_callback = edit,
880 delete_callback = delete,
881 refresh_callback = refresh,
882 middle_extra_button = (
883 u'PDF',
884 _('Create if necessary, and show the corresponding invoice PDF'),
885 show_pdf
886 ),
887 right_extra_button = (
888 _('Unbill'),
889 _('Select and remove items from a bill.'),
890 remove_items
891 ),
892 list_tooltip_callback = get_tooltip
893 )
894
895 #----------------------------------------------------------------
896 from Gnumed.wxGladeWidgets import wxgBillEAPnl
897
899
901
902 try:
903 data = kwargs['bill']
904 del kwargs['bill']
905 except KeyError:
906 data = None
907
908 wxgBillEAPnl.wxgBillEAPnl.__init__(self, *args, **kwargs)
909 gmEditArea.cGenericEditAreaMixin.__init__(self)
910
911 self.mode = 'new'
912 self.data = data
913 if data is not None:
914 self.mode = 'edit'
915
916 # self.__init_ui()
917 #----------------------------------------------------------------
918 # def __init_ui(self):
919 #----------------------------------------------------------------
920 # generic Edit Area mixin API
921 #----------------------------------------------------------------
923 validity = True
924
925 # flag but do not count as wrong
926 if not self._PRW_close_date.is_valid_timestamp(allow_empty = False):
927 self._PRW_close_date.SetFocus()
928
929 return validity
930 #----------------------------------------------------------------
934 #----------------------------------------------------------------
936 self.data['close_date'] = self._PRW_close_date.GetData()
937 self.data['apply_vat'] = self._CHBOX_vat_applies.GetValue()
938 self.data['comment'] = self._TCTRL_comment.GetValue()
939 self.data.save()
940 return True
941 #----------------------------------------------------------------
944 #----------------------------------------------------------------
947 #----------------------------------------------------------------
949 self._TCTRL_invoice_id.SetValue(self.data['invoice_id'])
950 self._PRW_close_date.SetText(data = self.data['close_date'])
951
952 self.data.set_missing_address_from_default()
953 if self.data['pk_receiver_address'] is None:
954 self._TCTRL_address.SetValue(u'')
955 else:
956 adr = self.data.address
957 self._TCTRL_address.SetValue(adr.format(single_line = True, show_type = False))
958
959 self._TCTRL_value.SetValue(u'%(currency)s%(total_amount)s' % self.data)
960 self._CHBOX_vat_applies.SetValue(self.data['apply_vat'])
961 self._CHBOX_vat_applies.SetLabel(_('&VAT applies (%s%%)') % self.data['percent_vat'])
962 if self.data['apply_vat']:
963 tmp = u'%s %%(currency)s%%(total_vat)s %s %s %%(currency)s%%(total_amount_with_vat)s' % (
964 gmTools.u_corresponds_to,
965 gmTools.u_right_arrow,
966 gmTools.u_sum,
967 )
968 self._TCTRL_value_with_vat.SetValue(tmp % self.data)
969 else:
970 self._TCTRL_value_with_vat.SetValue(u'')
971
972 self._TCTRL_comment.SetValue(gmTools.coalesce(self.data['comment'], u''))
973
974 self._PRW_close_date.SetFocus()
975 #----------------------------------------------------------------
976 # event handling
977 #----------------------------------------------------------------
979 if self._CHBOX_vat_applies.GetValue():
980 tmp = u'%s %%(currency)s%%(total_vat)s %s %s %%(currency)s%%(total_amount_with_vat)s' % (
981 gmTools.u_corresponds_to,
982 gmTools.u_right_arrow,
983 gmTools.u_sum,
984 )
985 self._TCTRL_value_with_vat.SetValue(tmp % self.data)
986 return
987 self._TCTRL_value_with_vat.SetValue(u'')
988 #----------------------------------------------------------------
1003
1004 #================================================================
1005 # per-patient bill items related widgets
1006 #----------------------------------------------------------------
1008
1009 if bill_item is not None:
1010 if bill_item.is_in_use:
1011 gmDispatcher.send(signal = 'statustext', msg = _('Cannot edit already invoiced bill item.'), beep = True)
1012 return False
1013
1014 ea = cBillItemEAPnl(parent = parent, id = -1)
1015 ea.data = bill_item
1016 ea.mode = gmTools.coalesce(bill_item, 'new', 'edit')
1017 dlg = gmEditArea.cGenericEditAreaDlg2(parent = parent, id = -1, edit_area = ea, single_entry = single_entry)
1018 dlg.SetTitle(gmTools.coalesce(bill_item, _('Adding new bill item'), _('Editing bill item')))
1019 if dlg.ShowModal() == wx.ID_OK:
1020 dlg.Destroy()
1021 return True
1022 dlg.Destroy()
1023 return False
1024 #----------------------------------------------------------------
1026
1027 if parent is None:
1028 parent = wx.GetApp().GetTopWindow()
1029 #------------------------------------------------------------
1030 def edit(item=None):
1031 return edit_bill_item(parent = parent, bill_item = item, single_entry = (item is not None))
1032 #------------------------------------------------------------
1033 def delete(item):
1034 if item.is_in_use is not None:
1035 gmDispatcher.send(signal = 'statustext', msg = _('Cannot delete already invoiced bill items.'), beep = True)
1036 return False
1037 gmBilling.delete_bill_item(pk_bill_item = item['pk_bill_item'])
1038 return True
1039 #------------------------------------------------------------
1040 def get_tooltip(item):
1041 if item is None:
1042 return None
1043 return item.format()
1044 #------------------------------------------------------------
1045 def refresh(lctrl):
1046 b_items = gmBilling.get_bill_items(pk_patient = pk_patient)
1047 items = [ [
1048 gmDateTime.pydt_strftime(b['date_to_bill'], '%Y %b %d', accuracy = gmDateTime.acc_days),
1049 b['unit_count'],
1050 u'%s: %s%s' % (b['billable_code'], b['billable_description'], gmTools.coalesce(b['item_detail'], u'', u' - %s')),
1051 b['currency'],
1052 u'%s (%s %s %s%s%s)' % (
1053 b['total_amount'],
1054 b['unit_count'],
1055 gmTools.u_multiply,
1056 b['net_amount_per_unit'],
1057 gmTools.u_multiply,
1058 b['amount_multiplier']
1059 ),
1060 u'%s (%s%%)' % (
1061 b['vat'],
1062 b['vat_multiplier'] * 100
1063 ),
1064 u'%s (%s)' % (b['catalog_short'], b['catalog_version']),
1065 b['pk_bill_item']
1066 ] for b in b_items ]
1067 lctrl.set_string_items(items)
1068 lctrl.set_data(b_items)
1069 #------------------------------------------------------------
1070 gmListWidgets.get_choices_from_list (
1071 parent = parent,
1072 #msg = msg,
1073 caption = _('Showing bill items.'),
1074 columns = [_('Date'), _('Count'), _('Description'), _('$__replace_by_your_currency_symbol')[:-len('__replace_by_your_currency_symbol')], _('Value'), _('VAT'), _('Catalog'), u'#'],
1075 single_selection = True,
1076 new_callback = edit,
1077 edit_callback = edit,
1078 delete_callback = delete,
1079 refresh_callback = refresh,
1080 list_tooltip_callback = get_tooltip
1081 )
1082
1083 #------------------------------------------------------------
1085 """A list for managing a patient's bill items.
1086
1087 Does NOT act on/listen to the current patient.
1088 """
1090
1091 try:
1092 self.__identity = kwargs['identity']
1093 del kwargs['identity']
1094 except KeyError:
1095 self.__identity = None
1096
1097 gmListWidgets.cGenericListManagerPnl.__init__(self, *args, **kwargs)
1098
1099 self.new_callback = self._add_item
1100 self.edit_callback = self._edit_item
1101 self.delete_callback = self._del_item
1102 self.refresh_callback = self.refresh
1103
1104 self.__show_non_invoiced_only = True
1105
1106 self.__init_ui()
1107 self.refresh()
1108 #--------------------------------------------------------
1109 # external API
1110 #--------------------------------------------------------
1112 if self.__identity is None:
1113 self._LCTRL_items.set_string_items()
1114 return
1115
1116 b_items = gmBilling.get_bill_items(pk_patient = self.__identity.ID, non_invoiced_only = self.__show_non_invoiced_only)
1117 items = [ [
1118 gmDateTime.pydt_strftime(b['date_to_bill'], '%Y %b %d', accuracy = gmDateTime.acc_days),
1119 b['unit_count'],
1120 u'%s: %s%s' % (b['billable_code'], b['billable_description'], gmTools.coalesce(b['item_detail'], u'', u' - %s')),
1121 b['currency'],
1122 b['total_amount'],
1123 u'%s (%s%%)' % (
1124 b['vat'],
1125 b['vat_multiplier'] * 100
1126 ),
1127 u'%s (%s)' % (b['catalog_short'], b['catalog_version']),
1128 u'%s %s %s %s %s' % (
1129 b['unit_count'],
1130 gmTools.u_multiply,
1131 b['net_amount_per_unit'],
1132 gmTools.u_multiply,
1133 b['amount_multiplier']
1134 ),
1135 gmTools.coalesce(b['pk_bill'], gmTools.u_diameter),
1136 b['pk_encounter_to_bill'],
1137 b['pk_bill_item']
1138 ] for b in b_items ]
1139
1140 self._LCTRL_items.set_string_items(items = items)
1141 self._LCTRL_items.set_column_widths()
1142 self._LCTRL_items.set_data(data = b_items)
1143 #--------------------------------------------------------
1144 # internal helpers
1145 #--------------------------------------------------------
1147 self._LCTRL_items.set_columns(columns = [
1148 _('Charge date'),
1149 _('Count'),
1150 _('Description'),
1151 _('$__replace_by_your_currency_symbol')[:-len('__replace_by_your_currency_symbol')],
1152 _('Value'),
1153 _('VAT'),
1154 _('Catalog'),
1155 _('Count %s Value %s Factor') % (gmTools.u_multiply, gmTools.u_multiply),
1156 _('Invoice'),
1157 _('Encounter'),
1158 u'#'
1159 ])
1160 self._LCTRL_items.item_tooltip_callback = self._get_item_tooltip
1161 # self.left_extra_button = (
1162 # _('Select pending'),
1163 # _('Select non-invoiced (pending) items.'),
1164 # self._select_pending_items
1165 # )
1166 self.left_extra_button = (
1167 _('Invoice selected items'),
1168 _('Create invoice from selected items.'),
1169 self._invoice_selected_items
1170 )
1171 self.middle_extra_button = (
1172 _('Bills'),
1173 _('Browse bills of this patient.'),
1174 self._browse_bills
1175 )
1176 self.right_extra_button = (
1177 _('Billables'),
1178 _('Browse list of billables.'),
1179 self._browse_billables
1180 )
1181 #--------------------------------------------------------
1183 return edit_bill_item(parent = self, bill_item = None, single_entry = False)
1184 #--------------------------------------------------------
1186 return edit_bill_item(parent = self, bill_item = bill_item, single_entry = True)
1187 #--------------------------------------------------------
1189 if item['pk_bill'] is not None:
1190 gmDispatcher.send(signal = 'statustext', msg = _('Cannot delete already invoiced bill items.'), beep = True)
1191 return False
1192 go_ahead = gmGuiHelpers.gm_show_question (
1193 _( 'Do you really want to delete this\n'
1194 'bill item from the patient ?'),
1195 _('Deleting bill item')
1196 )
1197 if not go_ahead:
1198 return False
1199 gmBilling.delete_bill_item(pk_bill_item = item['pk_bill_item'])
1200 return True
1201 #--------------------------------------------------------
1206 #--------------------------------------------------------
1209 #--------------------------------------------------------
1211 bill_items = self._LCTRL_items.get_selected_item_data()
1212 bill = create_bill_from_items(bill_items)
1213 if bill is None:
1214 return
1215 if bill['pk_receiver_address'] is None:
1216 gmGuiHelpers.gm_show_error (
1217 aMessage = _(
1218 'Cannot create invoice.\n'
1219 '\n'
1220 'No receiver address selected.'
1221 ),
1222 aTitle = _('Creating invoice')
1223 )
1224 return
1225 if bill['close_date'] is None:
1226 bill['close_date'] = gmDateTime.pydt_now_here()
1227 bill.save()
1228 create_invoice_from_bill(parent = self, bill = bill, print_it = True, keep_a_copy = True)
1229 #--------------------------------------------------------
1233 #--------------------------------------------------------
1236 #--------------------------------------------------------
1237 # properties
1238 #--------------------------------------------------------
1241
1245
1246 identity = property(_get_identity, _set_identity)
1247 #--------------------------------------------------------
1250
1254
1255 show_non_invoiced_only = property(_get_show_non_invoiced_only, _set_show_non_invoiced_only)
1256
1257 #------------------------------------------------------------
1258 from Gnumed.wxGladeWidgets import wxgBillItemEAPnl
1259
1261
1263
1264 try:
1265 data = kwargs['bill_item']
1266 del kwargs['bill_item']
1267 except KeyError:
1268 data = None
1269
1270 wxgBillItemEAPnl.wxgBillItemEAPnl.__init__(self, *args, **kwargs)
1271 gmEditArea.cGenericEditAreaMixin.__init__(self)
1272
1273 self.mode = 'new'
1274 self.data = data
1275 if data is not None:
1276 self.mode = 'edit'
1277
1278 self.__init_ui()
1279 #----------------------------------------------------------------
1281 self._PRW_encounter.set_context(context = 'patient', val = gmPerson.gmCurrentPatient().ID)
1282 self._PRW_billable.add_callback_on_selection(self._on_billable_selected)
1283 #----------------------------------------------------------------
1284 # generic Edit Area mixin API
1285 #----------------------------------------------------------------
1287
1288 validity = True
1289
1290 if self._TCTRL_factor.GetValue().strip() == u'':
1291 validity = False
1292 self.display_tctrl_as_valid(tctrl = self._TCTRL_factor, valid = False)
1293 self._TCTRL_factor.SetFocus()
1294 else:
1295 converted, factor = gmTools.input2decimal(self._TCTRL_factor.GetValue())
1296 if not converted:
1297 validity = False
1298 self.display_tctrl_as_valid(tctrl = self._TCTRL_factor, valid = False)
1299 self._TCTRL_factor.SetFocus()
1300 else:
1301 self.display_tctrl_as_valid(tctrl = self._TCTRL_factor, valid = True)
1302
1303 if self._TCTRL_amount.GetValue().strip() == u'':
1304 validity = False
1305 self.display_tctrl_as_valid(tctrl = self._TCTRL_amount, valid = False)
1306 self._TCTRL_amount.SetFocus()
1307 else:
1308 converted, factor = gmTools.input2decimal(self._TCTRL_amount.GetValue())
1309 if not converted:
1310 validity = False
1311 self.display_tctrl_as_valid(tctrl = self._TCTRL_amount, valid = False)
1312 self._TCTRL_amount.SetFocus()
1313 else:
1314 self.display_tctrl_as_valid(tctrl = self._TCTRL_amount, valid = True)
1315
1316 if self._TCTRL_count.GetValue().strip() == u'':
1317 validity = False
1318 self.display_tctrl_as_valid(tctrl = self._TCTRL_count, valid = False)
1319 self._TCTRL_count.SetFocus()
1320 else:
1321 converted, factor = gmTools.input2decimal(self._TCTRL_count.GetValue())
1322 if not converted:
1323 validity = False
1324 self.display_tctrl_as_valid(tctrl = self._TCTRL_count, valid = False)
1325 self._TCTRL_count.SetFocus()
1326 else:
1327 self.display_tctrl_as_valid(tctrl = self._TCTRL_count, valid = True)
1328
1329 if self._PRW_date.is_valid_timestamp(allow_empty = True):
1330 self._PRW_date.display_as_valid(True)
1331 else:
1332 validity = False
1333 self._PRW_date.display_as_valid(False)
1334 self._PRW_date.SetFocus()
1335
1336 if self._PRW_encounter.GetData() is None:
1337 validity = False
1338 self._PRW_encounter.display_as_valid(False)
1339 self._PRW_encounter.SetFocus()
1340 else:
1341 self._PRW_encounter.display_as_valid(True)
1342
1343 if self._PRW_billable.GetData() is None:
1344 validity = False
1345 self._PRW_billable.display_as_valid(False)
1346 self._PRW_billable.SetFocus()
1347 else:
1348 self._PRW_billable.display_as_valid(True)
1349
1350 return validity
1351 #----------------------------------------------------------------
1353 data = gmBilling.create_bill_item (
1354 pk_encounter = self._PRW_encounter.GetData(),
1355 pk_billable = self._PRW_billable.GetData(),
1356 pk_staff = gmStaff.gmCurrentProvider()['pk_staff'] # should be settable !
1357 )
1358 data['raw_date_to_bill'] = self._PRW_date.GetData()
1359 converted, data['unit_count'] = gmTools.input2decimal(self._TCTRL_count.GetValue())
1360 converted, data['net_amount_per_unit'] = gmTools.input2decimal(self._TCTRL_amount.GetValue())
1361 converted, data['amount_multiplier'] = gmTools.input2decimal(self._TCTRL_factor.GetValue())
1362 data['item_detail'] = self._TCTRL_comment.GetValue().strip()
1363 data.save()
1364
1365 self.data = data
1366 return True
1367 #----------------------------------------------------------------
1369 self.data['pk_encounter_to_bill'] = self._PRW_encounter.GetData()
1370 self.data['raw_date_to_bill'] = self._PRW_date.GetData()
1371 converted, self.data['unit_count'] = gmTools.input2decimal(self._TCTRL_count.GetValue())
1372 converted, self.data['net_amount_per_unit'] = gmTools.input2decimal(self._TCTRL_amount.GetValue())
1373 converted, self.data['amount_multiplier'] = gmTools.input2decimal(self._TCTRL_factor.GetValue())
1374 self.data['item_detail'] = self._TCTRL_comment.GetValue().strip()
1375 return self.data.save()
1376 #----------------------------------------------------------------
1378 self._PRW_billable.SetText()
1379 self._PRW_encounter.set_from_instance(gmPerson.gmCurrentPatient().emr.active_encounter)
1380 self._PRW_date.SetData()
1381 self._TCTRL_count.SetValue(u'1')
1382 self._TCTRL_amount.SetValue(u'')
1383 self._LBL_currency.SetLabel(gmTools.u_euro)
1384 self._TCTRL_factor.SetValue(u'1')
1385 self._TCTRL_comment.SetValue(u'')
1386
1387 self._PRW_billable.Enable()
1388 self._PRW_billable.SetFocus()
1389 #----------------------------------------------------------------
1391 self._PRW_billable.SetText()
1392 self._TCTRL_count.SetValue(u'1')
1393 self._TCTRL_amount.SetValue(u'')
1394 self._TCTRL_comment.SetValue(u'')
1395
1396 self._PRW_billable.Enable()
1397 self._PRW_billable.SetFocus()
1398 #----------------------------------------------------------------
1400 self._PRW_billable.set_from_pk(self.data['pk_billable'])
1401 self._PRW_encounter.SetData(self.data['pk_encounter_to_bill'])
1402 self._PRW_date.SetData(data = self.data['raw_date_to_bill'])
1403 self._TCTRL_count.SetValue(u'%s' % self.data['unit_count'])
1404 self._TCTRL_amount.SetValue(u'%s' % self.data['net_amount_per_unit'])
1405 self._LBL_currency.SetLabel(self.data['currency'])
1406 self._TCTRL_factor.SetValue(u'%s' % self.data['amount_multiplier'])
1407 self._TCTRL_comment.SetValue(gmTools.coalesce(self.data['item_detail'], u''))
1408
1409 self._PRW_billable.Disable()
1410 self._PRW_date.SetFocus()
1411 #----------------------------------------------------------------
1419
1420 #============================================================
1421 # a plugin for billing
1422 #------------------------------------------------------------
1423 from Gnumed.wxGladeWidgets import wxgBillingPluginPnl
1424
1425 -class cBillingPluginPnl(wxgBillingPluginPnl.wxgBillingPluginPnl, gmRegetMixin.cRegetOnPaintMixin):
1427
1428 wxgBillingPluginPnl.wxgBillingPluginPnl.__init__(self, *args, **kwargs)
1429 gmRegetMixin.cRegetOnPaintMixin.__init__(self)
1430 self.__register_interests()
1431 #-----------------------------------------------------
1433 self._PNL_bill_items.identity = None
1434 self._CHBOX_show_non_invoiced_only.SetValue(1)
1435 self._PRW_billable.SetText(u'', None)
1436 self._TCTRL_factor.SetValue(u'1.0')
1437 self._TCTRL_factor.Disable()
1438 self._TCTRL_details.SetValue(u'')
1439 self._TCTRL_details.Disable()
1440 #-----------------------------------------------------
1441 # event handling
1442 #-----------------------------------------------------
1444 gmDispatcher.connect(signal = u'pre_patient_selection', receiver = self._on_pre_patient_selection)
1445 gmDispatcher.connect(signal = u'post_patient_selection', receiver = self._on_post_patient_selection)
1446
1447 gmDispatcher.connect(signal = u'bill.bill_item_mod_db', receiver = self._on_bill_item_modified)
1448
1449 self._PRW_billable.add_callback_on_selection(self._on_billable_selected_in_prw)
1450 #-----------------------------------------------------
1453 #-----------------------------------------------------
1456 #-----------------------------------------------------
1459 #-----------------------------------------------------
1462 #--------------------------------------------------------
1487 #--------------------------------------------------------
1489 if billable is None:
1490 self._TCTRL_factor.Disable()
1491 self._TCTRL_details.Disable()
1492 self._BTN_insert_item.Disable()
1493 else:
1494 self._TCTRL_factor.Enable()
1495 self._TCTRL_details.Enable()
1496 self._BTN_insert_item.Enable()
1497 #-----------------------------------------------------
1498 # reget-on-paint mixin API
1499 #-----------------------------------------------------
1503 #============================================================
1504 # main
1505 #------------------------------------------------------------
1506 if __name__ == '__main__':
1507
1508 if len(sys.argv) < 2:
1509 sys.exit()
1510
1511 if sys.argv[1] != 'test':
1512 sys.exit()
1513
1514 from Gnumed.pycommon import gmI18N
1515 gmI18N.activate_locale()
1516 gmI18N.install_domain(domain = 'gnumed')
1517
1518 #----------------------------------------
1519 app = wx.PyWidgetTester(size = (600, 600))
1520 #app.SetWidget(cATCPhraseWheel, -1)
1521 #app.SetWidget(cSubstancePhraseWheel, -1)
1522 app.MainLoop()
1523
| Home | Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0.1 on Sat Oct 5 03:56:25 2013 | http://epydoc.sourceforge.net |