From c01fb2a4d8752b663828513fe722d4d62414b0da Mon Sep 17 00:00:00 2001 From: anoop Date: Mon, 13 Apr 2020 16:42:03 +0530 Subject: [PATCH] feat: multi-company billing sales onvoice - filter get items based on company utils - company filters in all get item helper methods utils - refactor appointemnt items --- .../doctype/sales_invoice/sales_invoice.js | 7 +- erpnext/healthcare/utils.py | 96 ++++++++++--------- 2 files changed, 55 insertions(+), 48 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js index 6f78db2ccc..7741842fca 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js @@ -919,7 +919,7 @@ var get_healthcare_services_to_invoice = function(frm) { if(patient && patient!=selected_patient){ selected_patient = patient; var method = "erpnext.healthcare.utils.get_healthcare_services_to_invoice"; - var args = {patient: patient}; + var args = {patient: patient, company: frm.doc.company}; var columns = (["service", "reference_name", "reference_type"]); get_healthcare_items(frm, true, $results, $placeholder, method, args, columns); } @@ -1063,7 +1063,10 @@ var get_drugs_to_invoice = function(frm) { description:'Quantity will be calculated only for items which has "Nos" as UoM. You may change as required for each invoice item.', get_query: function(doc) { return { - filters: { patient: dialog.get_value("patient"), docstatus: 1 } + filters: { patient: dialog.get_value("patient"), + company: frm.doc.company, + docstatus: 1 + } }; } }, diff --git a/erpnext/healthcare/utils.py b/erpnext/healthcare/utils.py index 246242ad84..e9cc597e81 100644 --- a/erpnext/healthcare/utils.py +++ b/erpnext/healthcare/utils.py @@ -3,82 +3,84 @@ # For license information, please see license.txt from __future__ import unicode_literals +import math +import json import frappe from frappe import _ -import math from frappe.utils import time_diff_in_hours, rounded from erpnext.healthcare.doctype.healthcare_settings.healthcare_settings import get_income_account from erpnext.healthcare.doctype.fee_validity.fee_validity import create_fee_validity from erpnext.healthcare.doctype.lab_test.lab_test import create_multiple @frappe.whitelist() -def get_healthcare_services_to_invoice(patient): +def get_healthcare_services_to_invoice(patient, company): patient = frappe.get_doc('Patient', patient) + items_to_invoice = [] if patient: validate_customer_created(patient) - items_to_invoice = [] - patient_appointments = frappe.get_list( - 'Patient Appointment', - fields='*', - filters={'patient': patient.name, 'invoiced': 0}, - order_by='appointment_date' - ) - if patient_appointments: - items_to_invoice = get_fee_validity(patient_appointments) + # Customer validated, build a list of billable services + items_to_invoice += get_appointments_to_invoice(patient, company) + items_to_invoice += get_encounters_to_invoice(patient, company) + items_to_invoice += get_lab_tests_to_invoice(patient, company) + items_to_invoice += get_clinical_procedures_to_invoice(patient, company) + items_to_invoice += get_inpatient_services_to_invoice(patient, company) - encounters = get_encounters_to_invoice(patient) - lab_tests = get_lab_tests_to_invoice(patient) - clinical_procedures = get_clinical_procedures_to_invoice(patient) - inpatient_services = get_inpatient_services_to_invoice(patient) - - items_to_invoice += encounters + lab_tests + clinical_procedures + inpatient_services return items_to_invoice + def validate_customer_created(patient): if not frappe.db.get_value('Patient', patient.name, 'customer'): msg = _("Please set a Customer linked to the Patient") msg += " {0}".format(patient.name) frappe.throw(msg, title=_('Customer Not Found')) -def get_fee_validity(patient_appointments): - if not frappe.db.get_single_value('Healthcare Settings', 'enable_free_follow_ups'): - return - items_to_invoice = [] +def get_appointments_to_invoice(patient, company): + appointments_to_invoice = [] + patient_appointments = frappe.get_list( + 'Patient Appointment', + fields = '*', + filters = {'patient': patient.name, 'company': company, 'invoiced': 0}, + order_by = 'appointment_date' + ) + for appointment in patient_appointments: + # Procedure Appointments if appointment.procedure_template: if frappe.db.get_value('Clinical Procedure Template', appointment.procedure_template, 'is_billable'): - items_to_invoice.append({ + appointments_to_invoice.append({ 'reference_type': 'Patient Appointment', 'reference_name': appointment.name, 'service': appointment.procedure_template }) + # Consultation Appointments, should check fee validity else: - fee_validity = frappe.db.exists('Fee Validity Reference', {'appointment': appointment.name}) - if not fee_validity: - practitioner_charge = 0 - income_account = None - service_item = None - if appointment.practitioner: - service_item, practitioner_charge = get_service_item_and_practitioner_charge(appointment) - income_account = get_income_account(appointment.practitioner, appointment.company) - items_to_invoice.append({ - 'reference_type': 'Patient Appointment', - 'reference_name': appointment.name, - 'service': service_item, - 'rate': practitioner_charge, - 'income_account': income_account - }) + if frappe.db.get_single_value('Healthcare Settings', 'enable_free_follow_ups') and \ + frappe.db.exists('Fee Validity Reference', {'appointment': appointment.name}): + continue # Skip invoicing, fee validty present + practitioner_charge = 0 + income_account = None + service_item = None + if appointment.practitioner: + service_item, practitioner_charge = get_service_item_and_practitioner_charge(appointment) + income_account = get_income_account(appointment.practitioner, appointment.company) + appointments_to_invoice.append({ + 'reference_type': 'Patient Appointment', + 'reference_name': appointment.name, + 'service': service_item, + 'rate': practitioner_charge, + 'income_account': income_account + }) - return items_to_invoice + return appointments_to_invoice -def get_encounters_to_invoice(patient): +def get_encounters_to_invoice(patient, company): encounters_to_invoice = [] encounters = frappe.get_list( 'Patient Encounter', fields=['*'], - filters={'patient': patient.name, 'invoiced': False, 'docstatus': 1} + filters={'patient': patient.name, 'company': company, 'invoiced': False, 'docstatus': 1} ) if encounters: for encounter in encounters: @@ -101,12 +103,12 @@ def get_encounters_to_invoice(patient): return encounters_to_invoice -def get_lab_tests_to_invoice(patient): +def get_lab_tests_to_invoice(patient, company): lab_tests_to_invoice = [] lab_tests = frappe.get_list( 'Lab Test', fields=['name', 'template'], - filters={'patient': patient.name, 'invoiced': False, 'docstatus': 1} + filters={'patient': patient.name, 'company': company, 'invoiced': False, 'docstatus': 1} ) for lab_test in lab_tests: item, is_billable = frappe.get_cached_value('Lab Test Template', lab_test.lab_test_code, ['item', 'is_billable']) @@ -142,12 +144,12 @@ def get_lab_tests_to_invoice(patient): return lab_tests_to_invoice -def get_clinical_procedures_to_invoice(patient): +def get_clinical_procedures_to_invoice(patient, company): clinical_procedures_to_invoice = [] procedures = frappe.get_list( 'Clinical Procedure', fields='*', - filters={'patient': patient.name, 'invoiced': False} + filters={'patient': patient.name, 'company': company, 'invoiced': False} ) for procedure in procedures: if not procedure.appointment: @@ -203,7 +205,7 @@ def get_clinical_procedures_to_invoice(patient): return clinical_procedures_to_invoice -def get_inpatient_services_to_invoice(patient): +def get_inpatient_services_to_invoice(patient, company): services_to_invoice = [] inpatient_services = frappe.db.sql( ''' @@ -213,10 +215,11 @@ def get_inpatient_services_to_invoice(patient): `tabInpatient Record` ip, `tabInpatient Occupancy` io WHERE ip.patient=%s + and ip.company=%s and io.parent=ip.name and io.left=1 and io.invoiced=0 - ''', (patient.name), as_dict=1) + ''', (patient.name, company), as_dict=1) for inpatient_occupancy in inpatient_services: service_unit_type = frappe.db.get_value('Healthcare Service Unit', inpatient_occupancy.service_unit, 'service_unit_type') @@ -376,6 +379,7 @@ def check_fee_validity(appointment): def manage_fee_validity(appointment): fee_validity = check_fee_validity(appointment) + if fee_validity: if appointment.status == 'Cancelled' and fee_validity.visited > 0: fee_validity.visited -= 1