Home | Trees | Indices | Help |
|
---|
|
1 # -*- coding: utf8 -*- 2 """Billing code. 3 4 Copyright: authors 5 """ 6 #============================================================ 7 __author__ = "Nico Latzer <nl@mnet-online.de>, Karsten Hilbert <Karsten.Hilbert@gmx.net>" 8 __license__ = 'GPL v2 or later (details at http://www.gnu.org)' 9 10 import sys 11 import logging 12 13 14 if __name__ == '__main__': 15 sys.path.insert(0, '../../') 16 from Gnumed.pycommon import gmPG2 17 from Gnumed.pycommon import gmBusinessDBObject 18 from Gnumed.pycommon import gmTools 19 from Gnumed.pycommon import gmDateTime 20 from Gnumed.business import gmDemographicRecord 21 from Gnumed.business import gmDocuments 22 23 _log = logging.getLogger('gm.bill') 24 25 INVOICE_DOCUMENT_TYPE = u'invoice' 26 #============================================================ 27 # billables 28 #------------------------------------------------------------ 29 _SQL_get_billable_fields = u"SELECT * FROM ref.v_billables WHERE %s" 3032 """Items which can be billed to patients.""" 33 34 _cmd_fetch_payload = _SQL_get_billable_fields % u"""pk_billable = %s""" 35 _cmds_store_payload = [ 36 u"""UPDATE ref.billable SET 37 code = %(billable_code)s, 38 term = %(billable_description)s, 39 amount = %(raw_amount)s, 40 currency = %(currency)s, 41 vat_multiplier = %(vat_multiplier)s 42 WHERE 43 pk = %(pk_billabs)s 44 AND 45 xmin = %(xmin_billable)s 46 RETURNING 47 xmin AS xmin_billable 48 """] 49 50 _updatable_fields = [ 51 'billable_description', 52 'raw_amount', 53 'vat_multiplier', 54 ] 55 #--------------------------------------------------------92 #------------------------------------------------------------57 txt = u'%s [#%s]\n\n' % ( 58 gmTools.bool2subst ( 59 self._payload[self._idx['active']], 60 _('Active billable item'), 61 _('Inactive billable item') 62 ), 63 self._payload[self._idx['pk_billable']] 64 ) 65 txt += u' %s: %s\n' % ( 66 self._payload[self._idx['billable_code']], 67 self._payload[self._idx['billable_description']] 68 ) 69 txt += _(' %s %s + %s%% VAT = %s %s\n') % ( 70 self._payload[self._idx['raw_amount']], 71 self._payload[self._idx['currency']], 72 self._payload[self._idx['vat_multiplier']] * 100, 73 self._payload[self._idx['amount_with_vat']], 74 self._payload[self._idx['currency']] 75 ) 76 txt += u' %s %s%s (%s)' % ( 77 self._payload[self._idx['catalog_short']], 78 self._payload[self._idx['catalog_version']], 79 gmTools.coalesce(self._payload[self._idx['catalog_language']], u'', ' - %s'), 80 self._payload[self._idx['catalog_long']] 81 ) 82 txt += gmTools.coalesce(self._payload[self._idx['comment']], u'', u'\n %s') 83 84 return txt85 #--------------------------------------------------------87 cmd = u'SELECT EXISTS(SELECT 1 FROM bill.bill_item WHERE fk_billable = %(pk)s LIMIT 1)' 88 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': {'pk': self._payload[self._idx['pk_billable']]}}]) 89 return rows[0][0]90 91 is_in_use = property(_get_is_in_use, lambda x:x)94 95 if order_by is None: 96 order_by = u' ORDER BY catalog_long, catalog_version, billable_code' 97 else: 98 order_by = u' ORDER BY %s' % order_by 99 100 if active_only: 101 where = u'active IS true' 102 else: 103 where = u'true' 104 105 cmd = (_SQL_get_billable_fields % where) + order_by 106 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx = True) 107 return [ cBillable(row = {'data': r, 'idx': idx, 'pk_field': 'pk_billable'}) for r in rows ]108 #------------------------------------------------------------110 cmd = u""" 111 DELETE FROM ref.billable 112 WHERE 113 pk = %(pk)s 114 AND 115 NOT EXISTS ( 116 SELECT 1 FROM bill.bill_item WHERE fk_billable = %(pk)s 117 ) 118 """ 119 args = {'pk': pk_billable} 120 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])121 #============================================================ 122 # bill items 123 #------------------------------------------------------------ 124 _SQL_fetch_bill_item_fields = u"SELECT * FROM bill.v_bill_items WHERE %s" 125127 128 _cmd_fetch_payload = _SQL_fetch_bill_item_fields % u"pk_bill_item = %s" 129 _cmds_store_payload = [ 130 u"""UPDATE bill.bill_item SET 131 fk_provider = %(pk_provider)s, 132 fk_encounter = %(pk_encounter_to_bill)s, 133 date_to_bill = %(raw_date_to_bill)s, 134 description = gm.nullify_empty_string(%(item_detail)s), 135 net_amount_per_unit = %(net_amount_per_unit)s, 136 currency = gm.nullify_empty_string(%(currency)s), 137 fk_bill = %(pk_bill)s, 138 unit_count = %(unit_count)s, 139 amount_multiplier = %(amount_multiplier)s 140 WHERE 141 pk = %(pk_bill_item)s 142 AND 143 xmin = %(xmin_bill_item)s 144 RETURNING 145 xmin AS xmin_bill_item 146 """] 147 148 _updatable_fields = [ 149 'pk_provider', 150 'pk_encounter_to_bill', 151 'raw_date_to_bill', 152 'item_detail', 153 'net_amount_per_unit', 154 'currency', 155 'pk_bill', 156 'unit_count', 157 'amount_multiplier' 158 ] 159 #--------------------------------------------------------234 #------------------------------------------------------------161 txt = u'%s (%s %s%s) [#%s]\n' % ( 162 gmTools.bool2subst( 163 self._payload[self._idx['pk_bill']] is None, 164 _('Open item'), 165 _('Billed item'), 166 ), 167 self._payload[self._idx['catalog_short']], 168 self._payload[self._idx['catalog_version']], 169 gmTools.coalesce(self._payload[self._idx['catalog_language']], u'', ' - %s'), 170 self._payload[self._idx['pk_bill_item']] 171 ) 172 txt += u' %s: %s\n' % ( 173 self._payload[self._idx['billable_code']], 174 self._payload[self._idx['billable_description']] 175 ) 176 txt += gmTools.coalesce ( 177 self._payload[self._idx['billable_comment']], 178 u'', 179 u' (%s)\n', 180 ) 181 txt += gmTools.coalesce ( 182 self._payload[self._idx['item_detail']], 183 u'', 184 _(' Details: %s\n'), 185 ) 186 187 txt += u'\n' 188 txt += _(' %s of units: %s\n') % ( 189 gmTools.u_numero, 190 self._payload[self._idx['unit_count']] 191 ) 192 txt += _(' Amount per unit: %s %s (%s %s per catalog)\n') % ( 193 self._payload[self._idx['net_amount_per_unit']], 194 self._payload[self._idx['currency']], 195 self._payload[self._idx['billable_amount']], 196 self._payload[self._idx['billable_currency']] 197 ) 198 txt += _(' Amount multiplier: %s\n') % self._payload[self._idx['amount_multiplier']] 199 txt += _(' VAT would be: %s%% %s %s %s\n') % ( 200 self._payload[self._idx['vat_multiplier']] * 100, 201 gmTools.u_corresponds_to, 202 self._payload[self._idx['vat']], 203 self._payload[self._idx['currency']] 204 ) 205 206 txt += u'\n' 207 txt += _(' Charge date: %s') % gmDateTime.pydt_strftime ( 208 self._payload[self._idx['date_to_bill']], 209 '%Y %b %d', 210 accuracy = gmDateTime.acc_days 211 ) 212 bill = self.bill 213 if bill is not None: 214 txt += _('\n On bill: %s') % bill['invoice_id'] 215 216 return txt217 #--------------------------------------------------------219 return cBillable(aPK_obj = self._payload[self._idx['pk_billable']])220 221 billable = property(_get_billable, lambda x:x) 222 #--------------------------------------------------------224 if self._payload[self._idx['pk_bill']] is None: 225 return None 226 return cBill(aPK_obj = self._payload[self._idx['pk_bill']])227 228 bill = property(_get_bill, lambda x:x) 229 #-------------------------------------------------------- 232 233 is_in_use = property(_get_is_in_use, lambda x:x)236 if non_invoiced_only: 237 cmd = _SQL_fetch_bill_item_fields % u"pk_patient = %(pat)s AND pk_bill IS NULL" 238 else: 239 cmd = _SQL_fetch_bill_item_fields % u"pk_patient = %(pat)s" 240 args = {'pat': pk_patient} 241 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True) 242 return [ cBillItem(row = {'data': r, 'idx': idx, 'pk_field': 'pk_bill_item'}) for r in rows ]243 #------------------------------------------------------------245 246 billable = cBillable(aPK_obj = pk_billable) 247 cmd = u""" 248 INSERT INTO bill.bill_item ( 249 fk_provider, 250 fk_encounter, 251 net_amount_per_unit, 252 currency, 253 fk_billable 254 ) VALUES ( 255 %(staff)s, 256 %(enc)s, 257 %(val)s, 258 %(curr)s, 259 %(billable)s 260 ) 261 RETURNING pk""" 262 args = { 263 'staff': pk_staff, 264 'enc': pk_encounter, 265 'val': billable['raw_amount'], 266 'curr': billable['currency'], 267 'billable': pk_billable 268 } 269 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], return_data = True) 270 return cBillItem(aPK_obj = rows[0][0])271 #------------------------------------------------------------273 cmd = u'DELETE FROM bill.bill_item WHERE pk = %(pk)s AND fk_bill IS NULL' 274 args = {'pk': pk_bill_item} 275 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])276 277 #============================================================ 278 # bills 279 #------------------------------------------------------------ 280 _SQL_get_bill_fields = u"""SELECT * FROM bill.v_bills WHERE %s""" 281283 """Represents a bill""" 284 285 _cmd_fetch_payload = _SQL_get_bill_fields % u"pk_bill = %s" 286 _cmds_store_payload = [ 287 u"""UPDATE bill.bill SET 288 invoice_id = gm.nullify_empty_string(%(invoice_id)s), 289 close_date = %(close_date)s, 290 apply_vat = %(apply_vat)s, 291 fk_receiver_identity = %(pk_receiver_identity)s, 292 fk_receiver_address = %(pk_receiver_address)s, 293 fk_doc = %(pk_doc)s 294 WHERE 295 pk = %(pk_bill)s 296 AND 297 xmin = %(xmin_bill)s 298 RETURNING 299 pk as pk_bill, 300 xmin as xmin_bill 301 """ 302 ] 303 _updatable_fields = [ 304 u'invoice_id', 305 u'pk_receiver_identity', 306 u'close_date', 307 u'apply_vat', 308 u'pk_receiver_address', 309 u'pk_doc' 310 ] 311 #--------------------------------------------------------414 #------------------------------------------------------------313 txt = u'%s [#%s]\n' % ( 314 gmTools.bool2subst ( 315 (self._payload[self._idx['close_date']] is None), 316 _('Open bill'), 317 _('Closed bill') 318 ), 319 self._payload[self._idx['pk_bill']] 320 ) 321 txt += _(' Invoice ID: %s\n') % self._payload[self._idx['invoice_id']] 322 if self._payload[self._idx['close_date']] is not None: 323 txt += _(' Closed: %s\n') % gmDateTime.pydt_strftime ( 324 self._payload[self._idx['close_date']], 325 '%Y %b %d', 326 accuracy = gmDateTime.acc_days 327 ) 328 txt += _(' Bill value: %s %s\n') % ( 329 self._payload[self._idx['total_amount']], 330 self._payload[self._idx['currency']] 331 ) 332 if self._payload[self._idx['apply_vat']]: 333 txt += _(' VAT: %s%% %s %s %s\n') % ( 334 self._payload[self._idx['percent_vat']], 335 gmTools.u_corresponds_to, 336 self._payload[self._idx['total_vat']], 337 self._payload[self._idx['currency']] 338 ) 339 txt += _(' Value + VAT: %s %s\n') % ( 340 self._payload[self._idx['total_amount_with_vat']], 341 self._payload[self._idx['currency']] 342 ) 343 else: 344 txt += _(' VAT: does not apply\n') 345 if self._payload[self._idx['pk_bill_items']] is None: 346 txt += _(' Items billed: 0\n') 347 else: 348 txt += _(' Items billed: %s\n') % len(self._payload[self._idx['pk_bill_items']]) 349 txt += _(' Invoice: %s\n') % ( 350 gmTools.bool2subst ( 351 self._payload[self._idx['pk_doc']] is None, 352 _('not available'), 353 u'#%s' % self._payload[self._idx['pk_doc']] 354 ) 355 ) 356 txt += _(' Patient: #%s\n') % self._payload[self._idx['pk_patient']] 357 txt += gmTools.coalesce ( 358 self._payload[self._idx['pk_receiver_identity']], 359 u'', 360 _(' Receiver: #%s\n') 361 ) 362 if self._payload[self._idx['pk_receiver_address']] is not None: 363 txt += u'\n '.join(gmDemographicRecord.get_patient_address(pk_patient_address = self._payload[self._idx['pk_receiver_address']]).format()) 364 365 return txt366 #--------------------------------------------------------368 """Requires no pending changes within the bill itself.""" 369 # should check for item consistency first 370 conn = gmPG2.get_connection(readonly = False) 371 for item in items: 372 item['pk_bill'] = self._payload[self._idx['pk_bill']] 373 item.save(conn = conn) 374 conn.commit() 375 self.refetch_payload() # make sure aggregates are re-filled from view376 #--------------------------------------------------------378 return [ cBillItem(aPK_obj = pk) for pk in self._payload[self._idx['pk_bill_items']] ]379 380 bill_items = property(_get_bill_items, lambda x:x) 381 #--------------------------------------------------------383 if self._payload[self._idx['pk_doc']] is None: 384 return None 385 return gmDocuments.cDocument(aPK_obj = self._payload[self._idx['pk_doc']])386 387 invoice = property(_get_invoice, lambda x:x) 388 #--------------------------------------------------------390 if self._payload[self._idx['pk_receiver_address']] is None: 391 return None 392 return gmDemographicRecord.get_address_from_patient_address_pk ( 393 pk_patient_address = self._payload[self._idx['pk_receiver_address']] 394 )395 396 address = property(_get_address, lambda x:x) 397 #--------------------------------------------------------399 return gmDemographicRecord.get_patient_address_by_type ( 400 pk_patient = self._payload[self._idx['pk_patient']], 401 adr_type = u'billing' 402 )403 404 default_address = property(_get_default_address, lambda x:x) 405 #--------------------------------------------------------407 if self._payload[self._idx['pk_receiver_address']] is not None: 408 return True 409 adr = self.default_address 410 if adr is None: 411 return False 412 self['pk_receiver_address'] = adr['pk_lnk_person_org_address'] 413 return self.save_payload()416 417 args = {'pat': pk_patient} 418 where_parts = [u'true'] 419 420 if pk_patient is not None: 421 where_parts.append(u'pk_patient = %(pat)s') 422 423 if order_by is None: 424 order_by = u'' 425 else: 426 order_by = u' ORDER BY %s' % order_by 427 428 cmd = (_SQL_get_bill_fields % u' AND '.join(where_parts)) + order_by 429 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True) 430 return [ cBill(row = {'data': r, 'idx': idx, 'pk_field': 'pk_bill'}) for r in rows ]431 #------------------------------------------------------------433 434 args = {u'inv_id': invoice_id} 435 cmd = u""" 436 INSERT INTO bill.bill (invoice_id) 437 VALUES (gm.nullify_empty_string(%(inv_id)s)) 438 RETURNING pk 439 """ 440 rows, idx = gmPG2.run_rw_queries(link_obj = conn, queries = [{'cmd': cmd, 'args': args}], return_data = True, get_col_idx = False) 441 442 return cBill(aPK_obj = rows[0]['pk'])443 #------------------------------------------------------------445 args = {'pk': pk_bill} 446 cmd = u"DELETE FROM bill.bill WHERE pk = %(pk)s" 447 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}]) 448 return True449 #------------------------------------------------------------ 452 #------------------------------------------------------------454 return u'GM%s / %s' % ( 455 pk_patient, 456 gmDateTime.pydt_strftime ( 457 gmDateTime.pydt_now_here(), 458 '%Y-%m-%d / %H%M%S' 459 ) 460 )461 #============================================================ 462 # main 463 #------------------------------------------------------------ 464 if __name__ == "__main__": 465 466 if len(sys.argv) < 2: 467 sys.exit() 468 469 if sys.argv[1] != 'test': 470 sys.exit() 471 472 # from Gnumed.pycommon import gmLog2 473 # from Gnumed.pycommon import gmI18N 474 # from Gnumed.business import gmPerson 475 476 # gmI18N.activate_locale() 477 ## gmDateTime.init() 478480 bills = get_bills(pk_patient = 12) 481 first_bill = bills[0] 482 print first_bill.default_address483485 print "--------------" 486 me = cBillable(aPK_obj=1) 487 fields = me.get_fields() 488 for field in fields: 489 print field, ':', me[field] 490 print "updatable:", me.get_updatable_fields()491 #me['vat']=4; me.store_payload() 492 #-------------------------------------------------- 493 #test_me() 494 test_default_address() 495
Home | Trees | Indices | Help |
|
---|
Generated by Epydoc 3.0.1 on Tue Jul 31 03:58:40 2012 | http://epydoc.sourceforge.net |