| Home | Trees | Indices | Help |
|
|---|
|
|
1 # -*- coding: utf-8 -*-
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, -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 '%(currency)s%(raw_amount)s' % b,
94 '%s (%s)' % (b['catalog_short'], b['catalog_version']),
95 gmTools.coalesce(b['comment'], ''),
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 = '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'), '#'],
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 = """
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 = list(self._data.values())[0]['data'])
177 return billable.format()
178 #------------------------------------------------------------
180 val = '%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 self.mode = 'new'
207 self.data = data
208 if data is not None:
209 self.mode = 'edit'
210
211 #self.__init_ui()
212 #----------------------------------------------------------------
213 # def __init_ui(self):
214 # # adjust phrasewheels etc
215 #----------------------------------------------------------------
216 # generic Edit Area mixin API
217 #----------------------------------------------------------------
219
220 validity = True
221
222 vat = self._TCTRL_vat.GetValue().strip()
223 if vat == '':
224 self.display_tctrl_as_valid(tctrl = self._TCTRL_vat, valid = True)
225 else:
226 success, vat = gmTools.input2decimal(initial = vat)
227 if success:
228 self.display_tctrl_as_valid(tctrl = self._TCTRL_vat, valid = True)
229 else:
230 validity = False
231 self.display_tctrl_as_valid(tctrl = self._TCTRL_vat, valid = False)
232 self.status_message = _('VAT must be empty or a number.')
233 self._TCTRL_vat.SetFocus()
234
235 currency = self._TCTRL_currency.GetValue().strip()
236 if currency == '':
237 validity = False
238 self.display_tctrl_as_valid(tctrl = self._TCTRL_currency, valid = False)
239 self.status_message = _('Currency is missing.')
240 self._TCTRL_currency.SetFocus()
241 else:
242 self.display_tctrl_as_valid(tctrl = self._TCTRL_currency, valid = True)
243
244 success, val = gmTools.input2decimal(initial = self._TCTRL_amount.GetValue())
245 if success:
246 self.display_tctrl_as_valid(tctrl = self._TCTRL_amount, valid = True)
247 else:
248 validity = False
249 self.display_tctrl_as_valid(tctrl = self._TCTRL_amount, valid = False)
250 self.status_message = _('Value is missing.')
251 self._TCTRL_amount.SetFocus()
252
253 if self._TCTRL_description.GetValue().strip() == '':
254 validity = False
255 self.display_tctrl_as_valid(tctrl = self._TCTRL_description, valid = False)
256 self.status_message = _('Description is missing.')
257 self._TCTRL_description.SetFocus()
258 else:
259 self.display_tctrl_as_valid(tctrl = self._TCTRL_description, valid = True)
260
261 if self._PRW_coding_system.GetData() is None:
262 validity = False
263 self._PRW_coding_system.display_as_valid(False)
264 self.status_message = _('Coding system is missing.')
265 self._PRW_coding_system.SetFocus()
266 else:
267 self._PRW_coding_system.display_as_valid(True)
268
269 if self._TCTRL_code.GetValue().strip() == '':
270 validity = False
271 self.display_tctrl_as_valid(tctrl = self._TCTRL_code, valid = False)
272 self.status_message = _('Code is missing.')
273 self._TCTRL_code.SetFocus()
274 else:
275 self.display_tctrl_as_valid(tctrl = self._TCTRL_code, valid = True)
276
277 return validity
278 #----------------------------------------------------------------
280 data = gmBilling.create_billable (
281 code = self._TCTRL_code.GetValue().strip(),
282 term = self._TCTRL_description.GetValue().strip(),
283 data_source = self._PRW_coding_system.GetData(),
284 return_existing = False
285 )
286 if data is None:
287 self.status_message = _('Billable already exists.')
288 return False
289
290 val = self._TCTRL_amount.GetValue().strip()
291 if val != '':
292 tmp, val = gmTools.input2decimal(val)
293 data['raw_amount'] = val
294 val = self._TCTRL_currency.GetValue().strip()
295 if val != '':
296 data['currency'] = val
297 vat = self._TCTRL_vat.GetValue().strip()
298 if vat != '':
299 tmp, vat = gmTools.input2decimal(vat)
300 data['vat_multiplier'] = vat / 100
301 data['comment'] = self._TCTRL_comment.GetValue().strip()
302 data['active'] = self._CHBOX_active.GetValue()
303
304 data.save()
305
306 self.data = data
307
308 return True
309 #----------------------------------------------------------------
311 self.data['billable_description'] = self._TCTRL_description.GetValue().strip()
312 tmp, self.data['raw_amount'] = gmTools.input2decimal(self._TCTRL_amount.GetValue())
313 self.data['currency'] = self._TCTRL_currency.GetValue().strip()
314 vat = self._TCTRL_vat.GetValue().strip()
315 if vat == '':
316 vat = 0
317 else:
318 tmp, vat = gmTools.input2decimal(vat)
319 self.data['vat_multiplier'] = vat / 100
320 self.data['comment'] = self._TCTRL_comment.GetValue().strip()
321 self.data['active'] = self._CHBOX_active.GetValue()
322 self.data.save()
323 return True
324 #----------------------------------------------------------------
326 self._TCTRL_code.SetValue('')
327 self._PRW_coding_system.SetText('', None)
328 self._TCTRL_description.SetValue('')
329 self._TCTRL_amount.SetValue('')
330 self._TCTRL_currency.SetValue('')
331 self._TCTRL_vat.SetValue('')
332 self._TCTRL_comment.SetValue('')
333 self._CHBOX_active.SetValue(True)
334
335 self._TCTRL_code.SetFocus()
336 #----------------------------------------------------------------
339 #----------------------------------------------------------------
341 self._TCTRL_code.SetValue(self.data['billable_code'])
342 self._TCTRL_code.Enable(False)
343 self._PRW_coding_system.SetText('%s (%s)' % (self.data['catalog_short'], self.data['catalog_version']), self.data['pk_data_source'])
344 self._PRW_coding_system.Enable(False)
345 self._TCTRL_description.SetValue(self.data['billable_description'])
346 self._TCTRL_amount.SetValue('%s' % self.data['raw_amount'])
347 self._TCTRL_currency.SetValue(self.data['currency'])
348 self._TCTRL_vat.SetValue('%s' % (self.data['vat_multiplier'] * 100))
349 self._TCTRL_comment.SetValue(gmTools.coalesce(self.data['comment'], ''))
350 self._CHBOX_active.SetValue(self.data['active'])
351
352 self._TCTRL_description.SetFocus()
353 #----------------------------------------------------------------
354
355 #================================================================
356 # invoice related widgets
357 #----------------------------------------------------------------
359
360 if parent is None:
361 parent = wx.GetApp().GetTopWindow()
362
363 template = gmFormWidgets.manage_form_templates (
364 parent = parent,
365 template_types = ['invoice']
366 )
367
368 if template is None:
369 gmDispatcher.send(signal = 'statustext', msg = _('No invoice template configured.'), beep = True)
370 return None
371
372 if template['engine'] not in ['L', 'X']:
373 gmDispatcher.send(signal = 'statustext', msg = _('No invoice template configured.'), beep = True)
374 return None
375
376 if with_vat:
377 option = 'form_templates.invoice_with_vat'
378 else:
379 option = 'form_templates.invoice_no_vat'
380
381 dbcfg = gmCfg.cCfgSQL()
382 dbcfg.set (
383 workplace = gmPraxis.gmCurrentPraxisBranch().active_workplace,
384 option = option,
385 value = '%s - %s' % (template['name_long'], template['external_version'])
386 )
387
388 return template
389 #----------------------------------------------------------------
391
392 dbcfg = gmCfg.cCfgSQL()
393 if with_vat:
394 option = 'form_templates.invoice_with_vat'
395 else:
396 option = 'form_templates.invoice_no_vat'
397
398 template = dbcfg.get2 (
399 option = option,
400 workplace = gmPraxis.gmCurrentPraxisBranch().active_workplace,
401 bias = 'user'
402 )
403
404 if template is None:
405 template = configure_invoice_template(parent = parent, with_vat = with_vat)
406 if template is None:
407 gmGuiHelpers.gm_show_error (
408 aMessage = _('There is no invoice template configured.'),
409 aTitle = _('Getting invoice template')
410 )
411 return None
412 else:
413 try:
414 name, ver = template.split(' - ')
415 except:
416 _log.exception('problem splitting invoice template name [%s]', template)
417 gmDispatcher.send(signal = 'statustext', msg = _('Problem loading invoice template.'), beep = True)
418 return None
419 template = gmForms.get_form_template(name_long = name, external_version = ver)
420 if template is None:
421 gmGuiHelpers.gm_show_error (
422 aMessage = _('Cannot load invoice template [%s - %s]') % (name, ver),
423 aTitle = _('Getting invoice template')
424 )
425 return None
426
427 return template
428
429 #================================================================
430 # per-patient bill related widgets
431 #----------------------------------------------------------------
433
434 if bill is None:
435 # manually creating bills is not yet supported
436 return
437
438 ea = cBillEAPnl(parent, -1)
439 ea.data = bill
440 ea.mode = gmTools.coalesce(bill, 'new', 'edit')
441 dlg = gmEditArea.cGenericEditAreaDlg2(parent, -1, edit_area = ea, single_entry = single_entry)
442 dlg.SetTitle(gmTools.coalesce(bill, _('Adding new bill'), _('Editing bill')))
443 if dlg.ShowModal() == wx.ID_OK:
444 dlg.Destroy()
445 return True
446 dlg.Destroy()
447 return False
448 #----------------------------------------------------------------
450
451 if len(bill_items) == 0:
452 return None
453
454 item = bill_items[0]
455 currency = item['currency']
456 vat = item['vat_multiplier']
457 pat = item['pk_patient']
458
459 # check item consistency
460 has_errors = False
461 for item in bill_items:
462 if (item['currency'] != currency) or (
463 item['vat_multiplier'] != vat) or (
464 item['pk_patient'] != pat
465 ):
466 msg = _(
467 'All items to be included with a bill must\n'
468 'coincide on currency, VAT, and patient.\n'
469 '\n'
470 'This item does not:\n'
471 '\n'
472 '%s\n'
473 ) % item.format()
474 has_errors = True
475
476 if item['pk_bill'] is not None:
477 msg = _(
478 'This item is already invoiced:\n'
479 '\n'
480 '%s\n'
481 '\n'
482 'Cannot put it on a second bill.'
483 ) % item.format()
484 has_errors = True
485
486 if has_errors:
487 gmGuiHelpers.gm_show_warning(aTitle = _('Checking invoice items'), aMessage = msg)
488 return None
489
490 # create bill
491 bill = gmBilling.create_bill(invoice_id = gmBilling.get_invoice_id(pk_patient = pat))
492 _log.info('created bill [%s]', bill['invoice_id'])
493 bill.add_items(items = bill_items)
494 bill.set_missing_address_from_default()
495
496 return bill
497
498 #----------------------------------------------------------------
500
501 bill_patient_not_active = False
502 # do we have a current patient ?
503 curr_pat = gmPerson.gmCurrentPatient()
504 if curr_pat.connected:
505 # is the bill about the current patient, too ?
506 # (because that's what the new invoice would get
507 # created for and attached to)
508 if curr_pat.ID != bill['pk_patient']:
509 bill_patient_not_active = True
510 else:
511 bill_patient_not_active = True
512
513 # FIXME: could ask whether to set fk_receiver_identity
514 # FIXME: but this would need enabling the bill EA to edit same
515 if bill_patient_not_active:
516 activate_patient = gmGuiHelpers.gm_show_question (
517 title = _('Creating invoice'),
518 question = _(
519 'Cannot find an existing invoice PDF for this bill.\n'
520 '\n'
521 'Active patient: %s\n'
522 'Patient on bill: #%s\n'
523 '\n'
524 'Activate patient on bill so invoice PDF can be created ?'
525 ) % (
526 gmTools.coalesce(curr_pat.ID, '', '#%s'),
527 bill['pk_patient']
528 )
529 )
530 if not activate_patient:
531 return False
532 if not gmPatSearchWidgets.set_active_patient(patient = bill['pk_patient']):
533 gmGuiHelpers.gm_show_error (
534 aTitle = _('Creating invoice'),
535 aMessage = _('Cannot activate patient #%s.') % bill['pk_patient']
536 )
537 return False
538
539 if None in [ bill['close_date'], bill['pk_receiver_address'], bill['apply_vat'] ]:
540 edit_bill(parent = parent, bill = bill, single_entry = True)
541 # cannot invoice open bills
542 if bill['close_date'] is None:
543 _log.error('cannot create invoice from bill, bill not closed')
544 gmGuiHelpers.gm_show_warning (
545 aTitle = _('Creating invoice'),
546 aMessage = _(
547 'Cannot create invoice from bill.\n'
548 '\n'
549 'The bill is not closed.'
550 )
551 )
552 return False
553 # cannot create invoice if no receiver address
554 if bill['pk_receiver_address'] is None:
555 _log.error('cannot create invoice from bill, lacking receiver address')
556 gmGuiHelpers.gm_show_warning (
557 aTitle = _('Creating invoice'),
558 aMessage = _(
559 'Cannot create invoice from bill.\n'
560 '\n'
561 'There is no receiver address.'
562 )
563 )
564 return False
565 # cannot create invoice if applying VAT is undecided
566 if bill['apply_vat'] is None:
567 _log.error('cannot create invoice from bill, apply_vat undecided')
568 gmGuiHelpers.gm_show_warning (
569 aTitle = _('Creating invoice'),
570 aMessage = _(
571 'Cannot create invoice from bill.\n'
572 '\n'
573 'You must decide on whether to apply VAT.'
574 )
575 )
576 return False
577
578 # find template
579 template = get_invoice_template(parent = parent, with_vat = bill['apply_vat'])
580 if template is None:
581 gmGuiHelpers.gm_show_warning (
582 aTitle = _('Creating invoice'),
583 aMessage = _(
584 'Cannot create invoice from bill\n'
585 'without an invoice template.'
586 )
587 )
588 return False
589
590 # process template
591 try:
592 invoice = template.instantiate()
593 except KeyError:
594 _log.exception('cannot instantiate invoice template [%s]', template)
595 gmGuiHelpers.gm_show_error (
596 aMessage = _('Invalid invoice template [%s - %s (%s)]') % (name, ver, template['engine']),
597 aTitle = _('Printing medication list')
598 )
599 return False
600
601 ph = gmMacro.gmPlaceholderHandler()
602 #ph.debug = True
603 ph.set_cache_value('bill', bill)
604 invoice.substitute_placeholders(data_source = ph)
605 ph.unset_cache_value('bill')
606 pdf_name = invoice.generate_output()
607 if pdf_name is None:
608 gmGuiHelpers.gm_show_error (
609 aMessage = _('Error generating invoice PDF.'),
610 aTitle = _('Creating invoice')
611 )
612 return False
613
614 # keep a copy
615 if keep_a_copy:
616 files2import = []
617 files2import.extend(invoice.final_output_filenames)
618 files2import.extend(invoice.re_editable_filenames)
619 doc = gmDocumentWidgets.save_files_as_new_document (
620 parent = parent,
621 filenames = files2import,
622 document_type = template['instance_type'],
623 review_as_normal = True,
624 reference = bill['invoice_id'],
625 pk_org_unit = gmPraxis.gmCurrentPraxisBranch()['pk_org_unit']
626 )
627 bill['pk_doc'] = doc['pk_doc']
628 bill.save()
629
630 if not print_it:
631 return True
632
633 # print template
634 printed = gmPrinting.print_files(filenames = [pdf_name], jobtype = 'invoice')
635 if not printed:
636 gmGuiHelpers.gm_show_error (
637 aMessage = _('Error printing the invoice.'),
638 aTitle = _('Printing invoice')
639 )
640 return True
641
642 return True
643
644 #----------------------------------------------------------------
646
647 if parent is None:
648 parent = wx.GetApp().GetTopWindow()
649
650 dlg = gmGuiHelpers.c3ButtonQuestionDlg (
651 parent, -1,
652 caption = _('Deleting bill'),
653 question = _(
654 'When deleting the bill [%s]\n'
655 'do you want to keep its items (effectively \"unbilling\" them)\n'
656 'or do you want to also delete the bill items from the patient ?\n'
657 ) % bill['invoice_id'],
658 button_defs = [
659 {'label': _('Delete + keep'), 'tooltip': _('Delete the bill but keep ("unbill") its items.'), 'default': True},
660 {'label': _('Delete all'), 'tooltip': _('Delete both the bill and its items from the patient.')}
661 ],
662 show_checkbox = True,
663 checkbox_msg = _('Also remove invoice PDF'),
664 checkbox_tooltip = _('Also remove the invoice PDF from the document archive (because it will not correspond to the bill anymore).')
665 )
666 button_pressed = dlg.ShowModal()
667 delete_invoice = dlg.checkbox_is_checked()
668 dlg.Destroy()
669
670 if button_pressed == wx.ID_CANCEL:
671 return False
672
673 delete_items = (button_pressed == wx.ID_NO)
674
675 if delete_invoice:
676 if bill['pk_doc'] is not None:
677 gmDocuments.delete_document (
678 document_id = bill['pk_doc'],
679 encounter_id = gmPerson.cPatient(aPK_obj = bill['pk_patient']).emr.active_encounter['pk_encounter']
680 )
681
682 items = bill['pk_bill_items']
683 success = gmBilling.delete_bill(pk_bill = bill['pk_bill'])
684 if delete_items:
685 for item in items:
686 gmBilling.delete_bill_item(pk_bill_item = item)
687
688 return success
689
690 #----------------------------------------------------------------
692
693 if bill is None:
694 return False
695
696 list_data = bill.bill_items
697 if len(list_data) == 0:
698 return False
699
700 if parent is None:
701 parent = wx.GetApp().GetTopWindow()
702
703 list_items = [ [
704 gmDateTime.pydt_strftime(b['date_to_bill'], '%Y %b %d', accuracy = gmDateTime.acc_days),
705 b['unit_count'],
706 '%s: %s%s' % (b['billable_code'], b['billable_description'], gmTools.coalesce(b['item_detail'], '', ' - %s')),
707 '%(curr)s %(total_val)s (%(count)s %(x)s %(unit_val)s%(x)s%(val_multiplier)s)' % {
708 'curr': b['currency'],
709 'total_val': b['total_amount'],
710 'count': b['unit_count'],
711 'x': gmTools.u_multiply,
712 'unit_val': b['net_amount_per_unit'],
713 'val_multiplier': b['amount_multiplier']
714 },
715 '%(curr)s%(vat)s (%(perc_vat)s%%)' % {
716 'vat': b['vat'],
717 'curr': b['currency'],
718 'perc_vat': b['vat_multiplier'] * 100
719 },
720 '%s (%s)' % (b['catalog_short'], b['catalog_version']),
721 b['pk_bill_item']
722 ] for b in list_data ]
723
724 msg = _('Select the items you want to remove from bill [%s]:\n') % bill['invoice_id']
725 items2remove = gmListWidgets.get_choices_from_list (
726 parent = parent,
727 msg = msg,
728 caption = _('Removing items from bill'),
729 columns = [_('Date'), _('Count'), _('Description'), _('Value'), _('VAT'), _('Catalog'), '#'],
730 single_selection = False,
731 choices = list_items,
732 data = list_data
733 )
734
735 if items2remove is None:
736 return False
737
738 if len(items2remove) == len(list_items):
739 gmGuiHelpers.gm_show_info (
740 title = _('Removing items from bill'),
741 info = _(
742 'Cannot remove all items from a bill because\n'
743 'GNUmed does not support empty bills.\n'
744 '\n'
745 'You must delete the bill itself if you want to\n'
746 'remove all items (at which point you can opt to\n'
747 'keep the items and only delete the bill).'
748 )
749 )
750 return False
751
752 dlg = gmGuiHelpers.c3ButtonQuestionDlg (
753 parent, -1,
754 caption = _('Removing items from bill'),
755 question = _(
756 '%s items selected from bill [%s]\n'
757 '\n'
758 'Do you want to only remove the selected items\n'
759 'from the bill ("unbill" them) or do you want\n'
760 'to delete them entirely from the patient ?\n'
761 '\n'
762 'Note that neither action is reversible.'
763 ) % (
764 len(items2remove),
765 bill['invoice_id']
766 ),
767 button_defs = [
768 {'label': _('"Unbill"'), 'tooltip': _('Only "unbill" items (remove from bill but do not delete from patient).'), 'default': True},
769 {'label': _('Delete'), 'tooltip': _('Completely delete items from the patient.')}
770 ],
771 show_checkbox = True,
772 checkbox_msg = _('Also remove invoice PDF'),
773 checkbox_tooltip = _('Also remove the invoice PDF from the document archive (because it will not correspond to the bill anymore).')
774 )
775 button_pressed = dlg.ShowModal()
776 delete_invoice = dlg.checkbox_is_checked()
777 dlg.Destroy()
778
779 if button_pressed == wx.ID_CANCEL:
780 return False
781
782 # remember this because unlinking/deleting the items
783 # will remove the patient PK from the bill
784 pk_patient = bill['pk_patient']
785
786 for item in items2remove:
787 item['pk_bill'] = None
788 item.save()
789 if button_pressed == wx.ID_NO:
790 gmBilling.delete_bill_item(pk_bill_item = item['pk_bill_item'])
791
792 if delete_invoice:
793 if bill['pk_doc'] is not None:
794 gmDocuments.delete_document (
795 document_id = bill['pk_doc'],
796 encounter_id = gmPerson.cPatient(aPK_obj = pk_patient).emr.active_encounter['pk_encounter']
797 )
798
799 # delete bill, too, if empty
800 if len(bill.bill_items) == 0:
801 gmBilling.delete_bill(pk_bill = bill['pk_bill'])
802
803 return True
804
805 #----------------------------------------------------------------
807
808 if parent is None:
809 parent = wx.GetApp().GetTopWindow()
810
811 #------------------------------------------------------------
812 def show_pdf(bill):
813 if bill is None:
814 return False
815
816 # find invoice
817 invoice = bill.invoice
818 if invoice is not None:
819 success, msg = invoice.parts[-1].display_via_mime()
820 if not success:
821 gmGuiHelpers.gm_show_error(aMessage = msg, aTitle = _('Displaying invoice'))
822 return False
823
824 # create it ?
825 create_it = gmGuiHelpers.gm_show_question (
826 title = _('Displaying invoice'),
827 question = _(
828 'Cannot find an existing\n'
829 'invoice PDF for this bill.\n'
830 '\n'
831 'Do you want to create one ?'
832 ),
833 )
834 if not create_it:
835 return False
836
837 # prepare invoicing
838 if not bill.set_missing_address_from_default():
839 gmGuiHelpers.gm_show_warning (
840 aTitle = _('Creating invoice'),
841 aMessage = _(
842 'There is no pre-configured billing address.\n'
843 '\n'
844 'Select the address you want to send the bill to.'
845 )
846 )
847 edit_bill(parent = parent, bill = bill, single_entry = True)
848 if bill['pk_receiver_address'] is None:
849 return False
850 if bill['close_date'] is None:
851 bill['close_date'] = gmDateTime.pydt_now_here()
852 bill.save()
853
854 return create_invoice_from_bill(parent = parent, bill = bill, print_it = True, keep_a_copy = True)
855 #------------------------------------------------------------
856 def edit(bill):
857 return edit_bill(parent = parent, bill = bill, single_entry = True)
858 #------------------------------------------------------------
859 def delete(bill):
860 return delete_bill(parent = parent, bill = bill)
861 #------------------------------------------------------------
862 def remove_items(bill):
863 return remove_items_from_bill(parent = parent, bill = bill)
864 #------------------------------------------------------------
865 def get_tooltip(item):
866 if item is None:
867 return None
868 return item.format()
869 #------------------------------------------------------------
870 def refresh(lctrl):
871 if patient is None:
872 bills = gmBilling.get_bills()
873 else:
874 bills = gmBilling.get_bills(pk_patient = patient.ID)
875 items = []
876 for b in bills:
877 if b['close_date'] is None:
878 close_date = _('<open>')
879 else:
880 close_date = gmDateTime.pydt_strftime(b['close_date'], '%Y %b %d')
881 if b['total_amount'] is None:
882 amount = _('no items on bill')
883 else:
884 amount = gmTools.bool2subst (
885 b['apply_vat'],
886 _('%(currency)s%(total_amount_with_vat)s (with %(percent_vat)s%% VAT)') % b,
887 '%(currency)s%(total_amount)s' % b,
888 _('without VAT: %(currency)s%(total_amount)s / with %(percent_vat)s%% VAT: %(currency)s%(total_amount_with_vat)s') % b
889 )
890 items.append ([
891 close_date,
892 b['invoice_id'],
893 amount,
894 gmTools.coalesce(b['comment'], '')
895 ])
896 lctrl.set_string_items(items)
897 lctrl.set_data(bills)
898 #------------------------------------------------------------
899 return gmListWidgets.get_choices_from_list (
900 parent = parent,
901 caption = _('Showing bills.'),
902 columns = [_('Close date'), _('Invoice ID'), _('Value'), _('Comment')],
903 single_selection = True,
904 edit_callback = edit,
905 delete_callback = delete,
906 refresh_callback = refresh,
907 middle_extra_button = (
908 'PDF',
909 _('Create if necessary, and show the corresponding invoice PDF'),
910 show_pdf
911 ),
912 right_extra_button = (
913 _('Unbill'),
914 _('Select and remove items from a bill.'),
915 remove_items
916 ),
917 list_tooltip_callback = get_tooltip
918 )
919
920 #----------------------------------------------------------------
921 from Gnumed.wxGladeWidgets import wxgBillEAPnl
922
924
926
927 try:
928 data = kwargs['bill']
929 del kwargs['bill']
930 except KeyError:
931 data = None
932
933 wxgBillEAPnl.wxgBillEAPnl.__init__(self, *args, **kwargs)
934 gmEditArea.cGenericEditAreaMixin.__init__(self)
935
936 self.mode = 'new'
937 self.data = data
938 if data is not None:
939 self.mode = 'edit'
940
941 self._3state2bool = {
942 wx.CHK_UNCHECKED: False,
943 wx.CHK_CHECKED: True,
944 wx.CHK_UNDETERMINED: None
945 }
946 self.bool_to_3state = {
947 False: wx.CHK_UNCHECKED,
948 True: wx.CHK_CHECKED,
949 None: wx.CHK_UNDETERMINED
950 }
951
952 # self.__init_ui()
953 #----------------------------------------------------------------
954 # def __init_ui(self):
955 #----------------------------------------------------------------
956 # generic Edit Area mixin API
957 #----------------------------------------------------------------
959 validity = True
960
961 # flag but do not count as wrong
962 if not self._PRW_close_date.is_valid_timestamp(allow_empty = False):
963 self._PRW_close_date.SetFocus()
964
965 # flag but do not count as wrong
966 if self._CHBOX_vat_applies.ThreeStateValue == wx.CHK_UNDETERMINED:
967 self._CHBOX_vat_applies.SetFocus()
968 self._CHBOX_vat_applies.SetBackgroundColour('yellow')
969
970 return validity
971 #----------------------------------------------------------------
975 #----------------------------------------------------------------
977 self.data['close_date'] = self._PRW_close_date.GetData()
978 self.data['apply_vat'] = self._3state2bool[self._CHBOX_vat_applies.ThreeStateValue]
979 self.data['comment'] = self._TCTRL_comment.GetValue()
980 self.data.save()
981 return True
982 #----------------------------------------------------------------
985 #----------------------------------------------------------------
988 #----------------------------------------------------------------
990 self._TCTRL_invoice_id.SetValue(self.data['invoice_id'])
991 self._PRW_close_date.SetText(data = self.data['close_date'])
992
993 self.data.set_missing_address_from_default()
994 if self.data['pk_receiver_address'] is None:
995 self._TCTRL_address.SetValue('')
996 else:
997 adr = self.data.address
998 self._TCTRL_address.SetValue(adr.format(single_line = True, show_type = False))
999
1000 self._TCTRL_value.SetValue('%(currency)s%(total_amount)s' % self.data)
1001 self._CHBOX_vat_applies.ThreeStateValue = self.bool_to_3state[self.data['apply_vat']]
1002 self._CHBOX_vat_applies.SetLabel(_('&VAT applies (%s%%)') % self.data['percent_vat'])
1003 if self.data['apply_vat'] is True:
1004 tmp = '%s %%(currency)s%%(total_vat)s %s %s %%(currency)s%%(total_amount_with_vat)s' % (
1005 gmTools.u_corresponds_to,
1006 gmTools.u_arrow2right,
1007 gmTools.u_sum,
1008 )
1009 self._TCTRL_value_with_vat.SetValue(tmp % self.data)
1010 elif self.data['apply_vat'] is None:
1011 self._TCTRL_value_with_vat.SetValue('?')
1012 else:
1013 self._TCTRL_value_with_vat.SetValue('')
1014
1015 self._TCTRL_comment.SetValue(gmTools.coalesce(self.data['comment'], ''))
1016
1017 self._PRW_close_date.SetFocus()
1018 #----------------------------------------------------------------
1019 # event handling
1020 #----------------------------------------------------------------
1022 if self._CHBOX_vat_applies.ThreeStateValue == wx.CHK_CHECKED:
1023 tmp = '%s %%(currency)s%%(total_vat)s %s %s %%(currency)s%%(total_amount_with_vat)s' % (
1024 gmTools.u_corresponds_to,
1025 gmTools.u_arrow2right,
1026 gmTools.u_sum,
1027 )
1028 self._TCTRL_value_with_vat.SetValue(tmp % self.data)
1029 return
1030 if self._CHBOX_vat_applies.ThreeStateValue == wx.CHK_UNDETERMINED:
1031 self._TCTRL_value_with_vat.SetValue('?')
1032 return
1033 self._TCTRL_value_with_vat.SetValue('')
1034 #----------------------------------------------------------------
1049
1050 #================================================================
1051 # per-patient bill items related widgets
1052 #----------------------------------------------------------------
1054
1055 if bill_item is not None:
1056 if bill_item.is_in_use:
1057 gmDispatcher.send(signal = 'statustext', msg = _('Cannot edit already invoiced bill item.'), beep = True)
1058 return False
1059
1060 ea = cBillItemEAPnl(parent, -1)
1061 ea.data = bill_item
1062 ea.mode = gmTools.coalesce(bill_item, 'new', 'edit')
1063 dlg = gmEditArea.cGenericEditAreaDlg2(parent, -1, edit_area = ea, single_entry = single_entry)
1064 dlg.SetTitle(gmTools.coalesce(bill_item, _('Adding new bill item'), _('Editing bill item')))
1065 if dlg.ShowModal() == wx.ID_OK:
1066 dlg.Destroy()
1067 return True
1068 dlg.Destroy()
1069 return False
1070 #----------------------------------------------------------------
1072
1073 if parent is None:
1074 parent = wx.GetApp().GetTopWindow()
1075 #------------------------------------------------------------
1076 def edit(item=None):
1077 return edit_bill_item(parent = parent, bill_item = item, single_entry = (item is not None))
1078 #------------------------------------------------------------
1079 def delete(item):
1080 if item.is_in_use is not None:
1081 gmDispatcher.send(signal = 'statustext', msg = _('Cannot delete already invoiced bill items.'), beep = True)
1082 return False
1083 gmBilling.delete_bill_item(pk_bill_item = item['pk_bill_item'])
1084 return True
1085 #------------------------------------------------------------
1086 def get_tooltip(item):
1087 if item is None:
1088 return None
1089 return item.format()
1090 #------------------------------------------------------------
1091 def refresh(lctrl):
1092 b_items = gmBilling.get_bill_items(pk_patient = pk_patient)
1093 items = [ [
1094 gmDateTime.pydt_strftime(b['date_to_bill'], '%Y %b %d', accuracy = gmDateTime.acc_days),
1095 b['unit_count'],
1096 '%s: %s%s' % (b['billable_code'], b['billable_description'], gmTools.coalesce(b['item_detail'], '', ' - %s')),
1097 b['currency'],
1098 '%s (%s %s %s%s%s)' % (
1099 b['total_amount'],
1100 b['unit_count'],
1101 gmTools.u_multiply,
1102 b['net_amount_per_unit'],
1103 gmTools.u_multiply,
1104 b['amount_multiplier']
1105 ),
1106 '%s (%s%%)' % (
1107 b['vat'],
1108 b['vat_multiplier'] * 100
1109 ),
1110 '%s (%s)' % (b['catalog_short'], b['catalog_version']),
1111 b['pk_bill_item']
1112 ] for b in b_items ]
1113 lctrl.set_string_items(items)
1114 lctrl.set_data(b_items)
1115 #------------------------------------------------------------
1116 gmListWidgets.get_choices_from_list (
1117 parent = parent,
1118 #msg = msg,
1119 caption = _('Showing bill items.'),
1120 columns = [_('Date'), _('Count'), _('Description'), _('$__replace_by_your_currency_symbol')[:-len('__replace_by_your_currency_symbol')], _('Value'), _('VAT'), _('Catalog'), '#'],
1121 single_selection = True,
1122 new_callback = edit,
1123 edit_callback = edit,
1124 delete_callback = delete,
1125 refresh_callback = refresh,
1126 list_tooltip_callback = get_tooltip
1127 )
1128
1129 #------------------------------------------------------------
1131 """A list for managing a patient's bill items.
1132
1133 Does NOT act on/listen to the current patient.
1134 """
1136
1137 try:
1138 self.__identity = kwargs['identity']
1139 del kwargs['identity']
1140 except KeyError:
1141 self.__identity = None
1142
1143 gmListWidgets.cGenericListManagerPnl.__init__(self, *args, **kwargs)
1144
1145 self.refresh_callback = self.refresh
1146 self.new_callback = self._add_item
1147 self.edit_callback = self._edit_item
1148 self.delete_callback = self._del_item
1149
1150 self.__show_non_invoiced_only = True
1151
1152 self.__init_ui()
1153 self.refresh()
1154 #--------------------------------------------------------
1155 # external API
1156 #--------------------------------------------------------
1158 if self.__identity is None:
1159 self._LCTRL_items.set_string_items()
1160 return
1161
1162 b_items = gmBilling.get_bill_items(pk_patient = self.__identity.ID, non_invoiced_only = self.__show_non_invoiced_only)
1163 items = [ [
1164 gmDateTime.pydt_strftime(b['date_to_bill'], '%Y %b %d', accuracy = gmDateTime.acc_days),
1165 b['unit_count'],
1166 '%s: %s%s' % (b['billable_code'], b['billable_description'], gmTools.coalesce(b['item_detail'], '', ' - %s')),
1167 b['currency'],
1168 b['total_amount'],
1169 '%s (%s%%)' % (
1170 b['vat'],
1171 b['vat_multiplier'] * 100
1172 ),
1173 '%s (%s)' % (b['catalog_short'], b['catalog_version']),
1174 '%s %s %s %s %s' % (
1175 b['unit_count'],
1176 gmTools.u_multiply,
1177 b['net_amount_per_unit'],
1178 gmTools.u_multiply,
1179 b['amount_multiplier']
1180 ),
1181 gmTools.coalesce(b['pk_bill'], gmTools.u_diameter),
1182 b['pk_encounter_to_bill'],
1183 b['pk_bill_item']
1184 ] for b in b_items ]
1185
1186 self._LCTRL_items.set_string_items(items = items)
1187 self._LCTRL_items.set_column_widths()
1188 self._LCTRL_items.set_data(data = b_items)
1189 #--------------------------------------------------------
1190 # internal helpers
1191 #--------------------------------------------------------
1193 self._LCTRL_items.set_columns(columns = [
1194 _('Charge date'),
1195 _('Count'),
1196 _('Description'),
1197 _('$__replace_by_your_currency_symbol')[:-len('__replace_by_your_currency_symbol')],
1198 _('Value'),
1199 _('VAT'),
1200 _('Catalog'),
1201 _('Count %s Value %s Factor') % (gmTools.u_multiply, gmTools.u_multiply),
1202 _('Invoice'),
1203 _('Encounter'),
1204 '#'
1205 ])
1206 self._LCTRL_items.item_tooltip_callback = self._get_item_tooltip
1207 # self.left_extra_button = (
1208 # _('Select pending'),
1209 # _('Select non-invoiced (pending) items.'),
1210 # self._select_pending_items
1211 # )
1212 self.left_extra_button = (
1213 _('Invoice selected items'),
1214 _('Create invoice from selected items.'),
1215 self._invoice_selected_items
1216 )
1217 self.middle_extra_button = (
1218 _('Bills'),
1219 _('Browse bills of this patient.'),
1220 self._browse_bills
1221 )
1222 self.right_extra_button = (
1223 _('Billables'),
1224 _('Browse list of billables.'),
1225 self._browse_billables
1226 )
1227 #--------------------------------------------------------
1230 #--------------------------------------------------------
1233 #--------------------------------------------------------
1235 if item['pk_bill'] is not None:
1236 gmDispatcher.send(signal = 'statustext', msg = _('Cannot delete already invoiced bill items.'), beep = True)
1237 return False
1238 go_ahead = gmGuiHelpers.gm_show_question (
1239 _( 'Do you really want to delete this\n'
1240 'bill item from the patient ?'),
1241 _('Deleting bill item')
1242 )
1243 if not go_ahead:
1244 return False
1245 gmBilling.delete_bill_item(pk_bill_item = item['pk_bill_item'])
1246 return True
1247 #--------------------------------------------------------
1252 #--------------------------------------------------------
1255 #--------------------------------------------------------
1257 bill_items = self._LCTRL_items.get_selected_item_data()
1258 bill = create_bill_from_items(bill_items)
1259 if bill is None:
1260 return
1261 if bill['pk_receiver_address'] is None:
1262 gmGuiHelpers.gm_show_error (
1263 aMessage = _(
1264 'Cannot create invoice.\n'
1265 '\n'
1266 'No receiver address selected.'
1267 ),
1268 aTitle = _('Creating invoice')
1269 )
1270 return
1271 if bill['close_date'] is None:
1272 bill['close_date'] = gmDateTime.pydt_now_here()
1273 bill.save()
1274 create_invoice_from_bill(parent = self, bill = bill, print_it = True, keep_a_copy = True)
1275 #--------------------------------------------------------
1279 #--------------------------------------------------------
1282 #--------------------------------------------------------
1283 # properties
1284 #--------------------------------------------------------
1287
1291
1292 identity = property(_get_identity, _set_identity)
1293 #--------------------------------------------------------
1296
1300
1301 show_non_invoiced_only = property(_get_show_non_invoiced_only, _set_show_non_invoiced_only)
1302
1303 #------------------------------------------------------------
1304 from Gnumed.wxGladeWidgets import wxgBillItemEAPnl
1305
1307
1309
1310 try:
1311 data = kwargs['bill_item']
1312 del kwargs['bill_item']
1313 except KeyError:
1314 data = None
1315
1316 wxgBillItemEAPnl.wxgBillItemEAPnl.__init__(self, *args, **kwargs)
1317 gmEditArea.cGenericEditAreaMixin.__init__(self)
1318
1319 self.mode = 'new'
1320 self.data = data
1321 if data is not None:
1322 self.mode = 'edit'
1323
1324 self.__init_ui()
1325 #----------------------------------------------------------------
1327 self._PRW_encounter.set_context(context = 'patient', val = gmPerson.gmCurrentPatient().ID)
1328 self._PRW_billable.add_callback_on_selection(self._on_billable_selected)
1329 self._PRW_billable.add_callback_on_modified(self._on_billable_modified)
1330 #----------------------------------------------------------------
1331 # generic Edit Area mixin API
1332 #----------------------------------------------------------------
1334
1335 validity = True
1336
1337 if self._TCTRL_factor.GetValue().strip() == '':
1338 validity = False
1339 self.display_tctrl_as_valid(tctrl = self._TCTRL_factor, valid = False)
1340 self._TCTRL_factor.SetFocus()
1341 else:
1342 converted, factor = gmTools.input2decimal(self._TCTRL_factor.GetValue())
1343 if not converted:
1344 validity = False
1345 self.display_tctrl_as_valid(tctrl = self._TCTRL_factor, valid = False)
1346 self._TCTRL_factor.SetFocus()
1347 else:
1348 self.display_tctrl_as_valid(tctrl = self._TCTRL_factor, valid = True)
1349
1350 if self._TCTRL_amount.GetValue().strip() == '':
1351 validity = False
1352 self.display_tctrl_as_valid(tctrl = self._TCTRL_amount, valid = False)
1353 self._TCTRL_amount.SetFocus()
1354 else:
1355 converted, factor = gmTools.input2decimal(self._TCTRL_amount.GetValue())
1356 if not converted:
1357 validity = False
1358 self.display_tctrl_as_valid(tctrl = self._TCTRL_amount, valid = False)
1359 self._TCTRL_amount.SetFocus()
1360 else:
1361 self.display_tctrl_as_valid(tctrl = self._TCTRL_amount, valid = True)
1362
1363 if self._TCTRL_count.GetValue().strip() == '':
1364 validity = False
1365 self.display_tctrl_as_valid(tctrl = self._TCTRL_count, valid = False)
1366 self._TCTRL_count.SetFocus()
1367 else:
1368 converted, factor = gmTools.input2decimal(self._TCTRL_count.GetValue())
1369 if not converted:
1370 validity = False
1371 self.display_tctrl_as_valid(tctrl = self._TCTRL_count, valid = False)
1372 self._TCTRL_count.SetFocus()
1373 else:
1374 self.display_tctrl_as_valid(tctrl = self._TCTRL_count, valid = True)
1375
1376 if self._PRW_date.is_valid_timestamp(allow_empty = True):
1377 self._PRW_date.display_as_valid(True)
1378 else:
1379 validity = False
1380 self._PRW_date.display_as_valid(False)
1381 self._PRW_date.SetFocus()
1382
1383 if self._PRW_encounter.GetData() is None:
1384 validity = False
1385 self._PRW_encounter.display_as_valid(False)
1386 self._PRW_encounter.SetFocus()
1387 else:
1388 self._PRW_encounter.display_as_valid(True)
1389
1390 if self._PRW_billable.GetData() is None:
1391 validity = False
1392 self._PRW_billable.display_as_valid(False)
1393 self._PRW_billable.SetFocus()
1394 else:
1395 self._PRW_billable.display_as_valid(True)
1396
1397 return validity
1398 #----------------------------------------------------------------
1400 data = gmBilling.create_bill_item (
1401 pk_encounter = self._PRW_encounter.GetData(),
1402 pk_billable = self._PRW_billable.GetData(),
1403 pk_staff = gmStaff.gmCurrentProvider()['pk_staff'] # should be settable !
1404 )
1405 data['raw_date_to_bill'] = self._PRW_date.GetData()
1406 converted, data['unit_count'] = gmTools.input2decimal(self._TCTRL_count.GetValue())
1407 converted, data['net_amount_per_unit'] = gmTools.input2decimal(self._TCTRL_amount.GetValue())
1408 converted, data['amount_multiplier'] = gmTools.input2decimal(self._TCTRL_factor.GetValue())
1409 data['item_detail'] = self._TCTRL_comment.GetValue().strip()
1410 data.save()
1411
1412 self.data = data
1413 return True
1414 #----------------------------------------------------------------
1416 self.data['pk_encounter_to_bill'] = self._PRW_encounter.GetData()
1417 self.data['raw_date_to_bill'] = self._PRW_date.GetData()
1418 converted, self.data['unit_count'] = gmTools.input2decimal(self._TCTRL_count.GetValue())
1419 converted, self.data['net_amount_per_unit'] = gmTools.input2decimal(self._TCTRL_amount.GetValue())
1420 converted, self.data['amount_multiplier'] = gmTools.input2decimal(self._TCTRL_factor.GetValue())
1421 self.data['item_detail'] = self._TCTRL_comment.GetValue().strip()
1422 return self.data.save()
1423 #----------------------------------------------------------------
1425 self._PRW_billable.SetText()
1426 self._PRW_encounter.set_from_instance(gmPerson.gmCurrentPatient().emr.active_encounter)
1427 self._PRW_date.SetData()
1428 self._TCTRL_count.SetValue('1')
1429 self._TCTRL_amount.SetValue('')
1430 self._LBL_currency.SetLabel(gmTools.u_euro)
1431 self._TCTRL_factor.SetValue('1')
1432 self._TCTRL_comment.SetValue('')
1433
1434 self._PRW_billable.Enable()
1435 self._PRW_billable.SetFocus()
1436 #----------------------------------------------------------------
1438 self._PRW_billable.SetText()
1439 self._TCTRL_count.SetValue('1')
1440 self._TCTRL_amount.SetValue('')
1441 self._TCTRL_comment.SetValue('')
1442
1443 self._PRW_billable.Enable()
1444 self._PRW_billable.SetFocus()
1445 #----------------------------------------------------------------
1447 self._PRW_billable.set_from_pk(self.data['pk_billable'])
1448 self._PRW_encounter.SetData(self.data['pk_encounter_to_bill'])
1449 self._PRW_date.SetData(data = self.data['raw_date_to_bill'])
1450 self._TCTRL_count.SetValue('%s' % self.data['unit_count'])
1451 self._TCTRL_amount.SetValue('%s' % self.data['net_amount_per_unit'])
1452 self._LBL_currency.SetLabel(self.data['currency'])
1453 self._TCTRL_factor.SetValue('%s' % self.data['amount_multiplier'])
1454 self._TCTRL_comment.SetValue(gmTools.coalesce(self.data['item_detail'], ''))
1455
1456 self._PRW_billable.Disable()
1457 self._PRW_date.SetFocus()
1458 #----------------------------------------------------------------
1460 if item is None:
1461 return
1462 if self._TCTRL_amount.GetValue().strip() != '':
1463 return
1464 val = '%s' % self._PRW_billable.GetData(as_instance = True)['raw_amount']
1465 wx.CallAfter(self._TCTRL_amount.SetValue, val)
1466 #----------------------------------------------------------------
1470
1471 #============================================================
1472 # a plugin for billing
1473 #------------------------------------------------------------
1474 from Gnumed.wxGladeWidgets import wxgBillingPluginPnl
1475
1476 -class cBillingPluginPnl(wxgBillingPluginPnl.wxgBillingPluginPnl, gmRegetMixin.cRegetOnPaintMixin):
1478
1479 wxgBillingPluginPnl.wxgBillingPluginPnl.__init__(self, *args, **kwargs)
1480 gmRegetMixin.cRegetOnPaintMixin.__init__(self)
1481 self.__register_interests()
1482 #-----------------------------------------------------
1484 self._PNL_bill_items.identity = None
1485 self._CHBOX_show_non_invoiced_only.SetValue(1)
1486 self._PRW_billable.SetText('', None)
1487 self._TCTRL_factor.SetValue('1.0')
1488 self._TCTRL_factor.Disable()
1489 self._TCTRL_details.SetValue('')
1490 self._TCTRL_details.Disable()
1491 #-----------------------------------------------------
1492 # event handling
1493 #-----------------------------------------------------
1495 gmDispatcher.connect(signal = 'pre_patient_unselection', receiver = self._on_pre_patient_unselection)
1496 gmDispatcher.connect(signal = 'post_patient_selection', receiver = self._on_post_patient_selection)
1497
1498 gmDispatcher.connect(signal = 'bill.bill_item_mod_db', receiver = self._on_bill_item_modified)
1499
1500 self._PRW_billable.add_callback_on_selection(self._on_billable_selected_in_prw)
1501 #-----------------------------------------------------
1504 #-----------------------------------------------------
1507 #-----------------------------------------------------
1510 #-----------------------------------------------------
1513 #--------------------------------------------------------
1544 #--------------------------------------------------------
1546 if billable is None:
1547 self._TCTRL_factor.Disable()
1548 self._TCTRL_details.Disable()
1549 self._BTN_insert_item.Disable()
1550 else:
1551 self._TCTRL_factor.Enable()
1552 self._TCTRL_details.Enable()
1553 self._BTN_insert_item.Enable()
1554 #-----------------------------------------------------
1555 # reget-on-paint mixin API
1556 #-----------------------------------------------------
1560 #============================================================
1561 # main
1562 #------------------------------------------------------------
1563 if __name__ == '__main__':
1564
1565 if len(sys.argv) < 2:
1566 sys.exit()
1567
1568 if sys.argv[1] != 'test':
1569 sys.exit()
1570
1571 from Gnumed.pycommon import gmI18N
1572 gmI18N.activate_locale()
1573 gmI18N.install_domain(domain = 'gnumed')
1574
1575 #----------------------------------------
1576 app = wx.PyWidgetTester(size = (600, 600))
1577 #app.SetWidget(cXxxPhraseWheel, -1)
1578 app.MainLoop()
1579
| Home | Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0.1 on Thu May 10 01:55:20 2018 | http://epydoc.sourceforge.net |