diff --git a/erpnext/__init__.py b/erpnext/__init__.py index c00d90efe4..0d5ac9d512 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -5,7 +5,7 @@ import frappe from erpnext.hooks import regional_overrides from frappe.utils import getdate -__version__ = '10.1.73' +__version__ = '10.1.74' def get_default_company(user=None): '''Get default company for user''' diff --git a/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.py b/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.py index 86023aa666..eb95e458dc 100644 --- a/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.py +++ b/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.py @@ -70,12 +70,14 @@ class PeriodClosingVoucher(AccountsController): net_pl_balance += flt(acc.balance_in_company_currency) if net_pl_balance: + cost_center = frappe.db.get_value("Company", self.company, "cost_center") gl_entries.append(self.get_gl_dict({ "account": self.closing_account_head, "debit_in_account_currency": abs(net_pl_balance) if net_pl_balance > 0 else 0, "debit": abs(net_pl_balance) if net_pl_balance > 0 else 0, "credit_in_account_currency": abs(net_pl_balance) if net_pl_balance < 0 else 0, - "credit": abs(net_pl_balance) if net_pl_balance < 0 else 0 + "credit": abs(net_pl_balance) if net_pl_balance < 0 else 0, + "cost_center": cost_center })) from erpnext.accounts.general_ledger import make_gl_entries diff --git a/erpnext/accounts/doctype/period_closing_voucher/test_period_closing_voucher.py b/erpnext/accounts/doctype/period_closing_voucher/test_period_closing_voucher.py index 9ef66edc34..eb02d97b78 100644 --- a/erpnext/accounts/doctype/period_closing_voucher/test_period_closing_voucher.py +++ b/erpnext/accounts/doctype/period_closing_voucher/test_period_closing_voucher.py @@ -72,6 +72,7 @@ class TestPeriodClosingVoucher(unittest.TestCase): "company": "_Test Company", "fiscal_year": get_fiscal_year(today(), company="_Test Company")[0], "posting_date": today(), + "cost_center": "_Test Cost Center - _TC", "remarks": "test" }) pcv.insert() diff --git a/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py b/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py index 995efee2c0..e4f37c44ff 100644 --- a/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py +++ b/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py @@ -21,8 +21,6 @@ class TestPricingRule(unittest.TestCase): from erpnext.stock.get_item_details import get_item_details from frappe import MandatoryError - - test_record = { "doctype": "Pricing Rule", "title": "_Test Pricing Rule", @@ -93,7 +91,7 @@ class TestPricingRule(unittest.TestCase): args.item_code = "_Test Item 2" details = get_item_details(args) - self.assertEqual(details.get("discount_percentage"), 15) + self.assertEquals(details.get("discount_percentage"), 15) def test_pricing_rule_for_margin(self): from erpnext.stock.get_item_details import get_item_details @@ -137,8 +135,8 @@ class TestPricingRule(unittest.TestCase): "name": None }) details = get_item_details(args) - self.assertEqual(details.get("margin_type"), "Percentage") - self.assertEqual(details.get("margin_rate_or_amount"), 10) + self.assertEquals(details.get("margin_type"), "Percentage") + self.assertEquals(details.get("margin_rate_or_amount"), 10) def test_pricing_rule_for_variants(self): from erpnext.stock.get_item_details import get_item_details @@ -253,6 +251,7 @@ class TestPricingRule(unittest.TestCase): self.assertEqual(so.items[0].rate, 100) def test_pricing_rule_with_margin_and_discount(self): + frappe.delete_doc_if_exists('Pricing Rule', '_Test Pricing Rule') make_pricing_rule(selling=1, margin_type="Percentage", margin_rate_or_amount=10, discount_percentage=10) si = create_sales_invoice(do_not_save=True) si.items[0].price_list_rate = 1000 @@ -260,12 +259,11 @@ class TestPricingRule(unittest.TestCase): si.insert(ignore_permissions=True) item = si.items[0] - self.assertEqual(item.margin_rate_or_amount, 10) - self.assertEqual(item.rate_with_margin, 1100) + self.assertEquals(item.margin_rate_or_amount, 10) + self.assertEquals(item.rate_with_margin, 1100) self.assertEqual(item.discount_percentage, 10) - self.assertEqual(item.discount_amount, 110) - self.assertEqual(item.rate, 990) - + self.assertEquals(item.discount_amount, 110) + self.assertEquals(item.rate, 990) def make_pricing_rule(**args): args = frappe._dict(args) @@ -295,4 +293,4 @@ def make_pricing_rule(**args): applicable_for = doc.applicable_for.replace(' ', '_').lower() if args.get(applicable_for): - doc.db_set(applicable_for, args.get(applicable_for)) \ No newline at end of file + doc.db_set(applicable_for, args.get(applicable_for)) diff --git a/erpnext/accounts/party.py b/erpnext/accounts/party.py index 8c7f3d881f..e5cdad1f94 100644 --- a/erpnext/accounts/party.py +++ b/erpnext/accounts/party.py @@ -72,7 +72,7 @@ def _get_party_details(party=None, account=None, party_type="Customer", company= return out -def set_address_details(out, party, party_type, doctype=None, company=None, party_address=None, shipping_address=None): +def set_address_details(out, party, party_type, doctype=None, company=None, party_address=None, shipping_address=None): billing_address_field = "customer_address" if party_type == "Lead" \ else party_type.lower() + "_address" out[billing_address_field] = party_address or get_default_address(party_type, party.name) @@ -459,38 +459,65 @@ def get_timeline_data(doctype, name): def get_dashboard_info(party_type, party): current_fiscal_year = get_fiscal_year(nowdate(), as_dict=True) - company = frappe.db.get_default("company") or frappe.get_all("Company")[0].name - party_account_currency = get_party_account_currency(party_type, party, company) - company_default_currency = get_default_currency() \ - or frappe.get_cached_value('Company', company, 'default_currency') - - if party_account_currency==company_default_currency: - total_field = "base_grand_total" - else: - total_field = "grand_total" doctype = "Sales Invoice" if party_type=="Customer" else "Purchase Invoice" - billing_this_year = frappe.db.sql(""" - select sum({0}) - from `tab{1}` - where {2}=%s and docstatus=1 and posting_date between %s and %s - """.format(total_field, doctype, party_type.lower()), - (party, current_fiscal_year.year_start_date, current_fiscal_year.year_end_date)) + companies = frappe.get_all(doctype, filters={ + 'docstatus': 1, + party_type.lower(): party + }, distinct=1, fields=['company']) - total_unpaid = frappe.db.sql(""" - select sum(debit_in_account_currency) - sum(credit_in_account_currency) + company_wise_info = [] + + company_wise_grand_total = frappe.get_all(doctype, + filters={ + 'docstatus': 1, + party_type.lower(): party, + 'posting_date': ('between', [current_fiscal_year.year_start_date, current_fiscal_year.year_end_date]) + }, + group_by="company", + fields=["company", "sum(grand_total) as grand_total", "sum(base_grand_total) as base_grand_total"] + ) + + company_wise_billing_this_year = frappe._dict() + + for d in company_wise_grand_total: + company_wise_billing_this_year.setdefault( + d.company,{ + "grand_total": d.grand_total, + "base_grand_total": d.base_grand_total + }) + + + company_wise_total_unpaid = frappe._dict(frappe.db.sql(""" + select company, sum(debit_in_account_currency) - sum(credit_in_account_currency) from `tabGL Entry` - where party_type = %s and party=%s""", (party_type, party)) + where party_type = %s and party=%s + group by company""", (party_type, party))) - info = {} - info["billing_this_year"] = flt(billing_this_year[0][0]) if billing_this_year else 0 - info["currency"] = party_account_currency - info["total_unpaid"] = flt(total_unpaid[0][0]) if total_unpaid else 0 - if party_type == "Supplier": - info["total_unpaid"] = -1 * info["total_unpaid"] + for d in companies: + company_default_currency = frappe.db.get_value("Company", d.company, 'default_currency') + party_account_currency = get_party_account_currency(party_type, party, d.company) - return info + if party_account_currency==company_default_currency: + billing_this_year = flt(company_wise_billing_this_year.get(d.company,{}).get("base_grand_total")) + else: + billing_this_year = flt(company_wise_billing_this_year.get(d.company,{}).get("grand_total")) + + total_unpaid = flt(company_wise_total_unpaid.get(d.company)) + + info = {} + info["billing_this_year"] = flt(billing_this_year) if billing_this_year else 0 + info["currency"] = party_account_currency + info["total_unpaid"] = flt(total_unpaid) if total_unpaid else 0 + info["company"] = d.company + + if party_type == "Supplier": + info["total_unpaid"] = -1 * info["total_unpaid"] + + company_wise_info.append(info) + + return company_wise_info def get_party_shipping_address(doctype, name): """ diff --git a/erpnext/buying/page/purchase_analytics/README.md b/erpnext/buying/page/purchase_analytics/README.md deleted file mode 100644 index 332e4c2c05..0000000000 --- a/erpnext/buying/page/purchase_analytics/README.md +++ /dev/null @@ -1 +0,0 @@ -Trends of purchases across Items, Item Groups, Suppliers. \ No newline at end of file diff --git a/erpnext/buying/page/purchase_analytics/__init__.py b/erpnext/buying/page/purchase_analytics/__init__.py deleted file mode 100644 index baffc48825..0000000000 --- a/erpnext/buying/page/purchase_analytics/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/buying/page/purchase_analytics/purchase_analytics.js b/erpnext/buying/page/purchase_analytics/purchase_analytics.js deleted file mode 100644 index 06764a3c60..0000000000 --- a/erpnext/buying/page/purchase_analytics/purchase_analytics.js +++ /dev/null @@ -1,231 +0,0 @@ -// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -// License: GNU General Public License v3. See license.txt - -frappe.pages['purchase-analytics'].on_page_load = function(wrapper) { - frappe.ui.make_app_page({ - parent: wrapper, - title: __('Purchase Analytics'), - single_column: true - }); - - new erpnext.PurchaseAnalytics(wrapper); - - frappe.breadcrumbs.add("Buying"); -} - -erpnext.PurchaseAnalytics = frappe.views.TreeGridReport.extend({ - init: function(wrapper) { - this._super({ - title: __("Purchase Analytics"), - parent: $(wrapper).find('.layout-main'), - page: wrapper.page, - doctypes: ["Item", "Item Group", "Supplier", "Supplier Group", "Company", "Fiscal Year", - "Purchase Invoice", "Purchase Invoice Item", - "Purchase Order", "Purchase Order Item[Purchase Analytics]", - "Purchase Receipt", "Purchase Receipt Item[Purchase Analytics]"], - tree_grid: { show: true } - }); - - this.tree_grids = { - "Supplier Group": { - label: __("Supplier Group / Supplier"), - show: true, - item_key: "supplier", - parent_field: "parent_supplier_group", - formatter: function(item) { - return item.supplier_name ? item.supplier_name + " (" + item.name + ")" : item.name; - } - }, - "Supplier": { - label: __("Supplier"), - show: false, - item_key: "supplier", - formatter: function(item) { - return item.supplier_name ? item.supplier_name + " (" + item.name + ")" : item.name; - } - }, - "Item Group": { - label: "Item", - show: true, - parent_field: "parent_item_group", - item_key: "item_code", - formatter: function(item) { - return item.name; - } - }, - "Item": { - label: "Item", - show: false, - item_key: "item_code", - formatter: function(item) { - return item.name; - } - }, - } - }, - setup_columns: function() { - this.tree_grid = this.tree_grids[this.tree_type]; - - var std_columns = [ - {id: "name", name: this.tree_grid.label, field: "name", width: 300}, - {id: "total", name: "Total", field: "total", plot: false, - formatter: this.currency_formatter} - ]; - - this.make_date_range_columns(); - this.columns = std_columns.concat(this.columns); - }, - filters: [ - {fieldtype:"Select", label: __("Tree Type"), fieldname: "tree_type", - options:["Supplier Group", "Supplier", "Item Group", "Item"], - filter: function(val, item, opts, me) { - return me.apply_zero_filter(val, item, opts, me); - }}, - {fieldtype:"Select", label: __("Based On"), fieldname: "based_on", - options:["Purchase Invoice", "Purchase Order", "Purchase Receipt"]}, - {fieldtype:"Select", label: __("Value or Qty"), fieldname: "value_or_qty", - options:["Value", "Quantity"]}, - {fieldtype:"Select", label: __("Company"), link:"Company", fieldname: "company", - default_value: __("Select Company...")}, - {fieldtype:"Date", label: __("From Date"), fieldname: "from_date"}, - {fieldtype:"Date", label: __("To Date"), fieldname: "to_date"}, - {fieldtype:"Select", label: __("Range"), fieldname: "range", - options:[{label: __("Daily"), value: "Daily"}, {label: __("Weekly"), value: "Weekly"}, - {label: __("Monthly"), value: "Monthly"}, {label: __("Quarterly"), value: "Quarterly"}, - {label: __("Yearly"), value: "Yearly"}]} - ], - setup_filters: function() { - var me = this; - this._super(); - - this.trigger_refresh_on_change(["value_or_qty", "tree_type", "based_on", "company"]); - - this.show_zero_check(); - }, - init_filter_values: function() { - this._super(); - this.filter_inputs.range.val('Monthly'); - }, - prepare_data: function() { - var me = this; - if (!this.tl) { - // add 'Not Set' Supplier & Item - // (Supplier / Item are not mandatory!!) - frappe.report_dump.data["Supplier"].push({ - name: __("Not Set"), - parent_supplier_group: __("All Supplier Groups"), - id: "Not Set", - }); - - frappe.report_dump.data["Item"].push({ - name: __("Not Set"), - parent_item_group: "All Item Groups", - id: "Not Set", - }); - } - - if (!this.tl || !this.tl[this.based_on]) { - this.make_transaction_list(this.based_on, this.based_on + " Item"); - } - - - if(!this.data || me.item_type != me.tree_type) { - var items; - if(me.tree_type=='Supplier') { - items = frappe.report_dump.data["Supplier"]; - } else if(me.tree_type=='Supplier Group') { - items = this.prepare_tree("Supplier", "Supplier Group"); - } else if(me.tree_type=="Item Group") { - items = this.prepare_tree("Item", "Item Group"); - } else if(me.tree_type=="Item") { - items = frappe.report_dump.data["Item"]; - } - - me.item_type = me.tree_type - me.parent_map = {}; - me.item_by_name = {}; - me.data = []; - - $.each(items, function(i, v) { - var d = copy_dict(v); - - me.data.push(d); - me.item_by_name[d.name] = d; - if(d[me.tree_grid.parent_field]) { - me.parent_map[d.name] = d[me.tree_grid.parent_field]; - } - me.reset_item_values(d); - }); - - this.set_indent(); - - } else { - // otherwise, only reset values - $.each(this.data, function(i, d) { - me.reset_item_values(d); - }); - } - - this.prepare_balances(); - if(me.tree_grid.show) { - this.set_totals(false); - this.update_groups(); - } else { - this.set_totals(true); - } - }, - prepare_balances: function() { - var me = this; - var from_date = frappe.datetime.str_to_obj(this.from_date); - var to_date = frappe.datetime.str_to_obj(this.to_date); - var is_val = this.value_or_qty == 'Value'; - - $.each(this.tl[this.based_on], function(i, tl) { - if (me.is_default('company') ? true : tl.company === me.company) { - var posting_date = frappe.datetime.str_to_obj(tl.posting_date); - if (posting_date >= from_date && posting_date <= to_date) { - var item = me.item_by_name[tl[me.tree_grid.item_key]] || - me.item_by_name['Not Set']; - item[me.column_map[tl.posting_date].field] += (is_val ? tl.base_net_amount : tl.qty); - } - } - }); - }, - update_groups: function() { - var me = this; - - $.each(this.data, function(i, item) { - var parent = me.parent_map[item.name]; - while(parent) { - var parent_group = me.item_by_name[parent]; - - $.each(me.columns, function(c, col) { - if (col.formatter == me.currency_formatter) { - parent_group[col.field] = - flt(parent_group[col.field]) - + flt(item[col.field]); - } - }); - parent = me.parent_map[parent]; - } - }); - }, - set_totals: function(sort) { - var me = this; - var checked = false; - $.each(this.data, function(i, d) { - d.total = 0.0; - $.each(me.columns, function(i, col) { - if(col.formatter==me.currency_formatter && !col.hidden && col.field!="total") - d.total += d[col.field]; - if(d.checked) checked = true; - }) - }); - - if(sort)this.data = this.data.sort(function(a, b) { return b.total - a.total; }); - - if(!this.checked) { - this.data[0].checked = true; - } - } -}); diff --git a/erpnext/buying/page/purchase_analytics/purchase_analytics.json b/erpnext/buying/page/purchase_analytics/purchase_analytics.json deleted file mode 100644 index ad13c7d415..0000000000 --- a/erpnext/buying/page/purchase_analytics/purchase_analytics.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "creation": "2012-09-21 20:15:16.000000", - "docstatus": 0, - "doctype": "Page", - "icon": "fa fa-bar-chart", - "idx": 1, - "modified": "2013-07-11 14:43:52.000000", - "modified_by": "Administrator", - "module": "Buying", - "name": "purchase-analytics", - "owner": "Administrator", - "page_name": "purchase-analytics", - "roles": [ - { - "role": "Analytics" - }, - { - "role": "Purchase Manager" - } - ], - "standard": "Yes", - "title": "Purchase Analytics" -} \ No newline at end of file diff --git a/erpnext/buying/report/purchase_analytics/purchase_analytics.js b/erpnext/buying/report/purchase_analytics/purchase_analytics.js index 297ec51cb1..b55046e065 100644 --- a/erpnext/buying/report/purchase_analytics/purchase_analytics.js +++ b/erpnext/buying/report/purchase_analytics/purchase_analytics.js @@ -68,11 +68,8 @@ frappe.query_reports["Purchase Analytics"] = { } ], - "formatter": function(value, row, column, data) { - if(!value){ - value = 0 - } - return value; + after_datatable_render: function(datatable_obj) { + $(datatable_obj.wrapper).find(".dt-row-0").find('input[type=checkbox]').click(); }, get_datatable_options(options) { return Object.assign(options, { @@ -110,19 +107,19 @@ frappe.query_reports["Purchase Analytics"] = { labels: raw_data.labels, datasets: new_datasets } - + setTimeout(() => { frappe.query_report.chart.update(new_data) - },200) - - + },500) + + setTimeout(() => { frappe.query_report.chart.draw(true); - }, 800) + }, 1000) frappe.query_report.raw_chart_data = new_data; }, } - }) - }, + }); + } } diff --git a/erpnext/controllers/taxes_and_totals.py b/erpnext/controllers/taxes_and_totals.py index a4410256f6..5bbef1831a 100644 --- a/erpnext/controllers/taxes_and_totals.py +++ b/erpnext/controllers/taxes_and_totals.py @@ -65,6 +65,7 @@ class calculate_taxes_and_totals(object): if item.doctype in ['Quotation Item', 'Sales Order Item', 'Delivery Note Item', 'Sales Invoice Item']: item.rate_with_margin, item.base_rate_with_margin = self.calculate_margin(item) + if flt(item.rate_with_margin) > 0: item.rate = flt(item.rate_with_margin * (1.0 - (item.discount_percentage / 100.0)), item.precision("rate")) item.discount_amount = item.rate_with_margin - item.rate @@ -647,4 +648,4 @@ def get_rounded_tax_amount(itemised_tax, precision): # Rounding based on tax_amount precision for taxes in itemised_tax.values(): for tax_account in taxes: - taxes[tax_account]["tax_amount"] = flt(taxes[tax_account]["tax_amount"], precision) \ No newline at end of file + taxes[tax_account]["tax_amount"] = flt(taxes[tax_account]["tax_amount"], precision) diff --git a/erpnext/education/doctype/assessment_result/assessment_result.js b/erpnext/education/doctype/assessment_result/assessment_result.js index 5f13e3e628..84865ca8ec 100644 --- a/erpnext/education/doctype/assessment_result/assessment_result.js +++ b/erpnext/education/doctype/assessment_result/assessment_result.js @@ -38,6 +38,12 @@ frappe.ui.form.on("Assessment Result", { frappe.ui.form.on("Assessment Result Detail", { score: function(frm, cdt, cdn) { var d = locals[cdt][cdn]; + + if(!d.maximum_score || !frm.doc.grading_scale) { + d.score = ""; + frappe.throw(__("Please fill in all the details to generate Assessment Result.")); + } + if (d.score > d.maximum_score) { frappe.throw(__("Score cannot be greater than Maximum Score")); } diff --git a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.js b/erpnext/healthcare/doctype/patient_appointment/patient_appointment.js index 71c8212412..2f328de1bc 100644 --- a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.js +++ b/erpnext/healthcare/doctype/patient_appointment/patient_appointment.js @@ -39,7 +39,9 @@ frappe.ui.form.on('Patient Appointment', { frm.add_custom_button(__('Cancel'), function() { btn_update_status(frm, "Cancelled"); }); - + frm.add_custom_button(__('Reschedule'), function() { + check_and_set_availability(frm); + }); if(frm.doc.procedure_template){ frm.add_custom_button(__("Procedure"),function(){ btn_create_procedure(frm); @@ -59,7 +61,9 @@ frappe.ui.form.on('Patient Appointment', { frm.add_custom_button(__('Cancel'), function() { btn_update_status(frm, "Cancelled"); }); - + frm.add_custom_button(__('Reschedule'), function() { + check_and_set_availability(frm); + }); if(frm.doc.procedure_template){ frm.add_custom_button(__("Procedure"),function(){ btn_create_procedure(frm); @@ -100,117 +104,7 @@ frappe.ui.form.on('Patient Appointment', { }); }, check_availability: function(frm) { - var { practitioner, appointment_date } = frm.doc; - if(!(practitioner && appointment_date)) { - frappe.throw(__("Please select Healthcare Practitioner and Date")); - } - - // show booking modal - frm.call({ - method: 'get_availability_data', - args: { - practitioner: practitioner, - date: appointment_date - }, - callback: (r) => { - var data = r.message; - if(data.slot_details.length > 0){ - show_availability(data); - }else{ - show_empty_state(); - } - } - }); - - function show_empty_state() { - frappe.msgprint({ - title: __('Not Available'), - message: __("Healthcare Practitioner {0} not available on {1}", [practitioner.bold(), appointment_date.bold()]), - indicator: 'red' - }); - } - - function show_availability(data) { - var d = new frappe.ui.Dialog({ - title: __("Available slots"), - fields: [{ fieldtype: 'HTML', fieldname: 'available_slots'}], - primary_action_label: __("Book"), - primary_action: function() { - // book slot - var btn_selected = $wrapper.find('button.btn-selected-slot'); - frm.set_value('appointment_time', btn_selected.attr('data-name')); - frm.set_value('service_unit', btn_selected.attr('data-service-unit') || ''); - frm.set_value('duration', btn_selected.attr('data-duration')); - d.hide(); - frm.enable_save(); - frm.save(); - frm.enable_save(); - } - }); - var $wrapper = d.fields_dict.available_slots.$wrapper; - - // disable dialog action initially - d.get_primary_btn().attr('disabled', true); - - var slot_details = data.slot_details; - var slot_html = ""; - var duration = frm.doc.duration | 0; - $.each(slot_details, function(i, slot_detail){ - slot_html = slot_html + ``; - slot_html = slot_html + `
` + slot_detail['avail_slot'].map(slot => { - let disabled = ''; - let start_str = slot.from_time; - let slot_start_time = moment(slot.from_time, 'HH:mm:ss'); - let slot_to_time = moment(slot.to_time, 'HH:mm:ss'); - let interval = (slot_to_time - slot_start_time)/60000 | 0; - // iterate in all booked appointments, update the start time and duration - slot_detail['appointments'].forEach(function(booked) { - let booked_moment = moment(booked.appointment_time, 'HH:mm:ss'); - let end_time = booked_moment.clone().add(booked.duration, 'minutes'); - // Deal with 0 duration appointments - if(booked_moment.isSame(slot_start_time) || booked_moment.isBetween(slot_start_time, slot_to_time)){ - if(booked.duration == 0){ - disabled = 'disabled="disabled"'; - return false; - } - } - // Check for overlaps considering appointment duration - if(slot_start_time.isBefore(end_time) && slot_to_time.isAfter(booked_moment)){ - // There is an overlap - disabled = 'disabled="disabled"'; - return false; - } - }); - - return ``; - }).join(""); - slot_html = slot_html + `
`; - }); - - $wrapper - .css('margin-bottom', 0) - .addClass('text-center') - .html(slot_html); - - // blue button when clicked - $wrapper.on('click', 'button', function() { - var $btn = $(this); - $wrapper.find('button').removeClass('btn-primary'); - $wrapper.find('button').removeClass('btn-selected-slot'); - $btn.addClass('btn-primary'); - $btn.addClass('btn-selected-slot'); - // enable dialog action - d.get_primary_btn().attr('disabled', null); - }); - - d.show(); - } + check_and_set_availability(frm); }, onload:function(frm){ if(frm.is_new()) { @@ -223,6 +117,176 @@ frappe.ui.form.on('Patient Appointment', { } }); +var check_and_set_availability = function(frm) { + var selected_slot = null; + var service_unit = null; + var duration = null; + + show_availability(); + + function show_empty_state(practitioner, appointment_date) { + frappe.msgprint({ + title: __('Not Available'), + message: __("Healthcare Practitioner {0} not available on {1}", [practitioner.bold(), appointment_date.bold()]), + indicator: 'red' + }); + } + + function show_availability() { + let selected_practitioner = ''; + var d = new frappe.ui.Dialog({ + title: __("Available slots"), + fields: [ + { fieldtype: 'Link', options: 'Medical Department', reqd:1, fieldname: 'department', label: 'Medical Department'}, + { fieldtype: 'Column Break'}, + { fieldtype: 'Link', options: 'Healthcare Practitioner', reqd:1, fieldname: 'practitioner', label: 'Healthcare Practitioner'}, + { fieldtype: 'Column Break'}, + { fieldtype: 'Date', reqd:1, fieldname: 'appointment_date', label: 'Date'}, + { fieldtype: 'Section Break'}, + { fieldtype: 'HTML', fieldname: 'available_slots'} + ], + primary_action_label: __("Book"), + primary_action: function() { + frm.set_value('appointment_time', selected_slot); + frm.set_value('service_unit', service_unit || ''); + frm.set_value('duration', duration); + frm.set_value('practitioner', d.get_value('practitioner')); + frm.set_value('department', d.get_value('department')); + frm.set_value('appointment_date', d.get_value('appointment_date')); + d.hide(); + frm.enable_save(); + frm.save(); + frm.enable_save(); + d.get_primary_btn().attr('disabled', true); + } + }); + + d.set_values({ + 'department': frm.doc.department, + 'practitioner': frm.doc.practitioner, + 'appointment_date': frm.doc.appointment_date + }); + + d.fields_dict["department"].df.onchange = () => { + d.set_values({ + 'practitioner': '' + }); + var department = d.get_value('department'); + if(department){ + d.fields_dict.practitioner.get_query = function() { + return { + filters: { + "department": department + } + }; + }; + } + }; + + // disable dialog action initially + d.get_primary_btn().attr('disabled', true); + + // Field Change Handler + + var fd = d.fields_dict; + + d.fields_dict["appointment_date"].df.onchange = () => { + show_slots(d, fd); + }; + d.fields_dict["practitioner"].df.onchange = () => { + if(d.get_value('practitioner') && d.get_value('practitioner') != selected_practitioner){ + selected_practitioner = d.get_value('practitioner'); + show_slots(d, fd); + } + }; + d.show(); + } + + function show_slots(d, fd) { + if (d.get_value('appointment_date') && d.get_value('practitioner')){ + fd.available_slots.html(""); + frappe.call({ + method: 'erpnext.healthcare.doctype.patient_appointment.patient_appointment.get_availability_data', + args: { + practitioner: d.get_value('practitioner'), + date: d.get_value('appointment_date') + }, + callback: (r) => { + var data = r.message; + if(data.slot_details.length > 0) { + var $wrapper = d.fields_dict.available_slots.$wrapper; + + // make buttons for each slot + var slot_details = data.slot_details; + var slot_html = ""; + for (let i = 0; i < slot_details.length; i++) { + slot_html = slot_html + ``; + slot_html = slot_html + `
` + slot_details[i].avail_slot.map(slot => { + let disabled = ''; + let start_str = slot.from_time; + let slot_start_time = moment(slot.from_time, 'HH:mm:ss'); + let slot_to_time = moment(slot.to_time, 'HH:mm:ss'); + let interval = (slot_to_time - slot_start_time)/60000 | 0; + // iterate in all booked appointments, update the start time and duration + slot_details[i].appointments.forEach(function(booked) { + let booked_moment = moment(booked.appointment_time, 'HH:mm:ss'); + let end_time = booked_moment.clone().add(booked.duration, 'minutes'); + // Deal with 0 duration appointments + if(booked_moment.isSame(slot_start_time) || booked_moment.isBetween(slot_start_time, slot_to_time)){ + if(booked.duration == 0){ + disabled = 'disabled="disabled"'; + return false; + } + } + // Check for overlaps considering appointment duration + if(slot_start_time.isBefore(end_time) && slot_to_time.isAfter(booked_moment)){ + // There is an overlap + disabled = 'disabled="disabled"'; + return false; + } + }); + return ``; + }).join(""); + slot_html = slot_html + `
`; + } + + $wrapper + .css('margin-bottom', 0) + .addClass('text-center') + .html(slot_html); + + // blue button when clicked + $wrapper.on('click', 'button', function() { + var $btn = $(this); + $wrapper.find('button').removeClass('btn-primary'); + $btn.addClass('btn-primary'); + selected_slot = $btn.attr('data-name'); + service_unit = $btn.attr('data-service-unit'); + duration = $btn.attr('data-duration'); + // enable dialog action + d.get_primary_btn().attr('disabled', null); + }); + + }else { + // fd.available_slots.html("Please select a valid date.".bold()) + show_empty_state(d.get_value('practitioner'), d.get_value('appointment_date')); + } + }, + freeze: true, + freeze_message: __("Fetching records......") + }); + }else{ + fd.available_slots.html("Appointment date and Healthcare Practitioner are Mandatory".bold()); + } + } +}; + var get_procedure_prescribed = function(frm){ if(frm.doc.patient){ frappe.call({ diff --git a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.json b/erpnext/healthcare/doctype/patient_appointment/patient_appointment.json index cef49d730b..ee9f013084 100644 --- a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.json +++ b/erpnext/healthcare/doctype/patient_appointment/patient_appointment.json @@ -1,1058 +1,1184 @@ { - "allow_copy": 1, - "allow_guest_to_view": 0, - "allow_import": 1, - "allow_rename": 0, - "autoname": "HLC-APP-.YYYY.-.#####", - "beta": 1, - "creation": "2017-05-04 11:52:40.941507", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "Document", - "editable_grid": 0, - "engine": "InnoDB", + "allow_copy": 1, + "allow_events_in_timeline": 0, + "allow_guest_to_view": 0, + "allow_import": 1, + "allow_rename": 0, + "autoname": "OP-.######", + "beta": 1, + "creation": "2017-05-04 11:52:40.941507", + "custom": 0, + "docstatus": 0, + "doctype": "DocType", + "document_type": "Document", + "editable_grid": 0, + "engine": "InnoDB", "fields": [ { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_from": "patient.inpatient_record", - "fieldname": "inpatient_record", - "fieldtype": "Link", - "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": "Inpatient Record", - "length": 0, - "no_copy": 0, - "options": "Inpatient Record", - "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, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fetch_from": "patient.inpatient_record", + "fieldname": "inpatient_record", + "fieldtype": "Link", + "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": "Inpatient Record", + "length": 0, + "no_copy": 0, + "options": "Inpatient Record", + "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, - "fetch_from": "inpatient_record.patient", - "fieldname": "patient", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 1, - "label": "Patient", - "length": 0, - "no_copy": 0, - "options": "Patient", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 1, - "set_only_once": 1, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fetch_from": "inpatient_record.patient", + "fieldname": "patient", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 1, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Patient", + "length": 0, + "no_copy": 0, + "options": "Patient", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 1, + "set_only_once": 1, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "department", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 1, - "label": "Department", - "length": 0, - "no_copy": 0, - "options": "Medical Department", - "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": 1, - "set_only_once": 1, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "appointment_type", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 1, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Appointment Type", + "length": 0, + "no_copy": 0, + "options": "Appointment Type", + "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": 1, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "practitioner", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 1, - "label": "Healthcare Practitioner", - "length": 0, - "no_copy": 0, - "options": "Healthcare Practitioner", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 1, - "set_only_once": 1, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "description": "In Minutes", + "fieldname": "duration", + "fieldtype": "Int", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 1, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Duration", + "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, - "fieldname": "get_procedure_from_encounter", - "fieldtype": "Button", - "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": "Get prescribed procedures", - "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, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "column_break_1", + "fieldtype": "Column Break", + "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": "", + "length": 0, + "no_copy": 0, + "options": "", + "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, - "fieldname": "procedure_prescription", - "fieldtype": "Link", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Procedure Prescription", - "length": 0, - "no_copy": 1, - "options": "Procedure Prescription", - "permlevel": 0, - "precision": "", - "print_hide": 1, - "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, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "default": "Scheduled", + "depends_on": "eval:!doc.__islocal", + "fieldname": "status", + "fieldtype": "Select", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 1, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Status", + "length": 0, + "no_copy": 0, + "options": "\nScheduled\nOpen\nClosed\nPending\nCancelled", + "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": 1, + "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, - "fieldname": "procedure_template", - "fieldtype": "Link", - "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": "Procedure", - "length": 0, - "no_copy": 0, - "options": "Clinical Procedure Template", - "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": 1, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "procedure_template", + "fieldtype": "Link", + "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": "Procedure", + "length": 0, + "no_copy": 0, + "options": "Clinical Procedure Template", + "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": 1, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "appointment_date", - "fieldtype": "Date", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 1, - "label": "Date", - "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": 1, - "search_index": 1, - "set_only_once": 1, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "get_procedure_from_encounter", + "fieldtype": "Button", + "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": "Get prescribed procedures", + "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, - "fieldname": "appointment_time", - "fieldtype": "Time", - "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": "Time", - "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, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "procedure_prescription", + "fieldtype": "Link", + "hidden": 1, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Procedure Prescription", + "length": 0, + "no_copy": 1, + "options": "Procedure Prescription", + "permlevel": 0, + "precision": "", + "print_hide": 1, + "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, - "description": "In Minutes", - "fieldname": "duration", - "fieldtype": "Int", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 1, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Duration", - "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, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "service_unit", + "fieldtype": "Link", + "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": "Service Unit", + "length": 0, + "no_copy": 0, + "options": "Healthcare Service Unit", + "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": 1, + "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": "eval:doc.__islocal", - "fieldname": "check_availability", - "fieldtype": "Button", - "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": "Check availability", - "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, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "eval:doc.__islocal", + "fieldname": "check_availability", + "fieldtype": "Button", + "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": "Check availability", + "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, - "fieldname": "column_break_1", - "fieldtype": "Column Break", - "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": "", - "length": 0, - "no_copy": 0, - "options": "", - "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, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "section_break_12", + "fieldtype": "Section Break", + "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, + "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, - "fieldname": "service_unit", - "fieldtype": "Link", - "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": "Service Unit", - "length": 0, - "no_copy": 0, - "options": "Healthcare Service Unit", - "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": 1, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "practitioner", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 1, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 1, + "label": "Healthcare Practitioner", + "length": 0, + "no_copy": 0, + "options": "Healthcare Practitioner", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 1, + "set_only_once": 1, + "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": "", - "fetch_from": "patient.patient_name", - "fieldname": "patient_name", - "fieldtype": "Data", - "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": "Patient Name", - "length": 0, - "no_copy": 0, - "options": "", - "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, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "department", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 1, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Department", + "length": 0, + "no_copy": 0, + "options": "Medical Department", + "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": 1, + "set_only_once": 1, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_from": "patient.sex", - "fieldname": "patient_sex", - "fieldtype": "Data", - "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": "Gender", - "length": 0, - "no_copy": 1, - "options": "", - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 1, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "column_break_17", + "fieldtype": "Column Break", + "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, + "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, - "fieldname": "patient_age", - "fieldtype": "Data", - "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": "Patient Age", - "length": 0, - "no_copy": 0, - "options": "", - "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, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "appointment_date", + "fieldtype": "Date", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Date", + "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": 1, + "search_index": 1, + "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": "Scheduled", - "fieldname": "status", - "fieldtype": "Select", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 1, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Status", - "length": 0, - "no_copy": 0, - "options": "\nScheduled\nOpen\nClosed\nPending\nCancelled", - "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": 1, - "set_only_once": 0, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "appointment_time", + "fieldtype": "Time", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Time", + "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, - "fieldname": "appointment_type", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Type", - "length": 0, - "no_copy": 0, - "options": "Appointment Type", - "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, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "section_break_16", + "fieldtype": "Section Break", + "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, + "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, - "depends_on": "", - "fieldname": "section_break_1", - "fieldtype": "Section Break", - "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, - "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": 1, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "", + "fetch_from": "patient.patient_name", + "fieldname": "patient_name", + "fieldtype": "Data", + "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": "Patient Name", + "length": 0, + "no_copy": 0, + "options": "", + "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, - "fieldname": "appointment_datetime", - "fieldtype": "Datetime", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Date TIme", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 1, - "reqd": 0, - "search_index": 1, - "set_only_once": 0, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fetch_from": "patient.sex", + "fieldname": "patient_sex", + "fieldtype": "Data", + "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": "Gender", + "length": 0, + "no_copy": 1, + "options": "", + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 1, + "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, - "fieldname": "mode_of_payment", - "fieldtype": "Link", - "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": "Mode of Payment", - "length": 0, - "no_copy": 0, - "options": "Mode of Payment", - "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, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "column_break_21", + "fieldtype": "Column Break", + "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, + "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, - "fieldname": "paid_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": "Paid Amount", - "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, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "patient_age", + "fieldtype": "Data", + "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": "Patient Age", + "length": 0, + "no_copy": 0, + "options": "", + "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, - "fieldname": "column_break_2", - "fieldtype": "Column Break", - "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, - "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, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "", + "fieldname": "section_break_1", + "fieldtype": "Section Break", + "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, + "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": 1, + "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", - "fieldname": "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": "Invoiced", - "length": 0, - "no_copy": 0, - "options": "", - "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": 1, - "set_only_once": 0, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "appointment_datetime", + "fieldtype": "Datetime", + "hidden": 1, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Date TIme", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 1, + "reqd": 0, + "search_index": 1, + "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, - "fieldname": "company", - "fieldtype": "Link", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Company", - "length": 0, - "no_copy": 1, - "options": "Company", - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 1, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "mode_of_payment", + "fieldtype": "Link", + "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": "Mode of Payment", + "length": 0, + "no_copy": 0, + "options": "Mode of Payment", + "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": 1, - "columns": 0, - "fieldname": "section_break_3", - "fieldtype": "Section Break", - "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": "More Info", - "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, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "paid_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": "Paid Amount", + "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, - "fieldname": "notes", - "fieldtype": "Small Text", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 1, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Notes", - "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, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "column_break_2", + "fieldtype": "Column Break", + "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, + "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, - "fieldname": "referring_practitioner", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Referring Practitioner", - "length": 0, - "no_copy": 0, - "options": "Healthcare Practitioner", - "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": 1, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "default": "0", + "fieldname": "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": "Invoiced", + "length": 0, + "no_copy": 0, + "options": "", + "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": 1, + "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", - "fieldname": "reminded", - "fieldtype": "Check", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Reminded", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 1, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "company", + "fieldtype": "Link", + "hidden": 1, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Company", + "length": 0, + "no_copy": 1, + "options": "Company", + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 1, + "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": 1, + "columns": 0, + "fieldname": "section_break_3", + "fieldtype": "Section Break", + "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": "More Info", + "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, + "fieldname": "notes", + "fieldtype": "Small Text", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 1, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Notes", + "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, + "fieldname": "referring_practitioner", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 1, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Referring Practitioner", + "length": 0, + "no_copy": 0, + "options": "Healthcare Practitioner", + "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": 1, + "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", + "fieldname": "reminded", + "fieldtype": "Check", + "hidden": 1, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Reminded", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 1, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 0, - "max_attachments": 0, - "modified": "2018-09-13 10:15:45.704550", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Patient Appointment", - "name_case": "", - "owner": "Administrator", + ], + "has_web_view": 0, + "hide_heading": 0, + "hide_toolbar": 0, + "idx": 0, + "image_view": 0, + "in_create": 0, + "is_submittable": 0, + "issingle": 0, + "istable": 0, + "max_attachments": 0, + "modified": "2018-11-14 13:24:01.529536", + "modified_by": "Administrator", + "module": "Healthcare", + "name": "Patient Appointment", + "name_case": "", + "owner": "Administrator", "permissions": [ { - "amend": 0, - "cancel": 0, - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Healthcare Administrator", - "set_user_permissions": 0, - "share": 1, - "submit": 0, + "amend": 0, + "cancel": 0, + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "if_owner": 0, + "import": 0, + "permlevel": 0, + "print": 1, + "read": 1, + "report": 1, + "role": "Healthcare Administrator", + "set_user_permissions": 0, + "share": 1, + "submit": 0, "write": 1 - }, + }, { - "amend": 0, - "cancel": 0, - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Physician", - "set_user_permissions": 0, - "share": 1, - "submit": 0, + "amend": 0, + "cancel": 0, + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "if_owner": 0, + "import": 0, + "permlevel": 0, + "print": 1, + "read": 1, + "report": 1, + "role": "Physician", + "set_user_permissions": 0, + "share": 1, + "submit": 0, "write": 1 - }, + }, { - "amend": 0, - "cancel": 0, - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Nursing User", - "set_user_permissions": 0, - "share": 1, - "submit": 0, + "amend": 0, + "cancel": 0, + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "if_owner": 0, + "import": 0, + "permlevel": 0, + "print": 1, + "read": 1, + "report": 1, + "role": "Nursing User", + "set_user_permissions": 0, + "share": 1, + "submit": 0, "write": 1 } - ], - "quick_entry": 0, - "read_only": 0, - "read_only_onload": 0, - "restrict_to_domain": "Healthcare", - "search_fields": "patient, practitioner, department, appointment_date, appointment_time", - "show_name_in_global_search": 1, - "sort_field": "modified", - "sort_order": "DESC", - "title_field": "patient", - "track_changes": 1, - "track_seen": 1, + ], + "quick_entry": 0, + "read_only": 0, + "read_only_onload": 0, + "restrict_to_domain": "Healthcare", + "search_fields": "patient, practitioner, department, appointment_date, appointment_time", + "show_name_in_global_search": 1, + "sort_field": "modified", + "sort_order": "DESC", + "title_field": "patient", + "track_changes": 1, + "track_seen": 1, "track_views": 0 } diff --git a/erpnext/hooks.py b/erpnext/hooks.py index cbd3939b7b..c1bb41be74 100644 --- a/erpnext/hooks.py +++ b/erpnext/hooks.py @@ -12,7 +12,7 @@ app_license = "GNU General Public License (v3)" source_link = "https://github.com/frappe/erpnext" develop_version = '12.x.x-develop' -staging_version = '11.0.3-beta.25' +staging_version = '11.0.3-beta.26' error_report_email = "support@erpnext.com" diff --git a/erpnext/manufacturing/page/production_analytics/__init__.py b/erpnext/manufacturing/page/production_analytics/__init__.py deleted file mode 100644 index baffc48825..0000000000 --- a/erpnext/manufacturing/page/production_analytics/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/manufacturing/page/production_analytics/production_analytics.js b/erpnext/manufacturing/page/production_analytics/production_analytics.js deleted file mode 100644 index 1647313036..0000000000 --- a/erpnext/manufacturing/page/production_analytics/production_analytics.js +++ /dev/null @@ -1,155 +0,0 @@ -// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -// License: GNU General Public License v3. See license.txt - -frappe.pages['production-analytics'].on_page_load = function(wrapper) { - frappe.ui.make_app_page({ - parent: wrapper, - title: __('Production Analytics'), - single_column: true - }); - - new erpnext.ProductionAnalytics(wrapper); - - frappe.breadcrumbs.add("Manufacturing"); -} - -erpnext.ProductionAnalytics = frappe.views.GridReportWithPlot.extend({ - init: function(wrapper) { - this._super({ - title: __("Production Analytics"), - parent: $(wrapper).find('.layout-main'), - page: wrapper.page, - doctypes: ["Item", "Company", "Fiscal Year", "Work Order"] - }); - - }, - setup_columns: function() { - - var std_columns = [ - {id: "name", name: __("Status"), field: "name", width: 100} - ]; - - this.make_date_range_columns(); - this.columns = std_columns.concat(this.columns); - }, - filters: [ - {fieldtype:"Select", label: __("Company"), link:"Company", fieldname: "company", - default_value: __("Select Company...")}, - {fieldtype:"Date", label: __("From Date"), fieldname: "from_date"}, - {fieldtype:"Date", label: __("To Date"), fieldname: "to_date"}, - {fieldtype:"Select", label: __("Range"), fieldname: "range", - options:[{label: __("Daily"), value: "Daily"}, {label: __("Weekly"), value: "Weekly"}, - {label: __("Monthly"), value: "Monthly"}, {label: __("Quarterly"), value: "Quarterly"}, - {label: __("Yearly"), value: "Yearly"}]} - ], - setup_filters: function() { - var me = this; - this._super(); - - this.trigger_refresh_on_change(["company"]); - this.trigger_refresh_on_change(["range"]); - - this.show_zero_check(); - - }, - init_filter_values: function() { - this._super(); - this.filter_inputs.range.val('Monthly'); - }, - setup_chart: function() { - var me = this; - - var chart_data = this.get_chart_data ? this.get_chart_data() : null; - - const parent = this.wrapper.find('.chart')[0]; - this.chart = new Chart(parent, { - height: 200, - data: chart_data, - type: 'line' - }); - }, - set_default_values: function() { - var values = { - from_date: frappe.datetime.str_to_user(frappe.datetime.add_months(frappe.datetime.now_datetime(),-12) ), - to_date: frappe.datetime.str_to_user(frappe.datetime.add_months(frappe.datetime.now_datetime(),1)) - } - - var me = this; - $.each(values, function(i, v) { - if(me.filter_inputs[i] && !me.filter_inputs[i].val()) - me.filter_inputs[i].val(v); - }) - }, - - prepare_data: function() { - // add Opening, Closing, Totals rows - // if filtered by account and / or voucher - var me = this; - var all_open_orders = {name:"All Work Orders", "id": "all-open-pos", - checked:true}; - var not_started = {name:"Not Started", "id":"not-started-pos", - checked:true}; - var overdue = {name:"Overdue (Not Started)", "id":"overdue-pos", - checked:true}; - var pending = {name:"Pending", "id":"pending-pos", - checked:true}; - var completed = {name:"Completed", "id":"completed-pos", - checked:true}; - - $.each(frappe.report_dump.data["Work Order"], function(i, d) { - var dateobj = frappe.datetime.str_to_obj(d.creation); - var date = frappe.datetime.str_to_user(d.creation.split(" ")[0]); - - $.each(me.columns, function(i,col) { - if (i > 1){ - var start_period = frappe.datetime.user_to_obj(frappe.datetime.str_to_user(col.id)); - var end_period = frappe.datetime.user_to_obj(frappe.datetime.str_to_user(col.name)); - var astart_date = frappe.datetime.user_to_obj(frappe.datetime.str_to_user(d.actual_start_date)); - var planned_start_date = frappe.datetime.user_to_obj(frappe.datetime.str_to_user(d.planned_start_date)); - var aend_date = frappe.datetime.user_to_obj(frappe.datetime.str_to_user(d.actual_end_date)); - var modified = frappe.datetime.user_to_obj(frappe.datetime.str_to_user(d.modified)); - - if (dateobj <= start_period || dateobj <= end_period) { - all_open_orders[col.field] = flt(all_open_orders[col.field]) + 1; - - if(d.status=="Completed") { - if(aend_date < start_period || modified < start_period) { - completed[col.field] = flt(completed[col.field]) + 1; - } - else if (astart_date < start_period) { - pending[col.field] = flt(pending[col.field]) + 1; - } - else if (planned_start_date < start_period) { - overdue[col.field] = flt(overdue[col.field]) + 1; - } else { - not_started[col.field] = flt(not_started[col.field]) + 1; - } - }else if(d.status == "In Process") - { - if (astart_date < start_period || modified < start_period){ - pending[col.field] = flt(pending[col.field]) + 1; - }else if (planned_start_date < start_period) { - overdue[col.field] = flt(overdue[col.field]) + 1; - }else{ - not_started[col.field] = flt(not_started[col.field]) + 1; - } - }else if(d.status == "Not Started") { - if (planned_start_date < start_period){ - overdue[col.field] = flt(overdue[col.field]) + 1; - }else{ - not_started[col.field] = flt(not_started[col.field]) + 1; - } - } - } - } - }); - }); - if(me.columns.length < 30){ - this.chart_area.toggle(true); - }else { - this.chart_area.toggle(false); - } - this.data = [all_open_orders, not_started, overdue, pending, completed]; - - } -}); diff --git a/erpnext/manufacturing/page/production_analytics/production_analytics.json b/erpnext/manufacturing/page/production_analytics/production_analytics.json deleted file mode 100644 index cd73bc826f..0000000000 --- a/erpnext/manufacturing/page/production_analytics/production_analytics.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "content": null, - "creation": "2012-09-21 20:15:16", - "docstatus": 0, - "doctype": "Page", - "icon": "fa fa-bar-chart", - "idx": 1, - "modified": "2017-02-20 17:33:05.913097", - "modified_by": "Administrator", - "module": "Manufacturing", - "name": "production-analytics", - "owner": "Administrator", - "page_name": "production-analytics", - "roles": [ - { - "role": "Analytics" - }, - { - "role": "Manufacturing Manager" - } - ], - "script": null, - "standard": "Yes", - "style": null, - "title": "Production Analytics" -} \ No newline at end of file diff --git a/erpnext/manufacturing/report/production_analytics/production_analytics.js b/erpnext/manufacturing/report/production_analytics/production_analytics.js index b7b8f05d89..99f9b1260a 100644 --- a/erpnext/manufacturing/report/production_analytics/production_analytics.js +++ b/erpnext/manufacturing/report/production_analytics/production_analytics.js @@ -39,8 +39,5 @@ frappe.query_reports["Production Analytics"] = { default: "Monthly", reqd: 1 } - ], - "formatter": function(value, row, column, data) { - return value; - } + ] } diff --git a/erpnext/patches.txt b/erpnext/patches.txt index dc4c94c8d1..4a67eb4e47 100755 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -568,10 +568,10 @@ erpnext.patches.v11_0.remove_land_unit_icon erpnext.patches.v11_0.add_default_dispatch_notification_template erpnext.patches.v11_0.add_market_segments erpnext.patches.v11_0.add_sales_stages -execute:frappe.delete_doc("Page", "sales-analytics") -execute:frappe.delete_doc("Page", "purchase-analytics") -execute:frappe.delete_doc("Page", "stock-analytics") -execute:frappe.delete_doc("Page", "production-analytics") +execute:frappe.delete_doc_if_exists("Page", "sales-analytics") +execute:frappe.delete_doc_if_exists("Page", "purchase-analytics") +execute:frappe.delete_doc_if_exists("Page", "stock-analytics") +execute:frappe.delete_doc_if_exists("Page", "production-analytics") erpnext.patches.v11_0.ewaybill_fields_gst_india #2018-11-13 erpnext.patches.v11_0.drop_column_max_days_allowed erpnext.patches.v11_0.change_healthcare_desktop_icons diff --git a/erpnext/patches/v11_0/add_healthcare_service_unit_tree_root.py b/erpnext/patches/v11_0/add_healthcare_service_unit_tree_root.py index 0c4209ac9a..029ea8738b 100644 --- a/erpnext/patches/v11_0/add_healthcare_service_unit_tree_root.py +++ b/erpnext/patches/v11_0/add_healthcare_service_unit_tree_root.py @@ -3,12 +3,18 @@ from frappe import _ def execute(): """ assign lft and rgt appropriately """ + if "Healthcare" not in frappe.get_active_domains(): + return + frappe.reload_doc("healthcare", "doctype", "healthcare_service_unit") frappe.reload_doc("healthcare", "doctype", "healthcare_service_unit_type") + company = frappe.get_value("Company", {"domain": "Healthcare"}, "name") - if not frappe.db.exists("Healthcare Service Unit", _('All Healthcare Service Units')): + if company: frappe.get_doc({ 'doctype': 'Healthcare Service Unit', 'healthcare_service_unit_name': _('All Healthcare Service Units'), - 'is_group': 1 + 'is_group': 1, + 'company': company }).insert(ignore_permissions=True) + diff --git a/erpnext/public/js/utils.js b/erpnext/public/js/utils.js index baee68e6be..e2933210bb 100644 --- a/erpnext/public/js/utils.js +++ b/erpnext/public/js/utils.js @@ -103,12 +103,32 @@ $.extend(erpnext, { $.extend(erpnext.utils, { set_party_dashboard_indicators: function(frm) { if(frm.doc.__onload && frm.doc.__onload.dashboard_info) { - var info = frm.doc.__onload.dashboard_info; - frm.dashboard.add_indicator(__('Annual Billing: {0}', - [format_currency(info.billing_this_year, info.currency)]), 'blue'); - frm.dashboard.add_indicator(__('Total Unpaid: {0}', - [format_currency(info.total_unpaid, info.currency)]), - info.total_unpaid ? 'orange' : 'green'); + var company_wise_info = frm.doc.__onload.dashboard_info; + if(company_wise_info.length > 1) { + frm.dashboard.stats_area.removeClass('hidden'); + frm.dashboard.stats_area_row.addClass('flex'); + frm.dashboard.stats_area_row.css('flex-wrap', 'wrap'); + company_wise_info.forEach(function(info) { + frm.dashboard.stats_area_row.append( + '
'+ + '
'+info.company+'
'+ + ''+ + ''+ + '
' + ); + }); + } + else { + frm.dashboard.stats_area.removeClass('hidden'); + frm.dashboard.stats_area_row.append( + '
Annual Billing: ' + +format_currency(company_wise_info[0].billing_this_year, company_wise_info[0].currency)+'
' + + '
Total Unpaid: ' + +format_currency(company_wise_info[0].billing_this_year, company_wise_info[0].currency)+'
' + ); + } } }, diff --git a/erpnext/public/js/utils/item_quick_entry.js b/erpnext/public/js/utils/item_quick_entry.js index b12e3b8633..62b82ac012 100644 --- a/erpnext/public/js/utils/item_quick_entry.js +++ b/erpnext/public/js/utils/item_quick_entry.js @@ -320,7 +320,7 @@ frappe.ui.form.ItemQuickEntryForm = frappe.ui.form.QuickEntryForm.extend({ ["attribute_value", "like", e.target.value + "%"] ], fields: ["attribute_value"], - parent: "Item" + parent: "Item Attribute" }, callback: function(r) { if (r.message) { diff --git a/erpnext/selling/page/sales_analytics/README.md b/erpnext/selling/page/sales_analytics/README.md deleted file mode 100644 index 11994c26b9..0000000000 --- a/erpnext/selling/page/sales_analytics/README.md +++ /dev/null @@ -1 +0,0 @@ -Trends of sales by Item, Item Group, Customer etc. \ No newline at end of file diff --git a/erpnext/selling/page/sales_analytics/__init__.py b/erpnext/selling/page/sales_analytics/__init__.py deleted file mode 100644 index baffc48825..0000000000 --- a/erpnext/selling/page/sales_analytics/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/selling/page/sales_analytics/sales_analytics.js b/erpnext/selling/page/sales_analytics/sales_analytics.js deleted file mode 100644 index f5caf1d591..0000000000 --- a/erpnext/selling/page/sales_analytics/sales_analytics.js +++ /dev/null @@ -1,246 +0,0 @@ -// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -// License: GNU General Public License v3. See license.txt - -frappe.pages['sales-analytics'].on_page_load = function(wrapper) { - frappe.ui.make_app_page({ - parent: wrapper, - title: __('Sales Analytics'), - single_column: true - }); - new erpnext.SalesAnalytics(wrapper); - - - frappe.breadcrumbs.add("Selling") - -}; - -erpnext.SalesAnalytics = frappe.views.TreeGridReport.extend({ - init: function(wrapper) { - this._super({ - title: __("Sales Analytics"), - parent: $(wrapper).find('.layout-main'), - page: wrapper.page, - doctypes: ["Item", "Item Group", "Customer", "Customer Group", "Company", "Territory", - "Fiscal Year", "Sales Invoice", "Sales Invoice Item", - "Sales Order", "Sales Order Item[Sales Analytics]", - "Delivery Note", "Delivery Note Item[Sales Analytics]"], - tree_grid: { show: true } - }); - - this.tree_grids = { - "Customer Group": { - label: __("Customer Group / Customer"), - show: true, - item_key: "customer", - parent_field: "parent_customer_group", - formatter: function(item) { - return item.customer_name? item.customer_name + " (" + item.name + ")" : item.name; - } - }, - "Customer": { - label: __("Customer"), - show: false, - item_key: "customer", - formatter: function(item) { - return item.customer_name? item.customer_name + " (" + item.name + ")" : item.name; - } - }, - "Item Group": { - label: __("Item"), - show: true, - parent_field: "parent_item_group", - item_key: "item_code", - formatter: function(item) { - return item.name; - } - }, - "Item": { - label: __("Item"), - show: false, - item_key: "item_code", - formatter: function(item) { - return item.name; - } - }, - "Territory": { - label: __("Territory / Customer"), - show: true, - item_key: "customer", - parent_field: "parent_territory", - formatter: function(item) { - return item.customer_name? item.customer_name + " (" + item.name + ")" : item.name; - } - } - } - }, - setup_columns: function() { - this.tree_grid = this.tree_grids[this.tree_type]; - - var std_columns = [ - {id: "name", name: this.tree_grid.label, field: "name", width: 300}, - {id: "total", name: "Total", field: "total", plot: false, - formatter: this.currency_formatter} - ]; - - this.make_date_range_columns(); - this.columns = std_columns.concat(this.columns); - }, - filters: [ - {fieldtype:"Select", fieldname: "tree_type", label: __("Tree Type"), options:["Customer Group", "Customer", - "Item Group", "Item", "Territory"], - filter: function(val, item, opts, me) { - return me.apply_zero_filter(val, item, opts, me); - }}, - {fieldtype:"Select", fieldname: "based_on", label: __("Based On"), options:["Sales Invoice", - "Sales Order", "Delivery Note"]}, - {fieldtype:"Select", fieldname: "value_or_qty", label: __("Value or Qty"), - options:[{label: __("Value"), value: "Value"}, {label: __("Quantity"), value: "Quantity"}]}, - {fieldtype:"Date", fieldname: "from_date", label: __("From Date")}, - {fieldtype:"Label", fieldname: "to", label: __("To")}, - {fieldtype:"Date", fieldname: "to_date", label: __("To Date")}, - {fieldtype:"Select", fieldname: "company", label: __("Company"), link:"Company", - default_value: __("Select Company...")}, - {fieldtype:"Select", label: __("Range"), fieldname: "range", - options:[{label: __("Daily"), value: "Daily"}, {label: __("Weekly"), value: "Weekly"}, - {label: __("Monthly"), value: "Monthly"}, {label: __("Quarterly"), value: "Quarterly"}, - {label: __("Yearly"), value: "Yearly"}]} - ], - setup_filters: function() { - var me = this; - this._super(); - - this.trigger_refresh_on_change(["value_or_qty", "tree_type", "based_on", "company"]); - - this.show_zero_check(); - }, - init_filter_values: function() { - this._super(); - this.filter_inputs.range.val('Monthly'); - }, - prepare_data: function() { - var me = this; - if (!this.tl) { - // add 'Not Set' Customer & Item - // (Customer / Item are not mandatory!!) - frappe.report_dump.data["Customer"].push({ - name: "Not Set", - parent_customer_group: "All Customer Groups", - parent_territory: "All Territories", - id: "Not Set", - }); - - frappe.report_dump.data["Item"].push({ - name: "Not Set", - parent_item_group: "All Item Groups", - id: "Not Set", - }); - } - - if (!this.tl || !this.tl[this.based_on]) { - this.make_transaction_list(this.based_on, this.based_on + " Item"); - } - - if(!this.data || me.item_type != me.tree_type) { - if(me.tree_type=='Customer') { - var items = frappe.report_dump.data["Customer"]; - } if(me.tree_type=='Customer Group') { - var items = this.prepare_tree("Customer", "Customer Group"); - } else if(me.tree_type=="Item Group") { - var items = this.prepare_tree("Item", "Item Group"); - } else if(me.tree_type=="Item") { - var items = frappe.report_dump.data["Item"]; - } else if(me.tree_type=="Territory") { - var items = this.prepare_tree("Customer", "Territory"); - } - - me.item_type = me.tree_type - me.parent_map = {}; - me.item_by_name = {}; - me.data = []; - - $.each(items, function(i, v) { - var d = copy_dict(v); - - me.data.push(d); - me.item_by_name[d.name] = d; - if(d[me.tree_grid.parent_field]) { - me.parent_map[d.name] = d[me.tree_grid.parent_field]; - } - me.reset_item_values(d); - }); - - this.set_indent(); - - } else { - // otherwise, only reset values - $.each(this.data, function(i, d) { - me.reset_item_values(d); - }); - } - - this.prepare_balances(); - if(me.tree_grid.show) { - this.set_totals(false); - this.update_groups(); - } else { - this.set_totals(true); - } - - }, - prepare_balances: function() { - var me = this; - var from_date = frappe.datetime.str_to_obj(this.from_date); - var to_date = frappe.datetime.str_to_obj(this.to_date); - var is_val = this.value_or_qty == 'Value'; - - $.each(this.tl[this.based_on], function(i, tl) { - if (me.is_default('company') ? true : tl.company === me.company) { - var posting_date = frappe.datetime.str_to_obj(tl.posting_date); - if (posting_date >= from_date && posting_date <= to_date) { - var item = me.item_by_name[tl[me.tree_grid.item_key]] || - me.item_by_name['Not Set']; - if(item){ - item[me.column_map[tl.posting_date].field] += (is_val ? tl.base_net_amount : tl.qty); - } - } - } - }); - }, - update_groups: function() { - var me = this; - - $.each(this.data, function(i, item) { - var parent = me.parent_map[item.name]; - while(parent) { - var parent_group = me.item_by_name[parent]; - - $.each(me.columns, function(c, col) { - if (col.formatter == me.currency_formatter) { - parent_group[col.field] = - flt(parent_group[col.field]) - + flt(item[col.field]); - } - }); - parent = me.parent_map[parent]; - } - }); - }, - set_totals: function(sort) { - var me = this; - var checked = false; - $.each(this.data, function(i, d) { - d.total = 0.0; - $.each(me.columns, function(i, col) { - if(col.formatter==me.currency_formatter && !col.hidden && col.field!="total") - d.total += d[col.field]; - if(d.checked) checked = true; - }) - }); - - if(sort)this.data = this.data.sort(function(a, b) { return a.total < b.total; }); - - if(!this.checked) { - this.data[0].checked = true; - } - } -}); diff --git a/erpnext/selling/page/sales_analytics/sales_analytics.json b/erpnext/selling/page/sales_analytics/sales_analytics.json deleted file mode 100644 index 4a7761ebaf..0000000000 --- a/erpnext/selling/page/sales_analytics/sales_analytics.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "creation": "2012-09-21 20:15:12.000000", - "docstatus": 0, - "doctype": "Page", - "icon": "fa fa-bar-chart", - "idx": 1, - "modified": "2013-07-11 14:43:59.000000", - "modified_by": "Administrator", - "module": "Selling", - "name": "sales-analytics", - "owner": "Administrator", - "page_name": "sales-analytics", - "roles": [ - { - "role": "Analytics" - }, - { - "role": "Sales Manager" - }, - { - "role": "Maintenance Manager" - } - ], - "standard": "Yes", - "title": "Sales Analytics" -} \ No newline at end of file diff --git a/erpnext/selling/report/sales_analytics/sales_analytics.js b/erpnext/selling/report/sales_analytics/sales_analytics.js index 7dc7c754bc..0df425d1cd 100644 --- a/erpnext/selling/report/sales_analytics/sales_analytics.js +++ b/erpnext/selling/report/sales_analytics/sales_analytics.js @@ -67,6 +67,9 @@ frappe.query_reports["Sales Analytics"] = { reqd: 1 } ], + after_datatable_render: function(datatable_obj) { + $(datatable_obj.wrapper).find(".dt-row-0").find('input[type=checkbox]').click(); + }, get_datatable_options(options) { return Object.assign(options, { checkboxColumn: true, @@ -106,12 +109,12 @@ frappe.query_reports["Sales Analytics"] = { setTimeout(() => { frappe.query_report.chart.update(new_data) - },200) + }, 500) setTimeout(() => { frappe.query_report.chart.draw(true); - }, 800) + }, 1000) frappe.query_report.raw_chart_data = new_data; }, diff --git a/erpnext/selling/report/sales_analytics/sales_analytics.py b/erpnext/selling/report/sales_analytics/sales_analytics.py index 8d99a9b789..9cc6c404a6 100644 --- a/erpnext/selling/report/sales_analytics/sales_analytics.py +++ b/erpnext/selling/report/sales_analytics/sales_analytics.py @@ -212,11 +212,11 @@ class Analytics(object): def get_period(self, posting_date): if self.filters.range == 'Weekly': - period = "Week " + str(posting_date.isocalendar()[1]) + period = "Week " + str(posting_date.isocalendar()[1]) + " " + str(posting_date.year) elif self.filters.range == 'Monthly': - period = self.months[posting_date.month - 1] + period = str(self.months[posting_date.month - 1]) + " " + str(posting_date.year) elif self.filters.range == 'Quarterly': - period = "Quarter " + str(((posting_date.month-1)//3)+1) + period = "Quarter " + str(((posting_date.month-1)//3)+1) +" " + str(posting_date.year) else: year = get_fiscal_year(posting_date, company=self.filters.company) period = str(year[2]) @@ -280,8 +280,7 @@ class Analytics(object): self.chart = { "data": { 'labels': labels, - 'datasets':[ - ] + 'datasets':[] }, "type": "line" } \ No newline at end of file diff --git a/erpnext/selling/report/sales_analytics/test_analytics.py b/erpnext/selling/report/sales_analytics/test_analytics.py index f59fff46f7..5d68b06b6d 100644 --- a/erpnext/selling/report/sales_analytics/test_analytics.py +++ b/erpnext/selling/report/sales_analytics/test_analytics.py @@ -35,52 +35,52 @@ class TestAnalytics(unittest.TestCase): { "entity": "_Test Customer 1", "entity_name": "_Test Customer 1", - "apr": 0.0, - "may": 0.0, - "jun": 0.0, - "jul": 0.0, - "aug": 0.0, - "sep": 0.0, - "oct": 0.0, - "nov": 0.0, - "dec": 0.0, - "jan": 0.0, - "feb": 2000.0, - "mar": 0.0, + "apr_2017": 0.0, + "may_2017": 0.0, + "jun_2017": 0.0, + "jul_2017": 0.0, + "aug_2017": 0.0, + "oct_2017": 0.0, + "sep_2017": 0.0, + "nov_2017": 0.0, + "dec_2017": 0.0, + "jan_2018": 0.0, + "feb_2018": 2000.0, + "mar_2018": 0.0, "total":2000.0 }, { "entity": "_Test Customer 2", "entity_name": "_Test Customer 2", - "apr": 0.0, - "may": 0.0, - "jun": 0.0, - "jul": 0.0, - "aug": 0.0, - "sep": 1500.0, - "oct": 1000.0, - "nov": 0.0, - "dec": 0.0, - "jan": 0.0, - "feb": 0.0, - "mar": 0.0, + "apr_2017": 0.0, + "may_2017": 0.0, + "jun_2017": 0.0, + "jul_2017": 0.0, + "aug_2017": 0.0, + "sep_2017": 1500.0, + "oct_2017": 1000.0, + "nov_2017": 0.0, + "dec_2017": 0.0, + "jan_2018": 0.0, + "feb_2018": 0.0, + "mar_2018": 0.0, "total":2500.0 }, { "entity": "_Test Customer 3", "entity_name": "_Test Customer 3", - "apr": 0.0, - "may": 0.0, - "jun": 2000.0, - "jul": 1000.0, - "aug": 0.0, - "sep": 0.0, - "oct": 0.0, - "nov": 0.0, - "dec": 0.0, - "jan": 0.0, - "feb": 0.0, - "mar": 0.0, + "apr_2017": 0.0, + "may_2017": 0.0, + "jun_2017": 2000.0, + "jul_2017": 1000.0, + "aug_2017": 0.0, + "sep_2017": 0.0, + "oct_2017": 0.0, + "nov_2017": 0.0, + "dec_2017": 0.0, + "jan_2018": 0.0, + "feb_2018": 0.0, + "mar_2018": 0.0, "total": 3000.0 } ] @@ -103,18 +103,18 @@ class TestAnalytics(unittest.TestCase): expected_first_row = { "entity": "All Customer Groups", "indent": 0, - "apr": 0.0, - "may": 0.0, - "jun": 2000.0, - "jul": 1000.0, - "aug": 0.0, - "sep": 1500.0, - "oct": 1000.0, - "nov": 0.0, - "dec": 0.0, - "jan": 0.0, - "feb": 2000.0, - "mar": 0.0, + "apr_2017": 0.0, + "may_2017": 0.0, + "jun_2017": 2000.0, + "jul_2017": 1000.0, + "aug_2017": 0.0, + "sep_2017": 1500.0, + "oct_2017": 1000.0, + "nov_2017": 0.0, + "dec_2017": 0.0, + "jan_2018": 0.0, + "feb_2018": 2000.0, + "mar_2018": 0.0, "total":7500.0 } self.assertEqual(expected_first_row, report[1][0]) @@ -136,52 +136,52 @@ class TestAnalytics(unittest.TestCase): { "entity": "_Test Customer 1", "entity_name": "_Test Customer 1", - "apr": 0.0, - "may": 0.0, - "jun": 0.0, - "jul": 0.0, - "aug": 0.0, - "sep": 0.0, - "oct": 0.0, - "nov": 0.0, - "dec": 0.0, - "jan": 0.0, - "feb": 20.0, - "mar": 0.0, + "apr_2017": 0.0, + "may_2017": 0.0, + "jun_2017": 0.0, + "jul_2017": 0.0, + "aug_2017": 0.0, + "sep_2017": 0.0, + "oct_2017": 0.0, + "nov_2017": 0.0, + "dec_2017": 0.0, + "jan_2018": 0.0, + "feb_2018": 20.0, + "mar_2018": 0.0, "total":20.0 }, { "entity": "_Test Customer 2", "entity_name": "_Test Customer 2", - "apr": 0.0, - "may": 0.0, - "jun": 0.0, - "jul": 0.0, - "aug": 0.0, - "sep": 15.0, - "oct": 10.0, - "nov": 0.0, - "dec": 0.0, - "jan": 0.0, - "feb": 0.0, - "mar": 0.0, + "apr_2017": 0.0, + "may_2017": 0.0, + "jun_2017": 0.0, + "jul_2017": 0.0, + "aug_2017": 0.0, + "sep_2017": 15.0, + "oct_2017": 10.0, + "nov_2017": 0.0, + "dec_2017": 0.0, + "jan_2018": 0.0, + "feb_2018": 0.0, + "mar_2018": 0.0, "total":25.0 }, { "entity": "_Test Customer 3", "entity_name": "_Test Customer 3", - "apr": 0.0, - "may": 0.0, - "jun": 20.0, - "jul": 10.0, - "aug": 0.0, - "sep": 0.0, - "oct": 0.0, - "nov": 0.0, - "dec": 0.0, - "jan": 0.0, - "feb": 0.0, - "mar": 0.0, + "apr_2017": 0.0, + "may_2017": 0.0, + "jun_2017": 20.0, + "jul_2017": 10.0, + "aug_2017": 0.0, + "sep_2017": 0.0, + "oct_2017": 0.0, + "nov_2017": 0.0, + "dec_2017": 0.0, + "jan_2018": 0.0, + "feb_2018": 0.0, + "mar_2018": 0.0, "total": 30.0 } ] diff --git a/erpnext/stock/doctype/item/item.js b/erpnext/stock/doctype/item/item.js index b3141e87fa..a26da7fbe3 100644 --- a/erpnext/stock/doctype/item/item.js +++ b/erpnext/stock/doctype/item/item.js @@ -513,7 +513,7 @@ $.extend(erpnext.item, { fields: ["attribute_value"], limit_start: 0, limit_page_length: 500, - parent: "Item", + parent: "Item Attribute", order_by: "idx" } }).then((r) => { @@ -651,7 +651,7 @@ $.extend(erpnext.item, { frappe.call({ method:"erpnext.stock.doctype.item.item.get_item_attribute", args:{ - parent: i, + parent: "Item Attribute", attribute_value: term }, callback: function(r) { diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py index 17cf044074..566b6386fe 100644 --- a/erpnext/stock/doctype/item/item.py +++ b/erpnext/stock/doctype/item/item.py @@ -32,6 +32,10 @@ class StockExistsForTemplate(frappe.ValidationError): pass +class InvalidBarcode(frappe.ValidationError): + pass + + class Item(WebsiteGenerator): website = frappe._dict( page_title_field="item_name", @@ -502,19 +506,19 @@ class Item(WebsiteGenerator): from stdnum import ean if len(self.barcodes) > 0: for item_barcode in self.barcodes: - options = frappe.get_meta("Item Barcode").get_options("barcode_type").split() + options = frappe.get_meta("Item Barcode").get_options("barcode_type").split('\n') if item_barcode.barcode: duplicate = frappe.db.sql( """select parent from `tabItem Barcode` where barcode = %s and parent != %s""", (item_barcode.barcode, self.name)) if duplicate: frappe.throw(_("Barcode {0} already used in Item {1}").format( - item_barcode.barcode, duplicate[0][0])) + item_barcode.barcode, duplicate[0][0]), frappe.DuplicateEntryError) item_barcode.barcode_type = "" if item_barcode.barcode_type not in options else item_barcode.barcode_type - if item_barcode.barcode_type: + if item_barcode.barcode_type and item_barcode.barcode_type.upper() in ('EAN', 'UPC-A', 'EAN-13', 'EAN-8'): if not ean.is_valid(item_barcode.barcode): frappe.throw(_("Barcode {0} is not a valid {1} code").format( - item_barcode.barcode, item_barcode.barcode_type)) + item_barcode.barcode, item_barcode.barcode_type), InvalidBarcode) def validate_warehouse_for_reorder(self): '''Validate Reorder level table for duplicate and conditional mandatory''' diff --git a/erpnext/stock/doctype/item/test_item.py b/erpnext/stock/doctype/item/test_item.py index 7ef4f8cecc..24292f7b4f 100644 --- a/erpnext/stock/doctype/item/test_item.py +++ b/erpnext/stock/doctype/item/test_item.py @@ -8,7 +8,7 @@ import frappe from frappe.test_runner import make_test_objects from erpnext.controllers.item_variant import (create_variant, ItemVariantExistsError, InvalidItemAttributeValueError, get_variant) -from erpnext.stock.doctype.item.item import StockExistsForTemplate +from erpnext.stock.doctype.item.item import StockExistsForTemplate, InvalidBarcode from erpnext.stock.doctype.item.item import get_uom_conv_factor from frappe.model.rename_doc import rename_doc from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry @@ -305,6 +305,65 @@ class TestItem(unittest.TestCase): item_doc.has_variants = 1 self.assertRaises(StockExistsForTemplate, item_doc.save) + def test_add_item_barcode(self): + # Clean up + frappe.db.sql("""delete from `tabItem Barcode`""") + item_code = "Test Item Barcode" + if frappe.db.exists("Item", item_code): + frappe.delete_doc("Item", item_code) + + # Create new item and add barcodes + barcode_properties_list = [ + { + "barcode": "0012345678905", + "barcode_type": "EAN" + }, + { + "barcode": "012345678905", + "barcode_type": "UAN" + }, + { + "barcode": "ARBITRARY_TEXT", + } + ] + create_item(item_code) + for barcode_properties in barcode_properties_list: + item_doc = frappe.get_doc('Item', item_code) + new_barcode = item_doc.append('barcodes') + new_barcode.update(barcode_properties) + item_doc.save() + + # Check values saved correctly + barcodes = frappe.get_list( + 'Item Barcode', + fields=['barcode', 'barcode_type'], + filters={'parent': item_code}) + + for barcode_properties in barcode_properties_list: + barcode_to_find = barcode_properties['barcode'] + matching_barcodes = [ + x for x in barcodes + if x['barcode'] == barcode_to_find + ] + self.assertEqual(len(matching_barcodes), 1) + details = matching_barcodes[0] + + for key, value in iteritems(barcode_properties): + self.assertEqual(value, details.get(key)) + + # Add barcode again - should cause DuplicateEntryError + item_doc = frappe.get_doc('Item', item_code) + new_barcode = item_doc.append('barcodes') + new_barcode.update(barcode_properties_list[0]) + self.assertRaises(frappe.DuplicateEntryError, item_doc.save) + + # Add invalid barcode - should cause InvalidBarcode + item_doc = frappe.get_doc('Item', item_code) + new_barcode = item_doc.append('barcodes') + new_barcode.barcode = '9999999999999' + new_barcode.barcode_type = 'EAN' + self.assertRaises(InvalidBarcode, item_doc.save) + def set_item_variant_settings(fields): doc = frappe.get_doc('Item Variant Settings') doc.set('fields', fields) diff --git a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py index 3b20b1cf64..6b5bb2825f 100644 --- a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py +++ b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py @@ -181,7 +181,7 @@ class StockReconciliation(StockController): frappe.throw(_("Valuation Rate required for Item in row {0}").format(row.idx)) if ((previous_sle and row.qty == previous_sle.get("qty_after_transaction") - and row.valuation_rate == previous_sle.get("valuation_rate")) + and (row.valuation_rate == previous_sle.get("valuation_rate") or row.qty == 0)) or (not previous_sle and not row.qty)): continue diff --git a/erpnext/stock/page/stock_analytics/README.md b/erpnext/stock/page/stock_analytics/README.md deleted file mode 100644 index 86c3644322..0000000000 --- a/erpnext/stock/page/stock_analytics/README.md +++ /dev/null @@ -1 +0,0 @@ -Trends of Items quantities and values. \ No newline at end of file diff --git a/erpnext/stock/page/stock_analytics/__init__.py b/erpnext/stock/page/stock_analytics/__init__.py deleted file mode 100644 index baffc48825..0000000000 --- a/erpnext/stock/page/stock_analytics/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/stock/page/stock_analytics/stock_analytics.js b/erpnext/stock/page/stock_analytics/stock_analytics.js deleted file mode 100644 index 6deeb7a1f4..0000000000 --- a/erpnext/stock/page/stock_analytics/stock_analytics.js +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -// License: GNU General Public License v3. See license.txt - -frappe.pages['stock-analytics'].on_page_load = function(wrapper) { - frappe.ui.make_app_page({ - parent: wrapper, - title: __('Stock Analytics'), - single_column: true - }); - - frappe.require(["assets/erpnext/js/stock_grid_report.js", - "assets/erpnext/js/stock_analytics.js"], function() { - new erpnext.StockAnalytics(wrapper); - frappe.breadcrumbs.add("Stock") - }); -}; diff --git a/erpnext/stock/page/stock_analytics/stock_analytics.json b/erpnext/stock/page/stock_analytics/stock_analytics.json deleted file mode 100644 index 90e9f2e56b..0000000000 --- a/erpnext/stock/page/stock_analytics/stock_analytics.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "creation": "2012-09-21 20:15:14.000000", - "docstatus": 0, - "doctype": "Page", - "icon": "fa fa-bar-chart", - "idx": 1, - "modified": "2013-07-11 14:44:10.000000", - "modified_by": "Administrator", - "module": "Stock", - "name": "stock-analytics", - "owner": "Administrator", - "page_name": "stock-analytics", - "roles": [ - { - "role": "Analytics" - }, - { - "role": "Material Manager" - } - ], - "standard": "Yes", - "title": "Stock Analytics" -} \ No newline at end of file diff --git a/erpnext/stock/report/stock_analytics/stock_analytics.js b/erpnext/stock/report/stock_analytics/stock_analytics.js index bebc84e057..6b384e2861 100644 --- a/erpnext/stock/report/stock_analytics/stock_analytics.js +++ b/erpnext/stock/report/stock_analytics/stock_analytics.js @@ -71,16 +71,8 @@ frappe.query_reports["Stock Analytics"] = { reqd: 1 } ], - "formatter": function(value, row, column, data) { - if(!value && (column.fieldname == 'brand' || column.fieldname == 'uom')){ - value = "" - } - - if(Number(value)){ - value = value.toFixed(2) - } - - return value; + after_datatable_render: function(datatable_obj) { + $(datatable_obj.wrapper).find(".dt-row-0").find('input[type=checkbox]').click(); }, get_datatable_options(options) { return Object.assign(options, { @@ -120,16 +112,16 @@ frappe.query_reports["Stock Analytics"] = { setTimeout(() => { frappe.query_report.chart.update(new_data) - },200) + },500) setTimeout(() => { frappe.query_report.chart.draw(true); - }, 800) + }, 1000) frappe.query_report.raw_chart_data = new_data; }, } - }) - }, + }); + } } diff --git a/erpnext/stock/report/stock_analytics/stock_analytics.py b/erpnext/stock/report/stock_analytics/stock_analytics.py index dad8be1b8c..54eefdfaaa 100644 --- a/erpnext/stock/report/stock_analytics/stock_analytics.py +++ b/erpnext/stock/report/stock_analytics/stock_analytics.py @@ -99,11 +99,11 @@ def get_period(posting_date, filters): months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"] if filters.range == 'Weekly': - period = "Week " + str(posting_date.isocalendar()[1]) + period = "Week " + str(posting_date.isocalendar()[1]) + " " + str(posting_date.year) elif filters.range == 'Monthly': - period = months[posting_date.month - 1] + period = str(months[posting_date.month - 1]) + " " + str(posting_date.year) elif filters.range == 'Quarterly': - period = "Quarter " + str(((posting_date.month-1)//3)+1) + period = "Quarter " + str(((posting_date.month-1)//3)+1) +" " + str(posting_date.year) else: year = get_fiscal_year(posting_date, company=filters.company) period = str(year[2]) diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py index 0c83529702..0ef2afa4a8 100644 --- a/erpnext/stock/stock_ledger.py +++ b/erpnext/stock/stock_ledger.py @@ -178,7 +178,7 @@ class update_entries_after(object): # rounding as per precision self.stock_value = flt(self.stock_value, self.precision) - if self.prev_stock_value < 0 and self.stock_value >= 0: + if self.prev_stock_value < 0 and self.stock_value >= 0 and sle.voucher_type != 'Stock Reconciliation': stock_value_difference = sle.actual_qty * self.valuation_rate else: stock_value_difference = self.stock_value - self.prev_stock_value