Skip to content

Commit

Permalink
Merge pull request #337 from frappe/version-14-hotfix
Browse files Browse the repository at this point in the history
chore: release v14
  • Loading branch information
akashkrishna619 authored Nov 28, 2023
2 parents 92176d5 + 1ef7d96 commit e4b80eb
Show file tree
Hide file tree
Showing 7 changed files with 265 additions and 43 deletions.
2 changes: 0 additions & 2 deletions healthcare/healthcare/doctype/lab_test/lab_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,6 @@ def create_multiple(doctype, docname):
frappe.msgprint(
_("Lab Test(s) {0} created successfully").format(lab_test_created), indicator="green"
)
else:
frappe.msgprint(_("No Lab Tests created"))


def create_lab_test_from_encounter(encounter):
Expand Down
51 changes: 38 additions & 13 deletions healthcare/healthcare/doctype/patient/patient.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ def onload(self):
def validate(self):
self.set_full_name()
self.flags.is_new_doc = self.is_new()
self.flags.existing_customer = self.is_new() and bool(self.customer)

def before_insert(self):
self.set_missing_customer_details()
Expand All @@ -46,18 +47,13 @@ def after_insert(self):
def on_update(self):
if frappe.db.get_single_value("Healthcare Settings", "link_customer_to_patient"):
if self.customer:
customer = frappe.get_doc("Customer", self.customer)
if self.customer_group:
customer.customer_group = self.customer_group
if self.territory:
customer.territory = self.territory
customer.customer_name = self.patient_name
customer.default_price_list = self.default_price_list
customer.default_currency = self.default_currency
customer.language = self.language
customer.image = self.image
customer.ignore_mandatory = True
customer.save(ignore_permissions=True)
if self.flags.existing_customer or frappe.db.exists(
{"doctype": "Patient", "name": ["!=", self.name], "customer": self.customer}
):
self.update_patient_based_on_existing_customer()
else:
self.update_linked_customer()

else:
create_customer(self)

Expand Down Expand Up @@ -253,6 +249,35 @@ def update_contact(self, contact):
contact.flags.skip_patient_update = True
contact.save(ignore_permissions=True)

def update_linked_customer(self):
customer = frappe.get_doc("Customer", self.customer)
if self.customer_group:
customer.customer_group = self.customer_group
if self.territory:
customer.territory = self.territory
customer.customer_name = self.patient_name
customer.default_price_list = self.default_price_list
customer.default_currency = self.default_currency
customer.language = self.language
customer.image = self.image
customer.ignore_mandatory = True
customer.save(ignore_permissions=True)

frappe.msgprint(_("Customer {0} updated").format(customer.name), alert=True)

def update_patient_based_on_existing_customer(self):
customer = frappe.get_doc("Customer", self.customer)
self.db_set(
{
"customer_group": customer.customer_group,
"territory": customer.territory,
"default_price_list": customer.default_price_list,
"default_currency": customer.default_currency,
"language": customer.language,
}
)
self.notify_update()


def create_customer(doc):
customer = frappe.get_doc(
Expand All @@ -271,7 +296,7 @@ def create_customer(doc):
).insert(ignore_permissions=True, ignore_mandatory=True)

frappe.db.set_value("Patient", doc.name, "customer", customer.name)
frappe.msgprint(_("Customer {0} is created.").format(customer.name), alert=True)
frappe.msgprint(_("Customer {0} created and linked to Patient").format(customer.name), alert=True)


def make_invoice(patient, company):
Expand Down
16 changes: 16 additions & 0 deletions healthcare/healthcare/doctype/patient/test_patient.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,3 +115,19 @@ def test_patient_image_update_should_update_customer_image(self):

customer = frappe.get_doc("Customer", patient.customer)
self.assertEqual(customer.image, patient.image)

def test_multiple_paients_linked_with_same_customer(self):
frappe.db.sql("""delete from `tabPatient`""")
frappe.db.set_single_value("Healthcare Settings", "link_customer_to_patient", 1)

patient_name_1 = create_patient(patient_name="John Doe")
p1_customer_name = frappe.get_value("Patient", patient_name_1, "customer")
p1_customer = frappe.get_doc("Customer", p1_customer_name)
self.assertEqual(p1_customer.customer_name, "John Doe")

patient_name_2 = create_patient(patient_name="Jane Doe", customer=p1_customer.name)
p2_customer_name = frappe.get_value("Patient", patient_name_2, "customer")
p2_customer = frappe.get_doc("Customer", p2_customer_name)

self.assertEqual(p1_customer_name, p2_customer_name)
self.assertEqual(p2_customer.customer_name, "John Doe")
Original file line number Diff line number Diff line change
Expand Up @@ -880,11 +880,40 @@ let make_payment = function (frm, automate_invoicing) {
options: "Mode of Payment",
reqd: 1,
},
{
fieldtype: "Column Break",
},
{
label: "Consultation Charge",
fieldname: "consultation_charge",
fieldtype: "Currency",
read_only: true,
},
{
label: "Total Payable",
fieldname: "total_payable",
fieldtype: "Currency",
read_only: true,
},
{
label: __("Additional Discount"),
fieldtype:"Section Break",
collapsible: 1,
},
{
label: "Discount Percentage",
fieldname: "discount_percentage",
fieldtype: "Percent",
default: 0,
},
{
fieldtype: "Column Break",
},
{
label: "Discount Amount",
fieldname: "discount_amount",
fieldtype: "Currency",
default: 0,
}
];

Expand All @@ -895,23 +924,23 @@ let make_payment = function (frm, automate_invoicing) {
fieldtype: "Data",
read_only: true,
};
fields.splice(1, 0, pract_dict);
fields.splice(3, 0, pract_dict);
} else if (frm.doc.appointment_for == "Service Unit") {
let su_dict = {
label: "Service Unit",
fieldname: "service_unit",
fieldtype: "Data",
read_only: true,
};
fields.splice(1, 0, su_dict);
fields.splice(3, 0, su_dict);
} else if (frm.doc.appointment_for == "Department") {
let dept_dict = {
label: "Department",
fieldname: "department",
fieldtype: "Data",
read_only: true,
};
fields.splice(1, 0, dept_dict);
fields.splice(3, 0, dept_dict);
}

if (automate_invoicing) {
Expand All @@ -924,16 +953,24 @@ let make_payment = function (frm, automate_invoicing) {
title: "Enter Payment Details",
fields: fields,
primary_action_label: "Create Invoice",
primary_action(values) {
frm.set_value("mode_of_payment", values.mode_of_payment)
frm.save();
primary_action: async function(values) {
if (frm.is_dirty()) {
await frm.save();
}
frappe.call({
method: "healthcare.healthcare.doctype.patient_appointment.patient_appointment.invoice_appointment",
args: { "appointment_name": frm.doc.name },
args: {
"appointment_name": frm.doc.name,
"discount_percentage": values.discount_percentage,
"discount_amount": values.discount_amount
},
callback: async function (data) {
if (!data.exc) {
await frm.reload_doc();
if (frm.doc.ref_sales_invoice) {
d.get_field("mode_of_payment").$input.prop("disabled", true);
d.get_field("discount_percentage").$input.prop("disabled", true);
d.get_field("discount_amount").$input.prop("disabled", true);
d.get_primary_btn().attr("disabled", true);
d.get_secondary_btn().attr("disabled", false);
}
Expand All @@ -949,10 +986,16 @@ let make_payment = function (frm, automate_invoicing) {
d.hide();
}
});
d.fields_dict["mode_of_payment"].df.onchange = () => {
if (d.get_value("mode_of_payment")) {
frm.set_value("mode_of_payment", d.get_value("mode_of_payment"));
}
};
d.get_secondary_btn().attr("disabled", true);
d.set_values({
"patient": frm.doc.patient_name,
"consultation_charge": frm.doc.paid_amount,
"total_payable": frm.doc.paid_amount,
});

if (frm.doc.appointment_for == "Practitioner") {
Expand All @@ -967,5 +1010,56 @@ let make_payment = function (frm, automate_invoicing) {
d.set_value("mode_of_payment", frm.doc.mode_of_payment);
}
d.show();

d.fields_dict["discount_percentage"].df.onchange = () => validate_discount("discount_percentage");
d.fields_dict["discount_amount"].df.onchange = () => validate_discount("discount_amount");

function validate_discount(field) {
let message = "";
let discount_percentage = d.get_value("discount_percentage");
let discount_amount = d.get_value("discount_amount");
let consultation_charge = d.get_value("consultation_charge");

if (field === "discount_percentage") {
if (discount_percentage > 100 || discount_percentage < 0) {
d.get_primary_btn().attr("disabled", true);
message = "Invalid discount percentage";
} else {
d.get_primary_btn().attr("disabled", false);
frm.via_discount_percentage = true;
if (discount_percentage && discount_amount) {
d.set_value("discount_amount", 0);
}
discount_amount = consultation_charge * (discount_percentage / 100);

d.set_values({
"discount_amount": discount_amount,
"total_payable": consultation_charge - discount_amount,
}).then(() => delete frm.via_discount_percentage);
}
} else if (field === "discount_amount") {
if (consultation_charge < discount_amount || discount_amount < 0) {
d.get_primary_btn().attr("disabled", true);
message = "Discount amount should not be more than Consultation Charge";
} else {
d.get_primary_btn().attr("disabled", false);
if (!frm.via_discount_percentage) {
discount_percentage = (discount_amount / consultation_charge) * 100;
d.set_values({
"discount_percentage": discount_percentage,
"total_payable": consultation_charge - discount_amount,
});
}
}
}
show_message(d, message, field);
}
}
};

let show_message = function(d, message, field) {
var field = d.get_field(field);
field.df.description = `<div style="color:red;
padding:5px 5px 5px 5px">${message}</div>`
field.refresh();
};
Original file line number Diff line number Diff line change
Expand Up @@ -352,17 +352,27 @@ def update_event(self):
self.google_meet_link = event_doc.google_meet_link

def set_postition_in_queue(self):
from frappe.query_builder.functions import Max

if self.status == "Checked In" and not self.position_in_queue:
app_count = frappe.db.count(
"Patient Appointment",
{
"status": "Checked In",
"practitioner": self.practitioner,
"service_unit": self.service_unit,
"appointment_time": self.appointment_time,
},
)
self.position_in_queue = app_count + 1
appointment = frappe.qb.DocType("Patient Appointment")
position = (
frappe.qb.from_(appointment)
.select(
Max(appointment.position_in_queue).as_("max_position"),
)
.where(
(appointment.status == "Checked In")
& (appointment.practitioner == self.practitioner)
& (appointment.service_unit == self.service_unit)
& (appointment.appointment_time == self.appointment_time)
)
).run(as_dict=True)[0]
position_in_queue = 1
if position and position.get("max_position"):
position_in_queue = position.get("max_position") + 1

self.position_in_queue = position_in_queue


@frappe.whitelist()
Expand All @@ -383,12 +393,11 @@ def check_payment_reqd(patient):


@frappe.whitelist()
def invoice_appointment(appointment_name):
def invoice_appointment(appointment_name, discount_percentage=0, discount_amount=0):
appointment_doc = frappe.get_doc("Patient Appointment", appointment_name)
show_payment_popup = frappe.db.get_single_value("Healthcare Settings", "show_payment_popup")
free_follow_ups = frappe.db.get_single_value("Healthcare Settings", "enable_free_follow_ups")
settings = frappe.get_single("Healthcare Settings")

if free_follow_ups:
if settings.enable_free_follow_ups:
fee_validity = check_fee_validity(appointment_doc)

if fee_validity and fee_validity.status != "Active":
Expand All @@ -399,12 +408,12 @@ def invoice_appointment(appointment_name):
else:
fee_validity = None

if show_payment_popup and not appointment_doc.invoiced and not fee_validity:
create_sales_invoice(appointment_doc)
if settings.show_payment_popup and not appointment_doc.invoiced and not fee_validity:
create_sales_invoice(appointment_doc, discount_percentage, discount_amount)
update_fee_validity(appointment_doc)


def create_sales_invoice(appointment_doc):
def create_sales_invoice(appointment_doc, discount_percentage=0, discount_amount=0):
sales_invoice = frappe.new_doc("Sales Invoice")
sales_invoice.patient = appointment_doc.patient
sales_invoice.customer = frappe.get_value("Patient", appointment_doc.patient, "customer")
Expand All @@ -416,12 +425,23 @@ def create_sales_invoice(appointment_doc):
item = sales_invoice.append("items", {})
item = get_appointment_item(appointment_doc, item)

paid_amount = flt(appointment_doc.paid_amount)
# Set discount amount and percentage if entered in payment popup
if flt(discount_percentage):
sales_invoice.additional_discount_percentage = flt(discount_percentage)
paid_amount = flt(appointment_doc.paid_amount) - (
flt(appointment_doc.paid_amount) * (flt(discount_percentage) / 100)
)
if flt(discount_amount):
sales_invoice.discount_amount = flt(discount_amount)
paid_amount = flt(appointment_doc.paid_amount) - flt(discount_amount)

# Add payments if payment details are supplied else proceed to create invoice as Unpaid
if appointment_doc.mode_of_payment and appointment_doc.paid_amount:
sales_invoice.is_pos = 1
payment = sales_invoice.append("payments", {})
payment.mode_of_payment = appointment_doc.mode_of_payment
payment.amount = appointment_doc.paid_amount
payment.amount = paid_amount

sales_invoice.set_missing_values(for_validate=True)
sales_invoice.flags.ignore_mandatory = True
Expand All @@ -434,10 +454,10 @@ def create_sales_invoice(appointment_doc):
{
"invoiced": 1,
"ref_sales_invoice": sales_invoice.name,
"paid_amount": appointment_doc.paid_amount,
"paid_amount": paid_amount,
},
)
appointment_doc.reload()
appointment_doc.notify_update()


@frappe.whitelist()
Expand Down
Loading

0 comments on commit e4b80eb

Please sign in to comment.