Clinical Procedure - Consumables Invoice Separately
diff --git a/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.js b/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.js
index 9fc5b37..7f866e1 100644
--- a/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.js
+++ b/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.js
@@ -264,21 +264,20 @@
let args = null;
if(d.item_code) {
args = {
- 'item_code' : d.item_code,
- 'transfer_qty' : d.transfer_qty,
- 'company' : frm.doc.company,
- 'quantity' : d.qty
+ 'doctype' : "Clinical Procedure",
+ 'item_code' : d.item_code,
+ 'company' : frm.doc.company,
+ 'warehouse': frm.doc.warehouse
};
return frappe.call({
- doc: frm.doc,
- method: "get_item_details",
- args: args,
+ method: "erpnext.stock.get_item_details.get_item_details",
+ args: {args: args},
callback: function(r) {
if(r.message) {
- var d = locals[cdt][cdn];
- $.each(r.message, function(k, v){
- d[k] = v;
- });
+ frappe.model.set_value(cdt, cdn, "item_name", r.message.item_name);
+ frappe.model.set_value(cdt, cdn, "stock_uom", r.message.stock_uom);
+ frappe.model.set_value(cdt, cdn, "conversion_factor", r.message.conversion_factor);
+ frappe.model.set_value(cdt, cdn, "actual_qty", r.message.actual_qty);
refresh_field("items");
}
}
diff --git a/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.json b/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.json
index 0856606..a830c37 100644
--- a/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.json
+++ b/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.json
@@ -711,6 +711,139 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "default": "0",
+ "fieldname": "invoice_separately_as_consumables",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Consumables Invoice Separately",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "depends_on": "invoice_separately_as_consumables",
+ "fieldname": "consumable_total_amount",
+ "fieldtype": "Currency",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Consumable Total Amount",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "depends_on": "invoice_separately_as_consumables",
+ "fieldname": "consumption_details",
+ "fieldtype": "Small Text",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Consumption Details",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "default": "0",
+ "depends_on": "invoice_separately_as_consumables",
+ "fieldname": "consumption_invoiced",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Consumption Invoiced",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
"default": "",
"fieldname": "status",
"fieldtype": "Select",
diff --git a/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.py b/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.py
index d51d062..4a4bd39 100644
--- a/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.py
+++ b/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.py
@@ -10,6 +10,7 @@
from erpnext.healthcare.doctype.healthcare_settings.healthcare_settings import get_account
from erpnext.healthcare.doctype.lab_test.lab_test import create_sample_doc
from erpnext.stock.stock_ledger import get_previous_sle
+from erpnext.stock.get_item_details import get_item_details
class ClinicalProcedure(Document):
def validate(self):
@@ -18,6 +19,12 @@
frappe.throw(("Set warehouse for Procedure {0} ").format(self.name))
self.set_actual_qty()
+ if self.items:
+ self.invoice_separately_as_consumables = False
+ for item in self.items:
+ if item.invoice_separately_as_consumables == 1:
+ self.invoice_separately_as_consumables = True
+
def before_insert(self):
if self.consume_stock:
set_stock_items(self, self.procedure_template, "Clinical Procedure Template")
@@ -40,6 +47,36 @@
create_stock_entry(self)
frappe.db.set_value("Clinical Procedure", self.name, "status", 'Completed')
+ if self.items:
+ consumable_total_amount = 0
+ consumption_details = False
+ for item in self.items:
+ if item.invoice_separately_as_consumables:
+ price_list, price_list_currency = frappe.db.get_values("Price List", {"selling": 1}, ['name', 'currency'])[0]
+ args = {
+ 'doctype': "Sales Invoice",
+ 'item_code': item.item_code,
+ 'company': self.company,
+ 'warehouse': self.warehouse,
+ '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_price = item_details.price_list_rate * item.transfer_qty
+ item_consumption_details = item_details.item_name+"\t"+str(item.qty)+" "+item.uom+"\t"+str(item_price)
+ consumable_total_amount += item_price
+ if not consumption_details:
+ consumption_details = "Clinical Procedure ("+self.name+"):\n\t"+item_consumption_details
+ else:
+ consumption_details += "\n\t"+item_consumption_details
+ if consumable_total_amount > 0:
+ frappe.db.set_value("Clinical Procedure", self.name, "consumable_total_amount", consumable_total_amount)
+ frappe.db.set_value("Clinical Procedure", self.name, "consumption_details", consumption_details)
+
+
def start(self):
allow_start = self.set_actual_qty()
if allow_start:
@@ -54,16 +91,7 @@
allow_start = True
for d in self.get('items'):
- previous_sle = get_previous_sle({
- "item_code": d.item_code,
- "warehouse": self.warehouse,
- "posting_date": nowdate(),
- "posting_time": nowtime()
- })
-
- # get actual stock at source warehouse
- d.actual_qty = previous_sle.get("qty_after_transaction") or 0
-
+ d.actual_qty = get_stock_qty(d.item_code, self.warehouse)
# validate qty
if not allow_negative_stock and d.actual_qty < d.qty:
allow_start = False
@@ -93,28 +121,14 @@
se_child.expense_account = expense_account
return stock_entry.as_dict()
- def get_item_details(self, args=None):
- item = frappe.db.sql("""select stock_uom, description, image, item_name,
- expense_account, buying_cost_center, item_group from `tabItem`
- where name = %s
- and disabled=0
- and (end_of_life is null or end_of_life='0000-00-00' or end_of_life > %s)""",
- (args.get('item_code'), nowdate()), as_dict = 1)
- if not item:
- frappe.throw(_("Item {0} is not active or end of life has been reached").format(args.get('item_code')))
-
- item = item[0]
-
- ret = {
- 'uom' : item.stock_uom,
- 'stock_uom' : item.stock_uom,
- 'item_name' : item.item_name,
- 'quantity' : 0,
- 'transfer_qty' : 0,
- 'conversion_factor' : 1
- }
- return ret
-
+@frappe.whitelist()
+def get_stock_qty(item_code, warehouse):
+ return get_previous_sle({
+ "item_code": item_code,
+ "warehouse": warehouse,
+ "posting_date": nowdate(),
+ "posting_time": nowtime()
+ }).get("qty_after_transaction") or 0
@frappe.whitelist()
def set_stock_items(doc, stock_detail_parent, parenttype):