Package Gnumed :: Package wxpython :: Module gmBillingWidgets
[frames] | no frames]

Source Code for Module Gnumed.wxpython.gmBillingWidgets

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