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
This commit is contained in:
anoop 2020-04-13 16:42:03 +05:30
parent f90ea8d622
commit c01fb2a4d8
2 changed files with 55 additions and 48 deletions

View File

@ -919,7 +919,7 @@ var get_healthcare_services_to_invoice = function(frm) {
if(patient && patient!=selected_patient){ if(patient && patient!=selected_patient){
selected_patient = patient; selected_patient = patient;
var method = "erpnext.healthcare.utils.get_healthcare_services_to_invoice"; 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"]); var columns = (["service", "reference_name", "reference_type"]);
get_healthcare_items(frm, true, $results, $placeholder, method, args, columns); 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.', 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) { get_query: function(doc) {
return { return {
filters: { patient: dialog.get_value("patient"), docstatus: 1 } filters: { patient: dialog.get_value("patient"),
company: frm.doc.company,
docstatus: 1
}
}; };
} }
}, },

View File

@ -3,66 +3,68 @@
# For license information, please see license.txt # For license information, please see license.txt
from __future__ import unicode_literals from __future__ import unicode_literals
import math
import json
import frappe import frappe
from frappe import _ from frappe import _
import math
from frappe.utils import time_diff_in_hours, rounded 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.healthcare_settings.healthcare_settings import get_income_account
from erpnext.healthcare.doctype.fee_validity.fee_validity import create_fee_validity from erpnext.healthcare.doctype.fee_validity.fee_validity import create_fee_validity
from erpnext.healthcare.doctype.lab_test.lab_test import create_multiple from erpnext.healthcare.doctype.lab_test.lab_test import create_multiple
@frappe.whitelist() @frappe.whitelist()
def get_healthcare_services_to_invoice(patient): def get_healthcare_services_to_invoice(patient, company):
patient = frappe.get_doc('Patient', patient) patient = frappe.get_doc('Patient', patient)
items_to_invoice = []
if patient: if patient:
validate_customer_created(patient) validate_customer_created(patient)
items_to_invoice = [] # Customer validated, build a list of billable services
patient_appointments = frappe.get_list( items_to_invoice += get_appointments_to_invoice(patient, company)
'Patient Appointment', items_to_invoice += get_encounters_to_invoice(patient, company)
fields='*', items_to_invoice += get_lab_tests_to_invoice(patient, company)
filters={'patient': patient.name, 'invoiced': 0}, items_to_invoice += get_clinical_procedures_to_invoice(patient, company)
order_by='appointment_date' items_to_invoice += get_inpatient_services_to_invoice(patient, company)
)
if patient_appointments:
items_to_invoice = get_fee_validity(patient_appointments)
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 return items_to_invoice
def validate_customer_created(patient): def validate_customer_created(patient):
if not frappe.db.get_value('Patient', patient.name, 'customer'): if not frappe.db.get_value('Patient', patient.name, 'customer'):
msg = _("Please set a Customer linked to the Patient") msg = _("Please set a Customer linked to the Patient")
msg += " <b><a href='#Form/Patient/{0}'>{0}</a></b>".format(patient.name) msg += " <b><a href='#Form/Patient/{0}'>{0}</a></b>".format(patient.name)
frappe.throw(msg, title=_('Customer Not Found')) 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: for appointment in patient_appointments:
# Procedure Appointments
if appointment.procedure_template: if appointment.procedure_template:
if frappe.db.get_value('Clinical Procedure Template', appointment.procedure_template, 'is_billable'): 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_type': 'Patient Appointment',
'reference_name': appointment.name, 'reference_name': appointment.name,
'service': appointment.procedure_template 'service': appointment.procedure_template
}) })
# Consultation Appointments, should check fee validity
else: else:
fee_validity = frappe.db.exists('Fee Validity Reference', {'appointment': appointment.name}) if frappe.db.get_single_value('Healthcare Settings', 'enable_free_follow_ups') and \
if not fee_validity: frappe.db.exists('Fee Validity Reference', {'appointment': appointment.name}):
continue # Skip invoicing, fee validty present
practitioner_charge = 0 practitioner_charge = 0
income_account = None income_account = None
service_item = None service_item = None
if appointment.practitioner: if appointment.practitioner:
service_item, practitioner_charge = get_service_item_and_practitioner_charge(appointment) service_item, practitioner_charge = get_service_item_and_practitioner_charge(appointment)
income_account = get_income_account(appointment.practitioner, appointment.company) income_account = get_income_account(appointment.practitioner, appointment.company)
items_to_invoice.append({ appointments_to_invoice.append({
'reference_type': 'Patient Appointment', 'reference_type': 'Patient Appointment',
'reference_name': appointment.name, 'reference_name': appointment.name,
'service': service_item, 'service': service_item,
@ -70,15 +72,15 @@ def get_fee_validity(patient_appointments):
'income_account': income_account '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_to_invoice = []
encounters = frappe.get_list( encounters = frappe.get_list(
'Patient Encounter', 'Patient Encounter',
fields=['*'], fields=['*'],
filters={'patient': patient.name, 'invoiced': False, 'docstatus': 1} filters={'patient': patient.name, 'company': company, 'invoiced': False, 'docstatus': 1}
) )
if encounters: if encounters:
for encounter in encounters: for encounter in encounters:
@ -101,12 +103,12 @@ def get_encounters_to_invoice(patient):
return encounters_to_invoice 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_to_invoice = []
lab_tests = frappe.get_list( lab_tests = frappe.get_list(
'Lab Test', 'Lab Test',
fields=['name', 'template'], 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: for lab_test in lab_tests:
item, is_billable = frappe.get_cached_value('Lab Test Template', lab_test.lab_test_code, ['item', 'is_billable']) 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 return lab_tests_to_invoice
def get_clinical_procedures_to_invoice(patient): def get_clinical_procedures_to_invoice(patient, company):
clinical_procedures_to_invoice = [] clinical_procedures_to_invoice = []
procedures = frappe.get_list( procedures = frappe.get_list(
'Clinical Procedure', 'Clinical Procedure',
fields='*', fields='*',
filters={'patient': patient.name, 'invoiced': False} filters={'patient': patient.name, 'company': company, 'invoiced': False}
) )
for procedure in procedures: for procedure in procedures:
if not procedure.appointment: if not procedure.appointment:
@ -203,7 +205,7 @@ def get_clinical_procedures_to_invoice(patient):
return clinical_procedures_to_invoice return clinical_procedures_to_invoice
def get_inpatient_services_to_invoice(patient): def get_inpatient_services_to_invoice(patient, company):
services_to_invoice = [] services_to_invoice = []
inpatient_services = frappe.db.sql( inpatient_services = frappe.db.sql(
''' '''
@ -213,10 +215,11 @@ def get_inpatient_services_to_invoice(patient):
`tabInpatient Record` ip, `tabInpatient Occupancy` io `tabInpatient Record` ip, `tabInpatient Occupancy` io
WHERE WHERE
ip.patient=%s ip.patient=%s
and ip.company=%s
and io.parent=ip.name and io.parent=ip.name
and io.left=1 and io.left=1
and io.invoiced=0 and io.invoiced=0
''', (patient.name), as_dict=1) ''', (patient.name, company), as_dict=1)
for inpatient_occupancy in inpatient_services: for inpatient_occupancy in inpatient_services:
service_unit_type = frappe.db.get_value('Healthcare Service Unit', inpatient_occupancy.service_unit, 'service_unit_type') 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): def manage_fee_validity(appointment):
fee_validity = check_fee_validity(appointment) fee_validity = check_fee_validity(appointment)
if fee_validity: if fee_validity:
if appointment.status == 'Cancelled' and fee_validity.visited > 0: if appointment.status == 'Cancelled' and fee_validity.visited > 0:
fee_validity.visited -= 1 fee_validity.visited -= 1