earthians / marley

Open Source Health Information System
https://frappehealth.com
GNU General Public License v3.0
334 stars 257 forks source link

Healthcare: Group healthcare Items in sales invoice #80

Open mujeerhashmi opened 4 years ago

mujeerhashmi commented 4 years ago

@ruchamahabal @akurungadam

Is your feature request related to a problem? Please describe. If the inpatient record has the same items [same inpatient occupancy added multiple times after transfers] and when creating a sales invoice for this patient the items table in the sales invoice will have multiple entries for the same item. As you can see in the image below, Deluxe Room is present twice, Instead, it can be one item with qty=2(1.5+0.5).

duplicate_item

Describe the solution you'd like The healthcare services when added to the sales invoice need to be grouped by item and their quantities added.

mujeerhashmi commented 4 years ago

@ruchamahabal @akurungadam

I see that every healthcare service in the inpatient record is a unique entry in DB & is tracked to be invoiced or not before the patient is discharged. As such every line item in the sales invoice is mapped to unique DB entries of healthcare services using custom fields reference_dt and reference_dn (Link type). This is resulting in multiple entries of the same healthcare service in the sales invoice.

Design Proposal: reference_dn should be changed to reference_names(short text type). Just like we handle serial_nos, multiples doctype names can be added here to this field after grouping them together from set_healthcare_services in salesinvoice.py. Here is a code that works.

    # Healthcare
    def set_healthcare_services(self, checked_values):      
        self.set("items", [])       
        from itertools import groupby
        from erpnext.stock.get_item_details import get_item_details
        def get_dt_key(item):
            return item['dt']

        def get_item_key(item):
            return item['item']

        for dt_key, value in groupby(sorted(checked_values, key=get_dt_key), get_dt_key):
            for item_key, item_value in groupby(sorted(list(value), key=get_item_key), get_item_key):                               
                item_line = self.append("items", {})
                grouped_items = list(item_value)
                price_list, price_list_currency = frappe.db.get_values("Price List", {"selling": 1}, ['name', 'currency'])[0]
                args = {
                    'doctype': "Sales Invoice",
                    'item_code': item_key,
                    'company': self.company,
                    'customer': frappe.db.get_value("Patient", self.patient, "customer"),
                    'selling_price_list': price_list,
                    'price_list_currency': price_list_currency,
                    'plc_conversion_rate': 1.0,
                    'conversion_rate': 1.0
                }
                item_details = get_item_details(args)
                item_line.item_code = item_key              
                qty = 1

                dn = []
                for ip_item in grouped_items:
                    qty += float(ip_item['qty'])
                    if (ip_item['dn']):
                        dn.append(ip_item['dn'])

                item_line.qty = qty 

                checked_item = grouped_items[0]

                if checked_item['rate']:
                    item_line.rate = checked_item['rate']
                else:
                    item_line.rate = item_details.price_list_rate
                    item_line.amount = float(item_line.rate) * float(item_line.qty)
                if checked_item['income_account']:
                    item_line.income_account = checked_item['income_account']
                if checked_item['dt']:
                    item_line.reference_dt = checked_item['dt']
                if len(dn) > 0:                 
                    item_line.reference_names = "\n".join(dn)
                if checked_item['description']:
                    item_line.description = checked_item['description']
        self.set_missing_values(for_validate = True)
stale[bot] commented 2 years ago

This issue has been automatically marked as inactive because it has not had recent activity and it wasn't validated by maintainer team. It will be closed within a week if no further activity occurs.