Skip to content

Commit

Permalink
fix(Inpatient Record): quantity mismatch when fetching healthcare ser…
Browse files Browse the repository at this point in the history
…vices
  • Loading branch information
Sajinsr committed Sep 16, 2024
1 parent a1c2835 commit c0ef79f
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 46 deletions.
91 changes: 57 additions & 34 deletions healthcare/healthcare/doctype/inpatient_record/inpatient_record.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,15 @@
from frappe.desk.reportview import get_match_cond
from frappe.model.document import Document
from frappe.model.mapper import get_mapped_doc
from frappe.utils import get_datetime, get_link_to_form, getdate, now, now_datetime, today
from frappe.utils import (
get_datetime,
get_link_to_form,
getdate,
now,
now_datetime,
time_diff_in_hours,
today,
)

from healthcare.healthcare.doctype.healthcare_settings.healthcare_settings import get_account
from healthcare.healthcare.doctype.nursing_task.nursing_task import NursingTask
Expand Down Expand Up @@ -118,55 +126,68 @@ def transfer(self, service_unit, check_in, leave_from=None, txred=0):
@frappe.whitelist()
def add_service_unit_rent_to_billable_items(self):
try:
query = frappe.db.sql(
f"""
SELECT
sum(TIMESTAMPDIFF(minute, io.check_in, now())) as now_difference,
sum(TIMESTAMPDIFF(minute, io.check_in, io.check_out)) as time_difference,
io.`left`,
io = frappe.qb.DocType("Inpatient Occupancy")
su = frappe.qb.DocType("Healthcare Service Unit")
sut = frappe.qb.DocType("Healthcare Service Unit Type")

query = (
frappe.qb.from_(io)
.left_join(su)
.on(io.service_unit == su.name)
.left_join(sut)
.on(su.service_unit_type == sut.name)
.select(
io.check_in,
io.check_out,
io.left,
io.parent,
io.name,
sut.item,
sut.uom,
sut.rate,
sut.no_of_hours,
sut.minimum_billable_qty
FROM
`tabInpatient Occupancy` as io left join
`tabHealthcare Service Unit` as su on io.service_unit=su.name left join
`tabHealthcare Service Unit Type` as sut on su.service_unit_type=sut.name
WHERE
io.parent={frappe.db.escape(self.name)}
GROUP BY
sut.item
""",
as_dict=True,
sut.minimum_billable_qty,
)
.where(io.parent == self.name)
)
for inpatient in query:

inpatient_details = query.run(as_dict=True)
item_hours = {}

# Calculate total hours for each item
for record in inpatient_details:
check_in = get_datetime(record["check_in"])
check_out = get_datetime(record["check_out"]) if record["check_out"] else get_datetime()

hours_diff = time_diff_in_hours(check_out, check_in)
item = record.get("item")

if item not in item_hours:
record["total_hours"] = 0
item_hours[item] = record

item_hours[item]["total_hours"] += hours_diff

ip_records = list(item_hours.values())

for inpatient in ip_records:
item_name, stock_uom = frappe.db.get_value(
"Item", inpatient.get("item"), ["item_name", "stock_uom"]
)
item_row = frappe.db.get_value(
"Inpatient Record Item",
{"item_code": inpatient.get("item"), "parent": self.name},
["name", "quantity", "invoiced"],
order_by="idx DESC",
as_dict=True,
)
uom = 60
if inpatient.get("uom") == "Hour":
uom = 60
elif inpatient.get("uom") == "Day":
uom = 1440

minimum_billable_qty = inpatient.get("minimum_billable_qty")
quantity = 1
if inpatient.get("left") == 1:
quantity = inpatient.get("time_difference") / uom
else:
quantity = inpatient.get("now_difference") / uom
if minimum_billable_qty and quantity < minimum_billable_qty:
quantity = minimum_billable_qty
quantity = max(inpatient.get("total_hours", 0.5), minimum_billable_qty or 0.5)

# Add or update item row based on existing data
if not item_row:
# to add item child first time
# Add new item row if none exists
se_child = self.append("items")
se_child.item_code = inpatient.get("item")
se_child.item_name = item_name
Expand All @@ -176,7 +197,7 @@ def add_service_unit_rent_to_billable_items(self):
se_child.rate = inpatient.rate / inpatient.get("no_of_hours")
else:
if item_row.get("invoiced"):
# if invoiced add another row
# Add new row if invoiced and additional quantity exists
if item_row.get("quantity") and quantity and quantity > item_row.get("quantity"):
se_child = self.append("items")
se_child.item_code = inpatient.get("item")
Expand All @@ -186,17 +207,19 @@ def add_service_unit_rent_to_billable_items(self):
se_child.quantity = quantity - item_row.get("quantity")
se_child.rate = inpatient.rate / inpatient.get("no_of_hours")
else:
# update existing row in item line if not invoiced
# Update existing non-invoiced item row
if quantity != item_row.get("quantity"):
for item in self.items:
if item.name == item_row.get("name"):
item.quantity = quantity

# Update inpatient occupancy billing time
for test in self.inpatient_occupancies:
if test.name == inpatient.get("name"):
test.scheduled_billing_time = now()

self.save()

except Exception as e:
frappe.log_error(message=e, title="Can't bill Service Unit occupancy")

Expand Down
19 changes: 7 additions & 12 deletions healthcare/healthcare/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,11 @@

import base64
import json
import math

import frappe
from frappe import _
from frappe.query_builder import DocType
from frappe.utils import cint, cstr, flt, get_link_to_form, rounded, time_diff_in_hours
from frappe.utils import cint, cstr, flt, get_link_to_form, time_diff_in_hours
from frappe.utils.formatters import format_value

from erpnext.setup.utils import insert_record
Expand Down Expand Up @@ -263,6 +262,7 @@ def get_inpatient_services_to_invoice(patient, company):

inpatient_services = (
frappe.qb.from_(ip_occupancy)
.join(ip_record)
.on(ip_occupancy.parent == ip_record.name)
.select(ip_occupancy.star)
.where(
Expand All @@ -280,19 +280,13 @@ def get_inpatient_services_to_invoice(patient, company):
service_unit_type = frappe.get_cached_doc("Healthcare Service Unit Type", service_unit_type)
if service_unit_type and service_unit_type.is_billable:
hours_occupied = flt(
time_diff_in_hours(inpatient_occupancy.check_out, inpatient_occupancy.check_in), 2
time_diff_in_hours(inpatient_occupancy.check_out, inpatient_occupancy.check_in)
)
qty = 0.5
if hours_occupied > 0:
actual_qty = hours_occupied / service_unit_type.no_of_hours
floor = math.floor(actual_qty)
decimal_part = actual_qty - floor
if decimal_part > 0.5:
qty = rounded(floor + 1, 1)
elif decimal_part < 0.5 and decimal_part > 0:
qty = rounded(floor + 0.5, 1)
if qty <= 0:
qty = 0.5
qty = hours_occupied / service_unit_type.no_of_hours
if qty < service_unit_type.minimum_billable_qty:
qty = service_unit_type.minimum_billable_qty
services_to_invoice.append(
{
"reference_type": "Inpatient Occupancy",
Expand All @@ -312,6 +306,7 @@ def get_inpatient_services_to_invoice(patient, company):
"qty": item.quantity,
}
)
inpatient_record_doc.add_service_unit_rent_to_billable_items()

else:
ip = frappe.qb.DocType("Inpatient Record")
Expand Down

0 comments on commit c0ef79f

Please sign in to comment.