Merge branch 'develop' into sales-analytics

This commit is contained in:
Anupam Kumar 2020-09-14 11:21:58 -07:00 committed by GitHub
commit 8cb356bf30
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 1055 additions and 1399 deletions

View File

@ -55,7 +55,7 @@ class BankStatementTransactionEntry(Document):
def populate_payment_entries(self):
if self.bank_statement is None: return
filename = self.bank_statement.split("/")[-1]
file_url = self.bank_statement
if (len(self.new_transaction_items + self.reconciled_transaction_items) > 0):
frappe.throw(_("Transactions already retreived from the statement"))
@ -65,7 +65,7 @@ class BankStatementTransactionEntry(Document):
if self.bank_settings:
mapped_items = frappe.get_doc("Bank Statement Settings", self.bank_settings).mapped_items
statement_headers = self.get_statement_headers()
transactions = get_transaction_entries(filename, statement_headers)
transactions = get_transaction_entries(file_url, statement_headers)
for entry in transactions:
date = entry[statement_headers["Date"]].strip()
#print("Processing entry DESC:{0}-W:{1}-D:{2}-DT:{3}".format(entry["Particulars"], entry["Withdrawals"], entry["Deposits"], entry["Date"]))
@ -398,20 +398,21 @@ def get_transaction_info(headers, header_index, row):
transaction[header] = ""
return transaction
def get_transaction_entries(filename, headers):
def get_transaction_entries(file_url, headers):
header_index = {}
rows, transactions = [], []
if (filename.lower().endswith("xlsx")):
if (file_url.lower().endswith("xlsx")):
from frappe.utils.xlsxutils import read_xlsx_file_from_attached_file
rows = read_xlsx_file_from_attached_file(file_id=filename)
elif (filename.lower().endswith("csv")):
rows = read_xlsx_file_from_attached_file(file_url=file_url)
elif (file_url.lower().endswith("csv")):
from frappe.utils.csvutils import read_csv_content
_file = frappe.get_doc("File", {"file_name": filename})
_file = frappe.get_doc("File", {"file_url": file_url})
filepath = _file.get_full_path()
with open(filepath,'rb') as csvfile:
rows = read_csv_content(csvfile.read())
elif (filename.lower().endswith("xls")):
elif (file_url.lower().endswith("xls")):
filename = file_url.split("/")[-1]
rows = get_rows_from_xls_file(filename)
else:
frappe.throw(_("Only .csv and .xlsx files are supported currently"))

View File

@ -7,6 +7,7 @@ import json
from frappe import _, throw
from frappe.utils import (today, flt, cint, fmt_money, formatdate,
getdate, add_days, add_months, get_last_day, nowdate, get_link_to_form)
from frappe.model.workflow import get_workflow_name, is_transition_condition_satisfied, WorkflowPermissionError
from erpnext.stock.get_item_details import get_conversion_factor, get_item_details
from erpnext.setup.utils import get_exchange_rate
from erpnext.accounts.utils import get_fiscal_years, validate_fiscal_year, get_account_currency
@ -1194,7 +1195,7 @@ def set_purchase_order_defaults(parent_doctype, parent_doctype_name, child_docna
child_item.base_amount = 1 # Initiallize value will update in parent validation
return child_item
def check_and_delete_children(parent, data):
def validate_and_delete_children(parent, data):
deleted_children = []
updated_item_names = [d.get("docname") for d in data]
for item in parent.items:
@ -1221,18 +1222,37 @@ def check_and_delete_children(parent, data):
@frappe.whitelist()
def update_child_qty_rate(parent_doctype, trans_items, parent_doctype_name, child_docname="items"):
def check_permissions(doc, perm_type='create'):
def check_doc_permissions(doc, perm_type='create'):
try:
doc.check_permission(perm_type)
except:
action = "add" if perm_type == 'create' else "update"
frappe.throw(_("You do not have permissions to {} items in a Sales Order.").format(action), title=_("Insufficient Permissions"))
except frappe.PermissionError:
actions = { 'create': 'add', 'write': 'update', 'cancel': 'remove' }
frappe.throw(_("You do not have permissions to {} items in a {}.")
.format(actions[perm_type], parent_doctype), title=_("Insufficient Permissions"))
def validate_workflow_conditions(doc):
workflow = get_workflow_name(doc.doctype)
if not workflow:
return
workflow_doc = frappe.get_doc("Workflow", workflow)
current_state = doc.get(workflow_doc.workflow_state_field)
roles = frappe.get_roles()
transitions = []
for transition in workflow_doc.transitions:
if transition.next_state == current_state and transition.allowed in roles:
if not is_transition_condition_satisfied(transition, doc):
continue
transitions.append(transition.as_dict())
if not transitions:
frappe.throw(_("You do not have workflow access to update this document."), title=_("Insufficient Workflow Permissions"))
def get_new_child_item(item_row):
if parent_doctype == "Sales Order":
return set_sales_order_defaults(parent_doctype, parent_doctype_name, child_docname, item_row)
if parent_doctype == "Purchase Order":
return set_purchase_order_defaults(parent_doctype, parent_doctype_name, child_docname, item_row)
new_child_function = set_sales_order_defaults if parent_doctype == "Sales Order" else set_purchase_order_defaults
return new_child_function(parent_doctype, parent_doctype_name, child_docname, item_row)
def validate_quantity(child_item, d):
if parent_doctype == "Sales Order" and flt(d.get("qty")) < flt(child_item.delivered_qty):
@ -1246,16 +1266,17 @@ def update_child_qty_rate(parent_doctype, trans_items, parent_doctype_name, chil
sales_doctypes = ['Sales Order', 'Sales Invoice', 'Delivery Note', 'Quotation']
parent = frappe.get_doc(parent_doctype, parent_doctype_name)
check_and_delete_children(parent, data)
check_doc_permissions(parent, 'cancel')
validate_and_delete_children(parent, data)
for d in data:
new_child_flag = False
if not d.get("docname"):
new_child_flag = True
check_permissions(parent, 'create')
check_doc_permissions(parent, 'create')
child_item = get_new_child_item(d)
else:
check_permissions(parent, 'write')
check_doc_permissions(parent, 'write')
child_item = frappe.get_doc(parent_doctype + ' Item', d.get("docname"))
prev_rate, new_rate = flt(child_item.get("rate")), flt(d.get("rate"))
@ -1362,6 +1383,9 @@ def update_child_qty_rate(parent_doctype, trans_items, parent_doctype_name, chil
parent.update_prevdoc_status('submit')
parent.update_delivery_status()
parent.reload()
validate_workflow_conditions(parent)
parent.update_blanket_order()
parent.update_billing_percentage()
parent.set_status()

View File

@ -3,15 +3,15 @@
frappe.ui.form.on('Student', {
setup: function(frm) {
frm.add_fetch("guardian", "guardian_name", "guardian_name");
frm.add_fetch("student", "title", "full_name");
frm.add_fetch("student", "gender", "gender");
frm.add_fetch("student", "date_of_birth", "date_of_birth");
frm.add_fetch('guardian', 'guardian_name', 'guardian_name');
frm.add_fetch('student', 'title', 'full_name');
frm.add_fetch('student', 'gender', 'gender');
frm.add_fetch('student', 'date_of_birth', 'date_of_birth');
frm.set_query("student", "siblings", function(doc, cdt, cdn) {
frm.set_query('student', 'siblings', function(doc) {
return {
"filters": {
"name": ["!=", doc.name]
'filters': {
'name': ['!=', doc.name]
}
};
})
@ -25,6 +25,12 @@ frappe.ui.form.on('Student', {
{party_type:'Student', party:frm.doc.name});
});
}
frappe.db.get_value('Education Settings', {name: 'Education Settings'}, 'user_creation_skip', (r) => {
if (cint(r.user_creation_skip) !== 1) {
frm.set_df_property('student_email_id', 'reqd', 1);
}
});
}
});

View File

@ -102,7 +102,6 @@
"fieldtype": "Data",
"in_global_search": 1,
"label": "Student Email Address",
"reqd": 1,
"unique": 1
},
{
@ -255,7 +254,7 @@
],
"image_field": "image",
"links": [],
"modified": "2020-07-23 18:14:06.366442",
"modified": "2020-09-07 19:28:08.914568",
"modified_by": "Administrator",
"module": "Education",
"name": "Student",

View File

@ -7,7 +7,7 @@ frappe.ui.form.on("Student Applicant", {
},
refresh: function(frm) {
if(frm.doc.application_status== "Applied" && frm.doc.docstatus== 1 ) {
if (frm.doc.application_status==="Applied" && frm.doc.docstatus===1 ) {
frm.add_custom_button(__("Approve"), function() {
frm.set_value("application_status", "Approved");
frm.save_or_update();
@ -20,10 +20,11 @@ frappe.ui.form.on("Student Applicant", {
}, 'Actions');
}
if(frm.doc.application_status== "Approved" && frm.doc.docstatus== 1 ) {
if (frm.doc.application_status === "Approved" && frm.doc.docstatus === 1) {
frm.add_custom_button(__("Enroll"), function() {
frm.events.enroll(frm)
}).addClass("btn-primary");
frm.add_custom_button(__("Reject"), function() {
frm.set_value("application_status", "Rejected");
frm.save_or_update();
@ -35,7 +36,13 @@ frappe.ui.form.on("Student Applicant", {
frappe.hide_msgprint(true);
frappe.show_progress(__("Enrolling student"), data.progress[0],data.progress[1]);
}
})
});
frappe.db.get_value("Education Settings", {name: "Education Settings"}, "user_creation_skip", (r) => {
if (cint(r.user_creation_skip) !== 1) {
frm.set_df_property("student_email_id", "reqd", 1);
}
});
},
enroll: function(frm) {

View File

@ -34,10 +34,10 @@ frappe.ui.form.on('Lab Test', {
if (frm.doc.docstatus === 1 && frm.doc.status !== 'Approved' && frm.doc.status !== 'Rejected') {
frm.add_custom_button(__('Approve'), function () {
status_update(1, frm);
});
}, __('Actions'));
frm.add_custom_button(__('Reject'), function () {
status_update(0, frm);
});
}, __('Actions'));
}
}
@ -179,23 +179,6 @@ var show_lab_tests = function (frm, lab_test_list) {
d.show();
};
cur_frm.cscript.custom_before_submit = function (doc) {
if (doc.normal_test_items) {
for (let result in doc.normal_test_items) {
if (!doc.normal_test_items[result].result_value && !doc.normal_test_items[result].allow_blank && doc.normal_test_items[result].require_result_value) {
frappe.throw(__('Please input all required result values'));
}
}
}
if (doc.descriptive_test_items) {
for (let result in doc.descriptive_test_items) {
if (!doc.descriptive_test_items[result].result_value && !doc.descriptive_test_items[result].allow_blank && doc.descriptive_test_items[result].require_result_value) {
frappe.throw(__('Please input all required result values'));
}
}
}
};
var make_dialog = function (frm, emailed, printed) {
var number = frm.doc.mobile;
@ -203,7 +186,7 @@ var make_dialog = function (frm, emailed, printed) {
title: 'Send SMS',
width: 400,
fields: [
{ fieldname: 'sms_type', fieldtype: 'Select', label: 'Type', options: ['Emailed', 'Printed'] },
{ fieldname: 'result_format', fieldtype: 'Select', label: 'Result Format', options: ['Emailed', 'Printed'] },
{ fieldname: 'number', fieldtype: 'Data', label: 'Mobile Number', reqd: 1 },
{ fieldname: 'message', fieldtype: 'Small Text', label: 'Message', reqd: 1 }
],
@ -217,22 +200,22 @@ var make_dialog = function (frm, emailed, printed) {
dialog.hide();
}
});
if (frm.doc.report_preference == 'Print') {
if (frm.doc.report_preference === 'Print') {
dialog.set_values({
'sms_type': 'Printed',
'result_format': 'Printed',
'number': number,
'message': printed
});
} else {
dialog.set_values({
'sms_type': 'Emailed',
'result_format': 'Emailed',
'number': number,
'message': emailed
});
}
var fd = dialog.fields_dict;
$(fd.sms_type.input).change(function () {
if (dialog.get_value('sms_type') == 'Emailed') {
$(fd.result_format.input).change(function () {
if (dialog.get_value('result_format') === 'Emailed') {
dialog.set_values({
'number': number,
'message': emailed

View File

@ -84,7 +84,7 @@
"fieldname": "naming_series",
"fieldtype": "Select",
"label": "Series",
"options": "LP-",
"options": "HLC-LAB-.YYYY.-",
"print_hide": 1,
"report_hide": 1,
"reqd": 1
@ -197,11 +197,10 @@
{
"fieldname": "status",
"fieldtype": "Select",
"in_list_view": 1,
"label": "Status",
"options": "Draft\nCompleted\nApproved\nRejected\nCancelled",
"print_hide": 1,
"read_only": 1,
"report_hide": 1,
"search_index": 1
},
{
@ -249,8 +248,8 @@
{
"fieldname": "result_date",
"fieldtype": "Date",
"hidden": 1,
"label": "Result Date",
"read_only": 1,
"search_index": 1
},
{
@ -354,7 +353,8 @@
},
{
"fieldname": "sb_normal",
"fieldtype": "Section Break"
"fieldtype": "Section Break",
"label": "Compound Test Result"
},
{
"fieldname": "normal_test_items",
@ -369,11 +369,13 @@
{
"depends_on": "descriptive_toggle",
"fieldname": "organisms_section",
"fieldtype": "Section Break"
"fieldtype": "Section Break",
"label": "Organism Test Result"
},
{
"fieldname": "sb_sensitivity",
"fieldtype": "Section Break"
"fieldtype": "Section Break",
"label": "Sensitivity Test Result"
},
{
"fieldname": "sensitivity_test_items",
@ -383,8 +385,10 @@
"report_hide": 1
},
{
"collapsible": 1,
"fieldname": "sb_comments",
"fieldtype": "Section Break"
"fieldtype": "Section Break",
"label": "Comments"
},
{
"fieldname": "lab_test_comment",
@ -531,7 +535,8 @@
},
{
"fieldname": "sb_descriptive",
"fieldtype": "Section Break"
"fieldtype": "Section Break",
"label": "Descriptive Test Result"
},
{
"default": "0",
@ -550,7 +555,7 @@
],
"is_submittable": 1,
"links": [],
"modified": "2020-07-16 13:35:24.811062",
"modified": "2020-07-30 18:18:38.516215",
"modified_by": "Administrator",
"module": "Healthcare",
"name": "Lab Test",

View File

@ -6,23 +6,24 @@ from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.model.document import Document
from frappe.utils import getdate, cstr
from frappe.utils import getdate, cstr, get_link_to_form
class LabTest(Document):
def validate(self):
if not self.is_new():
self.set_secondary_uom_result()
def on_submit(self):
self.validate_result_values()
self.db_set('submitted_date', getdate())
self.db_set('status', 'Completed')
insert_lab_test_to_medical_record(self)
def on_cancel(self):
delete_lab_test_from_medical_record(self)
self.db_set('status', 'Cancelled')
delete_lab_test_from_medical_record(self)
self.reload()
def validate(self):
if not self.is_new():
self.set_secondary_uom_result()
def on_update(self):
if self.sensitivity_test_items:
sensitivity = sorted(self.sensitivity_test_items, key=lambda x: x.antibiotic_sensitivity)
@ -51,7 +52,20 @@ class LabTest(Document):
item.secondary_uom_result = float(item.result_value) * float(item.conversion_factor)
except:
item.secondary_uom_result = ''
frappe.msgprint(_('Result for Secondary UOM not calculated for row #{0}'.format(item.idx)), title = _('Warning'))
frappe.msgprint(_('Row #{0}: Result for Secondary UOM not calculated'.format(item.idx)), title = _('Warning'))
def validate_result_values(self):
if self.normal_test_items:
for item in self.normal_test_items:
if not item.result_value and not item.allow_blank and item.require_result_value:
frappe.throw(_('Row #{0}: Please enter the result value for {1}').format(
item.idx, frappe.bold(item.lab_test_name)), title=_('Mandatory Results'))
if self.descriptive_test_items:
for item in self.descriptive_test_items:
if not item.result_value and not item.allow_blank and item.require_result_value:
frappe.throw(_('Row #{0}: Please enter the result value for {1}').format(
item.idx, frappe.bold(item.lab_test_particulars)), title=_('Mandatory Results'))
def create_test_from_template(lab_test):
@ -89,7 +103,7 @@ def create_multiple(doctype, docname):
lab_test_created = create_lab_test_from_encounter(docname)
if lab_test_created:
frappe.msgprint(_('Lab Test(s) {0} created'.format(lab_test_created)))
frappe.msgprint(_('Lab Test(s) {0} created successfully').format(lab_test_created), indicator='green')
else:
frappe.msgprint(_('No Lab Tests created'))
@ -211,8 +225,9 @@ def create_sample_doc(template, patient, invoice, company = None):
'docstatus': 0,
'sample': template.sample
})
if sample_exists:
# Update Sample Collection by adding quantity
# update sample collection by adding quantity
sample_collection = frappe.get_doc('Sample Collection', sample_exists[0][0])
quantity = int(sample_collection.sample_qty) + int(template.sample_qty)
if template.sample_details:
@ -238,7 +253,7 @@ def create_sample_doc(template, patient, invoice, company = None):
sample_collection.company = company
if template.sample_details:
sample_collection.sample_details = 'Test :' + (template.get('lab_test_name') or template.get('template')) + '\n' + 'Collection Detials:\n\t' + template.sample_details
sample_collection.sample_details = _('Test :') + (template.get('lab_test_name') or template.get('template')) + '\n' + 'Collection Detials:\n\t' + template.sample_details
sample_collection.save(ignore_permissions=True)
return sample_collection
@ -248,26 +263,31 @@ def create_sample_collection(lab_test, template, patient, invoice):
sample_collection = create_sample_doc(template, patient, invoice, lab_test.company)
if sample_collection:
lab_test.sample = sample_collection.name
sample_collection_doc = get_link_to_form('Sample Collection', sample_collection.name)
frappe.msgprint(_('Sample Collection {0} has been created').format(sample_collection_doc),
title=_('Sample Collection'), indicator='green')
return lab_test
def load_result_format(lab_test, template, prescription, invoice):
if template.lab_test_template_type == 'Single':
create_normals(template, lab_test)
elif template.lab_test_template_type == 'Compound':
create_compounds(template, lab_test, False)
elif template.lab_test_template_type == 'Descriptive':
create_descriptives(template, lab_test)
elif template.lab_test_template_type == 'Grouped':
# Iterate for each template in the group and create one result for all.
for lab_test_group in template.lab_test_groups:
# Template_in_group = None
if lab_test_group.lab_test_template:
template_in_group = frappe.get_doc('Lab Test Template',
lab_test_group.lab_test_template)
template_in_group = frappe.get_doc('Lab Test Template', lab_test_group.lab_test_template)
if template_in_group:
if template_in_group.lab_test_template_type == 'Single':
create_normals(template_in_group, lab_test)
elif template_in_group.lab_test_template_type == 'Compound':
normal_heading = lab_test.append('normal_test_items')
normal_heading.lab_test_name = template_in_group.lab_test_name
@ -275,6 +295,7 @@ def load_result_format(lab_test, template, prescription, invoice):
normal_heading.allow_blank = 1
normal_heading.template = template_in_group.name
create_compounds(template_in_group, lab_test, True)
elif template_in_group.lab_test_template_type == 'Descriptive':
descriptive_heading = lab_test.append('descriptive_test_items')
descriptive_heading.lab_test_name = template_in_group.lab_test_name
@ -282,6 +303,7 @@ def load_result_format(lab_test, template, prescription, invoice):
descriptive_heading.allow_blank = 1
descriptive_heading.template = template_in_group.name
create_descriptives(template_in_group, lab_test)
else: # Lab Test Group - Add New Line
normal = lab_test.append('normal_test_items')
normal.lab_test_name = lab_test_group.group_event
@ -292,6 +314,7 @@ def load_result_format(lab_test, template, prescription, invoice):
normal.allow_blank = lab_test_group.allow_blank
normal.require_result_value = 1
normal.template = template.name
if template.lab_test_template_type != 'No Result':
if prescription:
lab_test.prescription = prescription
@ -302,9 +325,10 @@ def load_result_format(lab_test, template, prescription, invoice):
@frappe.whitelist()
def get_employee_by_user_id(user_id):
emp_id = frappe.db.get_value('Employee', { 'user_id': user_id })
employee = frappe.get_doc('Employee', emp_id)
return employee
emp_id = frappe.db.exists('Employee', { 'user_id': user_id })
if emp_id:
return frappe.get_doc('Employee', emp_id)
return None
def insert_lab_test_to_medical_record(doc):
table_row = False

View File

@ -3,13 +3,16 @@
*/
frappe.listview_settings['Lab Test'] = {
add_fields: ['name', 'status', 'invoiced'],
filters: [['docstatus', '=', '0']],
filters: [['docstatus', '=', '1']],
get_indicator: function (doc) {
if (doc.status == 'Approved') {
if (doc.status === 'Approved') {
return [__('Approved'), 'green', 'status, =, Approved'];
}
if (doc.status == 'Rejected') {
} else if (doc.status === 'Rejected') {
return [__('Rejected'), 'orange', 'status, =, Rejected'];
} else if (doc.status === 'Completed') {
return [__('Completed'), 'green', 'status, =, Completed'];
} else if (doc.status === 'Cancelled') {
return [__('Cancelled'), 'red', 'status, =, Cancelled'];
}
},
onload: function (listview) {
@ -21,7 +24,7 @@ frappe.listview_settings['Lab Test'] = {
var create_multiple_dialog = function (listview) {
var dialog = new frappe.ui.Dialog({
title: 'Create Multiple Lab Test',
title: 'Create Multiple Lab Tests',
width: 100,
fields: [
{ fieldtype: 'Link', label: 'Patient', fieldname: 'patient', options: 'Patient', reqd: 1 },
@ -41,7 +44,7 @@ var create_multiple_dialog = function (listview) {
}
}
],
primary_action_label: __('Create Lab Test'),
primary_action_label: __('Create'),
primary_action: function () {
frappe.call({
method: 'erpnext.healthcare.doctype.lab_test.lab_test.create_multiple',

View File

@ -3,8 +3,204 @@
# See license.txt
from __future__ import unicode_literals
import unittest
# test_records = frappe.get_test_records('Lab Test')
import frappe
from frappe.utils import getdate, nowtime
from erpnext.healthcare.doctype.patient_appointment.test_patient_appointment import create_patient
from erpnext.healthcare.doctype.lab_test.lab_test import create_multiple
from erpnext.healthcare.doctype.healthcare_settings.healthcare_settings import get_receivable_account, get_income_account
from erpnext.healthcare.doctype.patient_medical_record.test_patient_medical_record import create_lab_test_template as create_blood_test_template
class TestLabTest(unittest.TestCase):
pass
def test_lab_test_item(self):
lab_template = create_lab_test_template()
self.assertTrue(frappe.db.exists('Item', lab_template.item))
self.assertEqual(frappe.db.get_value('Item Price', {'item_code':lab_template.item}, 'price_list_rate'), lab_template.lab_test_rate)
lab_template.disabled = 1
lab_template.save()
self.assertEquals(frappe.db.get_value('Item', lab_template.item, 'disabled'), 1)
lab_template.reload()
lab_template.disabled = 0
lab_template.save()
def test_descriptive_lab_test(self):
lab_template = create_lab_test_template()
# blank result value not allowed as per template
lab_test = create_lab_test(lab_template)
lab_test.descriptive_test_items[0].result_value = 12
lab_test.descriptive_test_items[2].result_value = 1
lab_test.save()
self.assertRaises(frappe.ValidationError, lab_test.submit)
def test_sample_collection(self):
frappe.db.set_value('Healthcare Settings', 'Healthcare Settings', 'create_sample_collection_for_lab_test', 1)
lab_template = create_lab_test_template()
lab_test = create_lab_test(lab_template)
lab_test.descriptive_test_items[0].result_value = 12
lab_test.descriptive_test_items[1].result_value = 1
lab_test.descriptive_test_items[2].result_value = 2.3
lab_test.save()
# check sample collection created
self.assertTrue(frappe.db.exists('Sample Collection', {'sample': lab_template.sample}))
frappe.db.set_value('Healthcare Settings', 'Healthcare Settings', 'create_sample_collection_for_lab_test', 0)
lab_test = create_lab_test(lab_template)
lab_test.descriptive_test_items[0].result_value = 12
lab_test.descriptive_test_items[1].result_value = 1
lab_test.descriptive_test_items[2].result_value = 2.3
lab_test.save()
# sample collection should not be created
lab_test.reload()
self.assertEquals(lab_test.sample, None)
def test_create_lab_tests_from_sales_invoice(self):
sales_invoice = create_sales_invoice()
create_multiple('Sales Invoice', sales_invoice.name)
sales_invoice.reload()
self.assertIsNotNone(sales_invoice.items[0].reference_dn)
self.assertIsNotNone(sales_invoice.items[1].reference_dn)
def test_create_lab_tests_from_patient_encounter(self):
patient_encounter = create_patient_encounter()
create_multiple('Patient Encounter', patient_encounter.name)
patient_encounter.reload()
self.assertTrue(patient_encounter.lab_test_prescription[0].lab_test_created)
self.assertTrue(patient_encounter.lab_test_prescription[0].lab_test_created)
def create_lab_test_template(test_sensitivity=0, sample_collection=1):
medical_department = create_medical_department()
if frappe.db.exists('Lab Test Template', 'Insulin Resistance'):
return frappe.get_doc('Lab Test Template', 'Insulin Resistance')
template = frappe.new_doc('Lab Test Template')
template.lab_test_name = 'Insulin Resistance'
template.lab_test_template_type = 'Descriptive'
template.lab_test_code = 'Insulin Resistance'
template.lab_test_group = 'Services'
template.department = medical_department
template.is_billable = 1
template.lab_test_description = 'Insulin Resistance'
template.lab_test_rate = 2000
for entry in ['FBS', 'Insulin', 'IR']:
template.append('descriptive_test_templates', {
'particulars': entry,
'allow_blank': 1 if entry=='IR' else 0
})
if test_sensitivity:
template.sensitivity = 1
if sample_collection:
template.sample = create_lab_test_sample()
template.sample_qty = 5.0
template.save()
return template
def create_medical_department():
medical_department = frappe.db.exists('Medical Department', '_Test Medical Department')
if not medical_department:
medical_department = frappe.new_doc('Medical Department')
medical_department.department = '_Test Medical Department'
medical_department.save()
medical_department = medical_department.name
return medical_department
def create_lab_test(lab_template):
patient = create_patient()
lab_test = frappe.new_doc('Lab Test')
lab_test.template = lab_template.name
lab_test.patient = patient
lab_test.patient_sex = 'Female'
lab_test.save()
return lab_test
def create_lab_test_sample():
blood_sample = frappe.db.exists('Lab Test Sample', 'Blood Sample')
if blood_sample:
return blood_sample
sample = frappe.new_doc('Lab Test Sample')
sample.sample = 'Blood Sample'
sample.sample_uom = 'U/ml'
sample.save()
return sample.name
def create_sales_invoice():
patient = create_patient()
medical_department = create_medical_department()
insulin_resistance_template = create_lab_test_template()
blood_test_template = create_blood_test_template(medical_department)
sales_invoice = frappe.new_doc('Sales Invoice')
sales_invoice.patient = patient
sales_invoice.customer = frappe.db.get_value('Patient', patient, 'customer')
sales_invoice.due_date = getdate()
sales_invoice.company = '_Test Company'
sales_invoice.debit_to = get_receivable_account('_Test Company')
tests = [insulin_resistance_template, blood_test_template]
for entry in tests:
sales_invoice.append('items', {
'item_code': entry.item,
'item_name': entry.lab_test_name,
'description': entry.lab_test_description,
'qty': 1,
'uom': 'Nos',
'conversion_factor': 1,
'income_account': get_income_account(None, '_Test Company'),
'rate': entry.lab_test_rate,
'amount': entry.lab_test_rate
})
sales_invoice.set_missing_values()
sales_invoice.submit()
return sales_invoice
def create_patient_encounter():
patient = create_patient()
medical_department = create_medical_department()
insulin_resistance_template = create_lab_test_template()
blood_test_template = create_blood_test_template(medical_department)
patient_encounter = frappe.new_doc('Patient Encounter')
patient_encounter.patient = patient
patient_encounter.practitioner = create_practitioner()
patient_encounter.encounter_date = getdate()
patient_encounter.encounter_time = nowtime()
tests = [insulin_resistance_template, blood_test_template]
for entry in tests:
patient_encounter.append('lab_test_prescription', {
'lab_test_code': entry.item,
'lab_test_name': entry.lab_test_name
})
patient_encounter.submit()
return patient_encounter
def create_practitioner():
practitioner = frappe.db.exists('Healthcare Practitioner', '_Test Healthcare Practitioner')
if not practitioner:
practitioner = frappe.new_doc('Healthcare Practitioner')
practitioner.first_name = '_Test Healthcare Practitioner'
practitioner.gender = 'Female'
practitioner.op_consulting_charge = 500
practitioner.inpatient_visit_charge = 500
practitioner.save(ignore_permissions=True)
practitioner = practitioner.name
return practitioner

View File

@ -93,7 +93,8 @@
"depends_on": "secondary_uom",
"fieldname": "conversion_factor",
"fieldtype": "Float",
"label": "Conversion Factor"
"label": "Conversion Factor",
"mandatory_depends_on": "secondary_uom"
},
{
"default": "0",
@ -106,7 +107,7 @@
],
"istable": 1,
"links": [],
"modified": "2020-06-24 10:59:01.921924",
"modified": "2020-07-30 12:36:03.082391",
"modified_by": "Administrator",
"module": "Healthcare",
"name": "Lab Test Group Template",

View File

@ -34,14 +34,15 @@
"descriptive_test_templates",
"section_break_group",
"lab_test_groups",
"medical_coding_section",
"medical_code_standard",
"medical_code",
"sb_sample_collection",
"sample",
"sample_uom",
"sample_qty",
"column_break_33",
"sample_details",
"medical_coding_section",
"medical_code",
"medical_code_standard",
"worksheet_section",
"worksheet_instructions",
"result_legend_section",
@ -112,7 +113,7 @@
{
"default": "1",
"depends_on": "eval:doc.lab_test_template_type != 'Grouped'",
"description": "If unchecked, the item wont be appear in Sales Invoice, but can be used in group test creation. ",
"description": "If unchecked, the item will not be available in Sales Invoices for billing but can be used in group test creation. ",
"fieldname": "is_billable",
"fieldtype": "Check",
"label": "Is Billable",
@ -128,6 +129,7 @@
"mandatory_depends_on": "eval:doc.is_billable == 1"
},
{
"collapsible": 1,
"fieldname": "medical_coding_section",
"fieldtype": "Section Break",
"label": "Medical Coding"
@ -184,7 +186,7 @@
"depends_on": "eval:doc.lab_test_template_type == 'Descriptive'",
"fieldname": "section_break_special",
"fieldtype": "Section Break",
"label": "Descriptive"
"label": "Descriptive Test"
},
{
"default": "0",
@ -196,7 +198,7 @@
"depends_on": "eval:doc.lab_test_template_type == 'Grouped'",
"fieldname": "section_break_group",
"fieldtype": "Section Break",
"label": "Group"
"label": "Group Tests"
},
{
"fieldname": "lab_test_groups",
@ -217,7 +219,6 @@
"no_copy": 1
},
{
"collapsible": 1,
"fieldname": "sb_sample_collection",
"fieldtype": "Section Break",
"label": "Sample Collection"
@ -311,10 +312,14 @@
"fieldname": "descriptive_test_templates",
"fieldtype": "Table",
"options": "Descriptive Test Template"
},
{
"fieldname": "column_break_33",
"fieldtype": "Column Break"
}
],
"links": [],
"modified": "2020-07-13 12:57:09.925436",
"modified": "2020-07-30 14:32:40.449818",
"modified_by": "Administrator",
"module": "Healthcare",
"name": "Lab Test Template",

View File

@ -15,7 +15,8 @@ class LabTestTemplate(Document):
def validate(self):
if self.is_billable and (not self.lab_test_rate or self.lab_test_rate <= 0.0):
frappe.throw(_("Standard Selling Rate should be greater than zero."))
frappe.throw(_('Standard Selling Rate should be greater than zero.'))
self.validate_conversion_factor()
self.enable_disable_item()
@ -42,7 +43,9 @@ class LabTestTemplate(Document):
# Remove template reference from item and disable item
if self.item:
try:
frappe.delete_doc('Item', self.item)
item = self.item
self.db_set('item', '')
frappe.delete_doc('Item', item)
except Exception:
frappe.throw(_('Not permitted. Please disable the Lab Test Template'))
@ -63,26 +66,26 @@ class LabTestTemplate(Document):
'standard_rate': self.lab_test_rate,
'description': self.lab_test_description
})
item.save()
item.flags.ignore_mandatory = True
item.save(ignore_permissions=True)
def item_price_exists(self):
item_price = frappe.db.exists({'doctype': 'Item Price', 'item_code': self.lab_test_code})
if item_price:
return item_price[0][0]
else:
return False
def validate_conversion_factor(self):
if self.lab_test_template_type == "Single" and self.secondary_uom and not self.conversion_factor:
frappe.throw(_("Conversion Factor is mandatory"))
if self.lab_test_template_type == "Compound":
if self.lab_test_template_type == 'Single' and self.secondary_uom and not self.conversion_factor:
frappe.throw(_('Conversion Factor is mandatory'))
if self.lab_test_template_type == 'Compound':
for item in self.normal_test_templates:
if item.secondary_uom and not item.conversion_factor:
frappe.throw(_("Conversion Factor is mandatory"))
if self.lab_test_template_type == "Grouped":
frappe.throw(_('Row #{0}: Conversion Factor is mandatory').format(item.idx))
if self.lab_test_template_type == 'Grouped':
for group in self.lab_test_groups:
if group.template_or_new_line == "Add New Line" and group.secondary_uom and not group.conversion_factor:
frappe.throw(_("Conversion Factor is mandatory"))
if group.template_or_new_line == 'Add New Line' and group.secondary_uom and not group.conversion_factor:
frappe.throw(_('Row #{0}: Conversion Factor is mandatory').format(group.idx))
def create_item_from_template(doc):

View File

@ -0,0 +1,13 @@
from __future__ import unicode_literals
from frappe import _
def get_data():
return {
'fieldname': 'template',
'transactions': [
{
'label': _('Lab Tests'),
'items': ['Lab Test']
}
]
}

View File

@ -3,5 +3,5 @@
*/
frappe.listview_settings['Lab Test Template'] = {
add_fields: ['lab_test_name', 'lab_test_code', 'lab_test_rate'],
filters: [['disabled', '=', 0]]
filters: [['disabled', '=', 'No']]
};

View File

@ -34,7 +34,7 @@ class TestPatientMedicalRecord(unittest.TestCase):
self.assertTrue(medical_rec)
template = create_lab_test_template(medical_department)
lab_test = create_lab_test(template, patient)
lab_test = create_lab_test(template.name, patient)
# check for lab test
medical_rec = frappe.db.exists('Patient Medical Record', {'status': 'Open', 'reference_name': lab_test.name})
self.assertTrue(medical_rec)
@ -66,7 +66,7 @@ def create_vital_signs(appointment):
def create_lab_test_template(medical_department):
if frappe.db.exists('Lab Test Template', 'Blood Test'):
return 'Blood Test'
return frappe.get_doc('Lab Test Template', 'Blood Test')
template = frappe.new_doc('Lab Test Template')
template.lab_test_name = 'Blood Test'
@ -76,7 +76,7 @@ def create_lab_test_template(medical_department):
template.is_billable = 1
template.lab_test_rate = 2000
template.save()
return template.name
return template
def create_lab_test(template, patient):
lab_test = frappe.new_doc('Lab Test')

View File

@ -3,19 +3,19 @@
frappe.ui.form.on('Sample Collection', {
refresh: function(frm) {
if(frappe.defaults.get_default("create_sample_collection_for_lab_test")){
frm.add_custom_button(__("View Lab Tests"), function() {
frappe.route_options = {"sample": frm.doc.name};
frappe.set_route("List", "Lab Test");
if (frappe.defaults.get_default('create_sample_collection_for_lab_test')) {
frm.add_custom_button(__('View Lab Tests'), function() {
frappe.route_options = {'sample': frm.doc.name};
frappe.set_route('List', 'Lab Test');
});
}
}
});
frappe.ui.form.on("Sample Collection", "patient", function(frm) {
frappe.ui.form.on('Sample Collection', 'patient', function(frm) {
if(frm.doc.patient){
frappe.call({
"method": "erpnext.healthcare.doctype.patient.patient.get_patient_detail",
'method': 'erpnext.healthcare.doctype.patient.patient.get_patient_detail',
args: {
patient: frm.doc.patient
},
@ -24,8 +24,8 @@ frappe.ui.form.on("Sample Collection", "patient", function(frm) {
if (data.message.dob){
age = calculate_age(data.message.dob);
}
frappe.model.set_value(frm.doctype,frm.docname, "patient_age", age);
frappe.model.set_value(frm.doctype,frm.docname, "patient_sex", data.message.sex);
frappe.model.set_value(frm.doctype,frm.docname, 'patient_age', age);
frappe.model.set_value(frm.doctype,frm.docname, 'patient_sex', data.message.sex);
}
});
}
@ -36,5 +36,5 @@ var calculate_age = function(birth) {
var age = new Date();
age.setTime(ageMS);
var years = age.getFullYear() - 1970;
return years + " Year(s) " + age.getMonth() + " Month(s) " + age.getDate() + " Day(s)";
return years + ' Year(s) ' + age.getMonth() + ' Month(s) ' + age.getDate() + ' Day(s)';
};

View File

@ -9,8 +9,10 @@
"document_type": "Document",
"engine": "InnoDB",
"field_order": [
"patient_details_section",
"naming_series",
"patient",
"patient_name",
"patient_age",
"patient_sex",
"column_break_4",
@ -25,15 +27,17 @@
"collected_by",
"collected_time",
"num_print",
"amended_from",
"section_break_15",
"sample_details"
"sample_details",
"amended_from"
],
"fields": [
{
"fetch_from": "patient.inpatient_record",
"fieldname": "inpatient_record",
"fieldtype": "Link",
"hide_days": 1,
"hide_seconds": 1,
"label": "Inpatient Record",
"options": "Inpatient Record",
"read_only": 1
@ -42,6 +46,8 @@
"bold": 1,
"fieldname": "naming_series",
"fieldtype": "Select",
"hide_days": 1,
"hide_seconds": 1,
"label": "Series",
"no_copy": 1,
"options": "HLC-SC-.YYYY.-",
@ -52,6 +58,8 @@
"default": "0",
"fieldname": "invoiced",
"fieldtype": "Check",
"hide_days": 1,
"hide_seconds": 1,
"label": "Invoiced",
"no_copy": 1,
"read_only": 1,
@ -61,41 +69,60 @@
"fetch_from": "inpatient_record.patient",
"fieldname": "patient",
"fieldtype": "Link",
"hide_days": 1,
"hide_seconds": 1,
"ignore_user_permissions": 1,
"in_standard_filter": 1,
"label": "Patient",
"options": "Patient",
"reqd": 1,
"search_index": 1
},
{
"fieldname": "column_break_4",
"fieldtype": "Column Break"
"fieldtype": "Column Break",
"hide_days": 1,
"hide_seconds": 1
},
{
"fieldname": "patient_age",
"fieldtype": "Data",
"label": "Age"
"hide_days": 1,
"hide_seconds": 1,
"label": "Age",
"read_only": 1
},
{
"fetch_from": "patient.sex",
"fieldname": "patient_sex",
"fieldtype": "Data",
"label": "Gender"
"fieldtype": "Link",
"hide_days": 1,
"hide_seconds": 1,
"label": "Gender",
"options": "Gender",
"read_only": 1
},
{
"fieldname": "company",
"fieldtype": "Link",
"hide_days": 1,
"hide_seconds": 1,
"in_standard_filter": 1,
"label": "Company",
"options": "Company"
},
{
"fieldname": "section_break_6",
"fieldtype": "Section Break"
"fieldtype": "Section Break",
"hide_days": 1,
"hide_seconds": 1,
"label": "Sample Details"
},
{
"fieldname": "sample",
"fieldtype": "Link",
"hide_days": 1,
"hide_seconds": 1,
"ignore_user_permissions": 1,
"in_list_view": 1,
"in_standard_filter": 1,
@ -108,16 +135,23 @@
"fetch_from": "sample.sample_uom",
"fieldname": "sample_uom",
"fieldtype": "Data",
"hide_days": 1,
"hide_seconds": 1,
"in_list_view": 1,
"label": "UOM"
"label": "UOM",
"read_only": 1
},
{
"fieldname": "column_break_10",
"fieldtype": "Column Break"
"fieldtype": "Column Break",
"hide_days": 1,
"hide_seconds": 1
},
{
"fieldname": "collected_by",
"fieldtype": "Link",
"hide_days": 1,
"hide_seconds": 1,
"ignore_user_permissions": 1,
"label": "Collected By",
"options": "User"
@ -125,20 +159,27 @@
{
"fieldname": "collected_time",
"fieldtype": "Datetime",
"label": "Collected Time"
"hide_days": 1,
"hide_seconds": 1,
"label": "Collected On"
},
{
"allow_on_submit": 1,
"default": "1",
"description": "Number of prints required for labelling the samples",
"fieldname": "num_print",
"fieldtype": "Int",
"label": "No. of print",
"hide_days": 1,
"hide_seconds": 1,
"label": "No. of prints",
"print_hide": 1,
"report_hide": 1
},
{
"fieldname": "amended_from",
"fieldtype": "Link",
"hide_days": 1,
"hide_seconds": 1,
"label": "Amended From",
"no_copy": 1,
"options": "Sample Collection",
@ -147,25 +188,43 @@
},
{
"fieldname": "section_break_15",
"fieldtype": "Section Break"
"fieldtype": "Section Break",
"hide_days": 1,
"hide_seconds": 1
},
{
"default": "0",
"fieldname": "sample_qty",
"fieldtype": "Float",
"hide_days": 1,
"hide_seconds": 1,
"in_list_view": 1,
"label": "Quantity"
},
{
"fieldname": "sample_details",
"fieldtype": "Long Text",
"hide_days": 1,
"hide_seconds": 1,
"ignore_xss_filter": 1,
"label": "Collection Details"
},
{
"fieldname": "patient_details_section",
"fieldtype": "Section Break",
"label": "Patient Details"
},
{
"fetch_from": "patient.patient_name",
"fieldname": "patient_name",
"fieldtype": "Data",
"label": "Patient Name",
"read_only": 1
}
],
"is_submittable": 1,
"links": [],
"modified": "2020-05-25 14:36:46.990469",
"modified": "2020-07-30 16:53:13.076104",
"modified_by": "Administrator",
"module": "Healthcare",
"name": "Sample Collection",

View File

@ -3,7 +3,12 @@
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
from frappe.model.document import Document
from frappe.utils import flt
from frappe import _
class SampleCollection(Document):
pass
def validate(self):
if flt(self.sample_qty) <= 0:
frappe.throw(_('Sample Quantity cannot be negative or 0'), title=_('Invalid Quantity'))

View File

@ -7,14 +7,28 @@ frappe.query_reports["Lab Test Report"] = {
"fieldname": "from_date",
"label": __("From Date"),
"fieldtype": "Date",
"default": frappe.datetime.now_date(),
"width": "80"
"default": frappe.datetime.add_months(frappe.datetime.get_today(), -1),
"reqd": 1
},
{
"fieldname": "to_date",
"label": __("To Date"),
"fieldtype": "Date",
"default": frappe.datetime.now_date()
"default": frappe.datetime.now_date(),
"reqd": 1
},
{
"fieldname": "company",
"label": __("Company"),
"fieldtype": "Link",
"default": frappe.defaults.get_default("Company"),
"options": "Company"
},
{
"fieldname": "template",
"label": __("Lab Test Template"),
"fieldtype": "Link",
"options": "Lab Test Template"
},
{
"fieldname": "patient",
@ -27,6 +41,17 @@ frappe.query_reports["Lab Test Report"] = {
"label": __("Medical Department"),
"fieldtype": "Link",
"options": "Medical Department"
},
{
"fieldname": "status",
"label": __("Status"),
"fieldtype": "Select",
"options": "\nCompleted\nApproved\nRejected"
},
{
"fieldname": "invoiced",
"label": __("Invoiced"),
"fieldtype": "Check"
}
]
};

View File

@ -1,12 +1,13 @@
{
"add_total_row": 1,
"add_total_row": 0,
"creation": "2013-04-23 18:15:29",
"disable_prepared_report": 0,
"disabled": 0,
"docstatus": 0,
"doctype": "Report",
"idx": 1,
"is_standard": "Yes",
"modified": "2018-08-06 11:41:50.218737",
"modified": "2020-07-30 18:53:20.102873",
"modified_by": "Administrator",
"module": "Healthcare",
"name": "Lab Test Report",

View File

@ -8,51 +8,204 @@ from frappe import msgprint, _
def execute(filters=None):
if not filters: filters = {}
lab_test_list = get_lab_test(filters)
data, columns = [], []
columns = get_columns()
lab_test_list = get_lab_tests(filters)
if not lab_test_list:
msgprint(_("No record found"))
msgprint(_('No records found'))
return columns, lab_test_list
data = []
for lab_test in lab_test_list:
row = [ lab_test.lab_test_name, lab_test.patient, lab_test.practitioner, lab_test.invoiced, lab_test.status, lab_test.result_date, lab_test.department]
row = frappe._dict({
'test': lab_test.name,
'template': lab_test.template,
'company': lab_test.company,
'patient': lab_test.patient,
'patient_name': lab_test.patient_name,
'practitioner': lab_test.practitioner,
'employee': lab_test.employee,
'status': lab_test.status,
'invoiced': lab_test.invoiced,
'result_date': lab_test.result_date,
'department': lab_test.department
})
data.append(row)
return columns, data
chart = get_chart_data(data)
report_summary = get_report_summary(data)
return columns, data, None, chart, report_summary
def get_columns():
columns = [
_("Test") + ":Data:120",
_("Patient") + ":Link/Patient:180",
_("Healthcare Practitioner") + ":Link/Healthcare Practitioner:120",
_("Invoiced") + ":Check:100",
_("Status") + ":Data:120",
_("Result Date") + ":Date:120",
_("Department") + ":Data:120",
return [
{
'fieldname': 'test',
'label': _('Lab Test'),
'fieldtype': 'Link',
'options': 'Lab Test',
'width': '120'
},
{
'fieldname': 'template',
'label': _('Lab Test Template'),
'fieldtype': 'Link',
'options': 'Lab Test Template',
'width': '120'
},
{
'fieldname': 'company',
'label': _('Company'),
'fieldtype': 'Link',
'options': 'Company',
'width': '120'
},
{
'fieldname': 'patient',
'label': _('Patient'),
'fieldtype': 'Link',
'options': 'Patient',
'width': '120'
},
{
'fieldname': 'patient_name',
'label': _('Patient Name'),
'fieldtype': 'Data',
'width': '120'
},
{
'fieldname': 'employee',
'label': _('Lab Technician'),
'fieldtype': 'Link',
'options': 'Employee',
'width': '120'
},
{
'fieldname': 'status',
'label': _('Status'),
'fieldtype': 'Data',
'width': '100'
},
{
'fieldname': 'invoiced',
'label': _('Invoiced'),
'fieldtype': 'Check',
'width': '100'
},
{
'fieldname': 'result_date',
'label': _('Result Date'),
'fieldtype': 'Date',
'width': '100'
},
{
'fieldname': 'practitioner',
'label': _('Requesting Practitioner'),
'fieldtype': 'Link',
'options': 'Healthcare Practitioner',
'width': '120'
},
{
'fieldname': 'department',
'label': _('Medical Department'),
'fieldtype': 'Link',
'options': 'Medical Department',
'width': '100'
}
]
return columns
def get_lab_tests(filters):
conditions = get_conditions(filters)
data = frappe.get_all(
doctype='Lab Test',
fields=['name', 'template', 'company', 'patient', 'patient_name', 'practitioner', 'employee', 'status', 'invoiced', 'result_date', 'department'],
filters=conditions,
order_by='submitted_date desc'
)
return data
def get_conditions(filters):
conditions = ""
conditions = {
'docstatus': ('=', 1)
}
if filters.get("patient"):
conditions += "and patient = %(patient)s"
if filters.get("from_date"):
conditions += "and result_date >= %(from_date)s"
if filters.get("to_date"):
conditions += " and result_date <= %(to_date)s"
if filters.get("department"):
conditions += " and department = %(department)s"
if filters.get('from_date') and filters.get('to_date'):
conditions['result_date'] = ('between', (filters.get('from_date'), filters.get('to_date')))
filters.pop('from_date')
filters.pop('to_date')
for key, value in filters.items():
if filters.get(key):
conditions[key] = value
return conditions
def get_lab_test(filters):
conditions = get_conditions(filters)
return frappe.db.sql("""select name, patient, lab_test_name, patient_name, status, result_date, practitioner, invoiced, department
from `tabLab Test`
where docstatus<2 %s order by submitted_date desc, name desc""" %
conditions, filters, as_dict=1)
def get_chart_data(data):
if not data:
return None
labels = ['Completed', 'Approved', 'Rejected']
status_wise_data = {
'Completed': 0,
'Approved': 0,
'Rejected': 0
}
datasets = []
for entry in data:
status_wise_data[entry.status] += 1
datasets.append({
'name': 'Lab Test Status',
'values': [status_wise_data.get('Completed'), status_wise_data.get('Approved'), status_wise_data.get('Rejected')]
})
chart = {
'data': {
'labels': labels,
'datasets': datasets
},
'type': 'donut',
'height': 300,
}
return chart
def get_report_summary(data):
if not data:
return None
total_lab_tests = len(data)
invoiced_lab_tests, unbilled_lab_tests = 0, 0
for entry in data:
if entry.invoiced:
invoiced_lab_tests += 1
else:
unbilled_lab_tests += 1
return [
{
'value': total_lab_tests,
'indicator': 'Blue',
'label': 'Total Lab Tests',
'datatype': 'Int',
},
{
'value': invoiced_lab_tests,
'indicator': 'Green',
'label': 'Invoiced Lab Tests',
'datatype': 'Int',
},
{
'value': unbilled_lab_tests,
'indicator': 'Red',
'label': 'Unbilled Lab Tests',
'datatype': 'Int',
}
]

View File

@ -417,8 +417,43 @@ class TestSalesOrder(unittest.TestCase):
# add new item
trans_item = json.dumps([{'item_code' : '_Test Item', 'rate' : 100, 'qty' : 2}])
self.assertRaises(frappe.ValidationError, update_child_qty_rate,'Sales Order', trans_item, so.name)
test_user.remove_roles("Accounts User")
frappe.set_user("Administrator")
def test_update_child_qty_rate_with_workflow(self):
from frappe.model.workflow import apply_workflow
workflow = make_sales_order_workflow()
so = make_sales_order(item_code= "_Test Item", qty=1, rate=150, do_not_submit=1)
apply_workflow(so, 'Approve')
frappe.set_user("Administrator")
user = 'test@example.com'
test_user = frappe.get_doc('User', user)
test_user.add_roles("Sales User", "Test Junior Approver")
frappe.set_user(user)
# user shouldn't be able to edit since grand_total will become > 200 if qty is doubled
trans_item = json.dumps([{'item_code' : '_Test Item', 'rate' : 150, 'qty' : 2, 'docname': so.items[0].name}])
self.assertRaises(frappe.ValidationError, update_child_qty_rate, 'Sales Order', trans_item, so.name)
frappe.set_user("Administrator")
user2 = 'test2@example.com'
test_user2 = frappe.get_doc('User', user2)
test_user2.add_roles("Sales User", "Test Approver")
frappe.set_user(user2)
# Test Approver is allowed to edit with grand_total > 200
update_child_qty_rate("Sales Order", trans_item, so.name)
so.reload()
self.assertEqual(so.items[0].qty, 2)
frappe.set_user("Administrator")
test_user.remove_roles("Sales User", "Test Junior Approver", "Test Approver")
test_user2.remove_roles("Sales User", "Test Junior Approver", "Test Approver")
workflow.is_active = 0
workflow.save()
def test_update_child_qty_rate_product_bundle(self):
# test Update Items with product bundle
if not frappe.db.exists("Item", "_Product Bundle Item"):
@ -973,3 +1008,37 @@ def get_reserved_qty(item_code="_Test Item", warehouse="_Test Warehouse - _TC"):
"reserved_qty"))
test_dependencies = ["Currency Exchange"]
def make_sales_order_workflow():
if frappe.db.exists('Workflow', 'SO Test Workflow'):
doc = frappe.get_doc("Workflow", "SO Test Workflow")
doc.set("is_active", 1)
doc.save()
return doc
frappe.get_doc(dict(doctype='Role', role_name='Test Junior Approver')).insert(ignore_if_duplicate=True)
frappe.get_doc(dict(doctype='Role', role_name='Test Approver')).insert(ignore_if_duplicate=True)
frappe.db.commit()
frappe.cache().hdel('roles', frappe.session.user)
workflow = frappe.get_doc({
"doctype": "Workflow",
"workflow_name": "SO Test Workflow",
"document_type": "Sales Order",
"workflow_state_field": "workflow_state",
"is_active": 1,
"send_email_alert": 0,
})
workflow.append('states', dict( state = 'Pending', allow_edit = 'All' ))
workflow.append('states', dict( state = 'Approved', allow_edit = 'Test Approver', doc_status = 1 ))
workflow.append('transitions', dict(
state = 'Pending', action = 'Approve', next_state = 'Approved', allowed = 'Test Junior Approver', allow_self_approval = 1,
condition = 'doc.grand_total < 200'
))
workflow.append('transitions', dict(
state = 'Pending', action = 'Approve', next_state = 'Approved', allowed = 'Test Approver', allow_self_approval = 1,
condition = 'doc.grand_total > 200'
))
workflow.insert(ignore_permissions=True)
return workflow

View File

@ -130,12 +130,18 @@ erpnext.stock.DeliveryNoteController = erpnext.selling.SellingController.extend(
if (this.frm.doc.docstatus===0) {
this.frm.add_custom_button(__('Sales Order'),
function() {
if (!me.frm.doc.customer) {
frappe.throw({
title: __("Mandatory"),
message: __("Please Select a Customer")
});
}
erpnext.utils.map_current_doc({
method: "erpnext.selling.doctype.sales_order.sales_order.make_delivery_note",
source_doctype: "Sales Order",
target: me.frm,
setters: {
customer: me.frm.doc.customer || undefined,
customer: me.frm.doc.customer,
},
get_query_filters: {
docstatus: 1,

View File

@ -116,12 +116,18 @@ erpnext.stock.PurchaseReceiptController = erpnext.buying.BuyingController.extend
if (this.frm.doc.docstatus == 0) {
this.frm.add_custom_button(__('Purchase Order'),
function () {
if (!me.frm.doc.supplier) {
frappe.throw({
title: __("Mandatory"),
message: __("Please Select a Supplier")
});
}
erpnext.utils.map_current_doc({
method: "erpnext.buying.doctype.purchase_order.purchase_order.make_purchase_receipt",
source_doctype: "Purchase Order",
target: me.frm,
setters: {
supplier: me.frm.doc.supplier || undefined,
supplier: me.frm.doc.supplier,
},
get_query_filters: {
docstatus: 1,

View File

@ -73,7 +73,8 @@
"fieldname": "reference_type",
"fieldtype": "Select",
"label": "Reference Type",
"options": "\nPurchase Receipt\nPurchase Invoice\nDelivery Note\nSales Invoice\nStock Entry"
"options": "\nPurchase Receipt\nPurchase Invoice\nDelivery Note\nSales Invoice\nStock Entry",
"reqd": 1
},
{
"fieldname": "reference_name",
@ -84,7 +85,8 @@
"label": "Reference Name",
"oldfieldname": "purchase_receipt_no",
"oldfieldtype": "Link",
"options": "reference_type"
"options": "reference_type",
"reqd": 1
},
{
"fieldname": "section_break_7",
@ -231,9 +233,10 @@
],
"icon": "fa fa-search",
"idx": 1,
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
"modified": "2020-04-26 17:50:25.068222",
"modified": "2020-09-12 16:11:31.910508",
"modified_by": "Administrator",
"module": "Stock",
"name": "Quality Inspection",