1
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 = 'invoice'
26
27
28
29 _SQL_get_billable_fields = "SELECT * FROM ref.v_billables WHERE %s"
30
31 -class cBillable(gmBusinessDBObject.cBusinessDBObject):
32 """Items which can be billed to patients."""
33
34 _cmd_fetch_payload = _SQL_get_billable_fields % "pk_billable = %s"
35 _cmds_store_payload = [
36 """UPDATE ref.billable SET
37 fk_data_source = %(pk_data_source)s,
38 code = %(billable_code)s,
39 term = %(billable_description)s,
40 comment = gm.nullify_empty_string(%(comment)s),
41 amount = %(raw_amount)s,
42 currency = %(currency)s,
43 vat_multiplier = %(vat_multiplier)s,
44 active = %(active)s
45 --, discountable = %(discountable)s
46 WHERE
47 pk = %(pk_billable)s
48 AND
49 xmin = %(xmin_billable)s
50 RETURNING
51 xmin AS xmin_billable
52 """]
53
54 _updatable_fields = [
55 'billable_code',
56 'billable_description',
57 'raw_amount',
58 'vat_multiplier',
59 'comment',
60 'currency',
61 'active',
62 'pk_data_source'
63 ]
64
93
95 cmd = 'SELECT EXISTS(SELECT 1 FROM bill.bill_item WHERE fk_billable = %(pk)s LIMIT 1)'
96 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': {'pk': self._payload[self._idx['pk_billable']]}}])
97 return rows[0][0]
98
99 is_in_use = property(_get_is_in_use, lambda x:x)
100
101
103
104 if order_by is None:
105 order_by = ' ORDER BY catalog_long, catalog_version, billable_code'
106 else:
107 order_by = ' ORDER BY %s' % order_by
108
109 if active_only:
110 where = 'active IS true'
111 else:
112 where = 'true'
113
114 cmd = (_SQL_get_billable_fields % where) + order_by
115 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx = True)
116 return [ cBillable(row = {'data': r, 'idx': idx, 'pk_field': 'pk_billable'}) for r in rows ]
117
118
119 -def create_billable(code=None, term=None, data_source=None, return_existing=False):
120 args = {
121 'code': code.strip(),
122 'term': term.strip(),
123 'data_src': data_source
124 }
125 cmd = """
126 INSERT INTO ref.billable (code, term, fk_data_source)
127 SELECT
128 %(code)s,
129 %(term)s,
130 %(data_src)s
131 WHERE NOT EXISTS (
132 SELECT 1 FROM ref.billable
133 WHERE
134 code = %(code)s
135 AND
136 term = %(term)s
137 AND
138 fk_data_source = %(data_src)s
139 )
140 RETURNING pk"""
141 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False, return_data = True)
142 if len(rows) > 0:
143 return cBillable(aPK_obj = rows[0]['pk'])
144
145 if not return_existing:
146 return None
147
148 cmd = """
149 SELECT * FROM ref.v_billables
150 WHERE
151 code = %(code)s
152 AND
153 term = %(term)s
154 AND
155 pk_data_source = %(data_src)s
156 """
157 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True)
158 return cBillable(row = {'data': rows[0], 'idx': idx, 'pk_field': 'pk_billable'})
159
160
162 cmd = """
163 DELETE FROM ref.billable
164 WHERE
165 pk = %(pk)s
166 AND
167 NOT EXISTS (
168 SELECT 1 FROM bill.bill_item WHERE fk_billable = %(pk)s
169 )
170 """
171 args = {'pk': pk_billable}
172 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
173
174
175
176
177 _SQL_get_bill_item_fields = u"SELECT * FROM bill.v_bill_items WHERE %s"
178
179 -class cBillItem(gmBusinessDBObject.cBusinessDBObject):
180
181 _cmd_fetch_payload = _SQL_get_bill_item_fields % u"pk_bill_item = %s"
182 _cmds_store_payload = [
183 """UPDATE bill.bill_item SET
184 fk_provider = %(pk_provider)s,
185 fk_encounter = %(pk_encounter_to_bill)s,
186 date_to_bill = %(raw_date_to_bill)s,
187 description = gm.nullify_empty_string(%(item_detail)s),
188 net_amount_per_unit = %(net_amount_per_unit)s,
189 currency = gm.nullify_empty_string(%(currency)s),
190 fk_bill = %(pk_bill)s,
191 unit_count = %(unit_count)s,
192 amount_multiplier = %(amount_multiplier)s
193 WHERE
194 pk = %(pk_bill_item)s
195 AND
196 xmin = %(xmin_bill_item)s
197 RETURNING
198 xmin AS xmin_bill_item
199 """]
200
201 _updatable_fields = [
202 'pk_provider',
203 'pk_encounter_to_bill',
204 'raw_date_to_bill',
205 'item_detail',
206 'net_amount_per_unit',
207 'currency',
208 'pk_bill',
209 'unit_count',
210 'amount_multiplier'
211 ]
212
270
272 return cBillable(aPK_obj = self._payload[self._idx['pk_billable']])
273
274 billable = property(_get_billable, lambda x:x)
275
277 if self._payload[self._idx['pk_bill']] is None:
278 return None
279 return cBill(aPK_obj = self._payload[self._idx['pk_bill']])
280
281 bill = property(_get_bill, lambda x:x)
282
284 return self._payload[self._idx['pk_bill']] is not None
285
286 is_in_use = property(_get_is_in_use, lambda x:x)
287
296
297
299
300 billable = cBillable(aPK_obj = pk_billable)
301 cmd = """
302 INSERT INTO bill.bill_item (
303 fk_provider,
304 fk_encounter,
305 net_amount_per_unit,
306 currency,
307 fk_billable
308 ) VALUES (
309 %(staff)s,
310 %(enc)s,
311 %(val)s,
312 %(curr)s,
313 %(billable)s
314 )
315 RETURNING pk"""
316 args = {
317 'staff': pk_staff,
318 'enc': pk_encounter,
319 'val': billable['raw_amount'],
320 'curr': billable['currency'],
321 'billable': pk_billable
322 }
323 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], return_data = True)
324 return cBillItem(aPK_obj = rows[0][0])
325
326
328 cmd = 'DELETE FROM bill.bill_item WHERE pk = %(pk)s AND fk_bill IS NULL'
329 args = {'pk': pk_bill_item}
330 gmPG2.run_rw_queries(link_obj = link_obj, queries = [{'cmd': cmd, 'args': args}])
331
332
333
334
335 _SQL_get_bill_fields = """SELECT * FROM bill.v_bills WHERE %s"""
336
337 -class cBill(gmBusinessDBObject.cBusinessDBObject):
338 """Represents a bill"""
339
340 _cmd_fetch_payload = _SQL_get_bill_fields % "pk_bill = %s"
341 _cmds_store_payload = [
342 """UPDATE bill.bill SET
343 invoice_id = gm.nullify_empty_string(%(invoice_id)s),
344 close_date = %(close_date)s,
345 apply_vat = %(apply_vat)s,
346 comment = gm.nullify_empty_string(%(comment)s),
347 fk_receiver_identity = %(pk_receiver_identity)s,
348 fk_receiver_address = %(pk_receiver_address)s,
349 fk_doc = %(pk_doc)s
350 WHERE
351 pk = %(pk_bill)s
352 AND
353 xmin = %(xmin_bill)s
354 RETURNING
355 pk as pk_bill,
356 xmin as xmin_bill
357 """
358 ]
359 _updatable_fields = [
360 'invoice_id',
361 'pk_receiver_identity',
362 'close_date',
363 'apply_vat',
364 'comment',
365 'pk_receiver_address',
366 'pk_doc'
367 ]
368
434
444
446 return [ cBillItem(aPK_obj = pk) for pk in self._payload[self._idx['pk_bill_items']] ]
447
448 bill_items = property(_get_bill_items, lambda x:x)
449
451 if self._payload[self._idx['pk_doc']] is None:
452 return None
453 return gmDocuments.cDocument(aPK_obj = self._payload[self._idx['pk_doc']])
454
455 invoice = property(_get_invoice, lambda x:x)
456
463
464 address = property(_get_address, lambda x:x)
465
471
472 default_address = property(_get_default_address, lambda x:x)
473
479
480 home_address = property(_get_home_address, lambda x:x)
481
483 if self._payload[self._idx['pk_receiver_address']] is not None:
484 return True
485 adr = self.default_address
486 if adr is None:
487 adr = self.home_address
488 if adr is None:
489 return False
490 self['pk_receiver_address'] = adr['pk_lnk_person_org_address']
491 return self.save_payload()
492
493
494 -def get_bills(order_by=None, pk_patient=None):
495
496 args = {'pat': pk_patient}
497 where_parts = ['true']
498
499 if pk_patient is not None:
500 where_parts.append('pk_patient = %(pat)s')
501
502 if order_by is None:
503 order_by = ''
504 else:
505 order_by = ' ORDER BY %s' % order_by
506
507 cmd = (_SQL_get_bill_fields % ' AND '.join(where_parts)) + order_by
508 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True)
509 return [ cBill(row = {'data': r, 'idx': idx, 'pk_field': 'pk_bill'}) for r in rows ]
510
511
513 args = {'pk_doc': pk_document}
514 cmd = _SQL_get_bill_fields % 'pk_doc = %(pk_doc)s'
515 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True)
516 return [ cBill(row = {'data': r, 'idx': idx, 'pk_field': 'pk_bill'}) for r in rows ]
517
518
520
521 args = {'inv_id': invoice_id}
522 cmd = """
523 INSERT INTO bill.bill (invoice_id)
524 VALUES (gm.nullify_empty_string(%(inv_id)s))
525 RETURNING pk
526 """
527 rows, idx = gmPG2.run_rw_queries(link_obj = conn, queries = [{'cmd': cmd, 'args': args}], return_data = True, get_col_idx = False)
528
529 return cBill(aPK_obj = rows[0]['pk'])
530
531
533 args = {'pk': pk_bill}
534 cmd = "DELETE FROM bill.bill WHERE pk = %(pk)s"
535 gmPG2.run_rw_queries(link_obj = link_obj, queries = [{'cmd': cmd, 'args': args}])
536 return True
537
538
541
542
551
552
553
554
555 if __name__ == "__main__":
556
557 if len(sys.argv) < 2:
558 sys.exit()
559
560 if sys.argv[1] != 'test':
561 sys.exit()
562
563
564
565
566
567
568
569
574
576 print("--------------")
577 me = cBillable(aPK_obj=1)
578 fields = me.get_fields()
579 for field in fields:
580 print(field, ':', me[field])
581 print("updatable:", me.get_updatable_fields())
582
583
584
585 test_default_address()
586