Merge branch 'staging' into develop
This commit is contained in:
commit
7c2a5bddb1
@ -5,7 +5,7 @@ import frappe
|
|||||||
from erpnext.hooks import regional_overrides
|
from erpnext.hooks import regional_overrides
|
||||||
from frappe.utils import getdate
|
from frappe.utils import getdate
|
||||||
|
|
||||||
__version__ = '10.1.73'
|
__version__ = '10.1.74'
|
||||||
|
|
||||||
def get_default_company(user=None):
|
def get_default_company(user=None):
|
||||||
'''Get default company for user'''
|
'''Get default company for user'''
|
||||||
|
@ -70,12 +70,14 @@ class PeriodClosingVoucher(AccountsController):
|
|||||||
net_pl_balance += flt(acc.balance_in_company_currency)
|
net_pl_balance += flt(acc.balance_in_company_currency)
|
||||||
|
|
||||||
if net_pl_balance:
|
if net_pl_balance:
|
||||||
|
cost_center = frappe.db.get_value("Company", self.company, "cost_center")
|
||||||
gl_entries.append(self.get_gl_dict({
|
gl_entries.append(self.get_gl_dict({
|
||||||
"account": self.closing_account_head,
|
"account": self.closing_account_head,
|
||||||
"debit_in_account_currency": abs(net_pl_balance) if net_pl_balance > 0 else 0,
|
"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,
|
"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_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
|
from erpnext.accounts.general_ledger import make_gl_entries
|
||||||
|
@ -72,6 +72,7 @@ class TestPeriodClosingVoucher(unittest.TestCase):
|
|||||||
"company": "_Test Company",
|
"company": "_Test Company",
|
||||||
"fiscal_year": get_fiscal_year(today(), company="_Test Company")[0],
|
"fiscal_year": get_fiscal_year(today(), company="_Test Company")[0],
|
||||||
"posting_date": today(),
|
"posting_date": today(),
|
||||||
|
"cost_center": "_Test Cost Center - _TC",
|
||||||
"remarks": "test"
|
"remarks": "test"
|
||||||
})
|
})
|
||||||
pcv.insert()
|
pcv.insert()
|
||||||
|
@ -21,8 +21,6 @@ class TestPricingRule(unittest.TestCase):
|
|||||||
from erpnext.stock.get_item_details import get_item_details
|
from erpnext.stock.get_item_details import get_item_details
|
||||||
from frappe import MandatoryError
|
from frappe import MandatoryError
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
test_record = {
|
test_record = {
|
||||||
"doctype": "Pricing Rule",
|
"doctype": "Pricing Rule",
|
||||||
"title": "_Test Pricing Rule",
|
"title": "_Test Pricing Rule",
|
||||||
@ -93,7 +91,7 @@ class TestPricingRule(unittest.TestCase):
|
|||||||
|
|
||||||
args.item_code = "_Test Item 2"
|
args.item_code = "_Test Item 2"
|
||||||
details = get_item_details(args)
|
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):
|
def test_pricing_rule_for_margin(self):
|
||||||
from erpnext.stock.get_item_details import get_item_details
|
from erpnext.stock.get_item_details import get_item_details
|
||||||
@ -137,8 +135,8 @@ class TestPricingRule(unittest.TestCase):
|
|||||||
"name": None
|
"name": None
|
||||||
})
|
})
|
||||||
details = get_item_details(args)
|
details = get_item_details(args)
|
||||||
self.assertEqual(details.get("margin_type"), "Percentage")
|
self.assertEquals(details.get("margin_type"), "Percentage")
|
||||||
self.assertEqual(details.get("margin_rate_or_amount"), 10)
|
self.assertEquals(details.get("margin_rate_or_amount"), 10)
|
||||||
|
|
||||||
def test_pricing_rule_for_variants(self):
|
def test_pricing_rule_for_variants(self):
|
||||||
from erpnext.stock.get_item_details import get_item_details
|
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)
|
self.assertEqual(so.items[0].rate, 100)
|
||||||
|
|
||||||
def test_pricing_rule_with_margin_and_discount(self):
|
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)
|
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 = create_sales_invoice(do_not_save=True)
|
||||||
si.items[0].price_list_rate = 1000
|
si.items[0].price_list_rate = 1000
|
||||||
@ -260,12 +259,11 @@ class TestPricingRule(unittest.TestCase):
|
|||||||
si.insert(ignore_permissions=True)
|
si.insert(ignore_permissions=True)
|
||||||
|
|
||||||
item = si.items[0]
|
item = si.items[0]
|
||||||
self.assertEqual(item.margin_rate_or_amount, 10)
|
self.assertEquals(item.margin_rate_or_amount, 10)
|
||||||
self.assertEqual(item.rate_with_margin, 1100)
|
self.assertEquals(item.rate_with_margin, 1100)
|
||||||
self.assertEqual(item.discount_percentage, 10)
|
self.assertEqual(item.discount_percentage, 10)
|
||||||
self.assertEqual(item.discount_amount, 110)
|
self.assertEquals(item.discount_amount, 110)
|
||||||
self.assertEqual(item.rate, 990)
|
self.assertEquals(item.rate, 990)
|
||||||
|
|
||||||
|
|
||||||
def make_pricing_rule(**args):
|
def make_pricing_rule(**args):
|
||||||
args = frappe._dict(args)
|
args = frappe._dict(args)
|
||||||
|
@ -459,38 +459,65 @@ def get_timeline_data(doctype, name):
|
|||||||
|
|
||||||
def get_dashboard_info(party_type, party):
|
def get_dashboard_info(party_type, party):
|
||||||
current_fiscal_year = get_fiscal_year(nowdate(), as_dict=True)
|
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"
|
doctype = "Sales Invoice" if party_type=="Customer" else "Purchase Invoice"
|
||||||
|
|
||||||
billing_this_year = frappe.db.sql("""
|
companies = frappe.get_all(doctype, filters={
|
||||||
select sum({0})
|
'docstatus': 1,
|
||||||
from `tab{1}`
|
party_type.lower(): party
|
||||||
where {2}=%s and docstatus=1 and posting_date between %s and %s
|
}, distinct=1, fields=['company'])
|
||||||
""".format(total_field, doctype, party_type.lower()),
|
|
||||||
(party, current_fiscal_year.year_start_date, current_fiscal_year.year_end_date))
|
|
||||||
|
|
||||||
total_unpaid = frappe.db.sql("""
|
company_wise_info = []
|
||||||
select sum(debit_in_account_currency) - sum(credit_in_account_currency)
|
|
||||||
|
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`
|
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)))
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
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 = {}
|
||||||
info["billing_this_year"] = flt(billing_this_year[0][0]) if billing_this_year else 0
|
info["billing_this_year"] = flt(billing_this_year) if billing_this_year else 0
|
||||||
info["currency"] = party_account_currency
|
info["currency"] = party_account_currency
|
||||||
info["total_unpaid"] = flt(total_unpaid[0][0]) if total_unpaid else 0
|
info["total_unpaid"] = flt(total_unpaid) if total_unpaid else 0
|
||||||
|
info["company"] = d.company
|
||||||
|
|
||||||
if party_type == "Supplier":
|
if party_type == "Supplier":
|
||||||
info["total_unpaid"] = -1 * info["total_unpaid"]
|
info["total_unpaid"] = -1 * info["total_unpaid"]
|
||||||
|
|
||||||
return info
|
company_wise_info.append(info)
|
||||||
|
|
||||||
|
return company_wise_info
|
||||||
|
|
||||||
def get_party_shipping_address(doctype, name):
|
def get_party_shipping_address(doctype, name):
|
||||||
"""
|
"""
|
||||||
|
@ -1 +0,0 @@
|
|||||||
Trends of purchases across Items, Item Groups, Suppliers.
|
|
@ -1 +0,0 @@
|
|||||||
from __future__ import unicode_literals
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
@ -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"
|
|
||||||
}
|
|
@ -68,11 +68,8 @@ frappe.query_reports["Purchase Analytics"] = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
],
|
],
|
||||||
"formatter": function(value, row, column, data) {
|
after_datatable_render: function(datatable_obj) {
|
||||||
if(!value){
|
$(datatable_obj.wrapper).find(".dt-row-0").find('input[type=checkbox]').click();
|
||||||
value = 0
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
},
|
},
|
||||||
get_datatable_options(options) {
|
get_datatable_options(options) {
|
||||||
return Object.assign(options, {
|
return Object.assign(options, {
|
||||||
@ -113,16 +110,16 @@ frappe.query_reports["Purchase Analytics"] = {
|
|||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
frappe.query_report.chart.update(new_data)
|
frappe.query_report.chart.update(new_data)
|
||||||
},200)
|
},500)
|
||||||
|
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
frappe.query_report.chart.draw(true);
|
frappe.query_report.chart.draw(true);
|
||||||
}, 800)
|
}, 1000)
|
||||||
|
|
||||||
frappe.query_report.raw_chart_data = new_data;
|
frappe.query_report.raw_chart_data = new_data;
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
|
@ -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']:
|
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)
|
item.rate_with_margin, item.base_rate_with_margin = self.calculate_margin(item)
|
||||||
|
|
||||||
if flt(item.rate_with_margin) > 0:
|
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.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
|
item.discount_amount = item.rate_with_margin - item.rate
|
||||||
|
@ -38,6 +38,12 @@ frappe.ui.form.on("Assessment Result", {
|
|||||||
frappe.ui.form.on("Assessment Result Detail", {
|
frappe.ui.form.on("Assessment Result Detail", {
|
||||||
score: function(frm, cdt, cdn) {
|
score: function(frm, cdt, cdn) {
|
||||||
var d = locals[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) {
|
if (d.score > d.maximum_score) {
|
||||||
frappe.throw(__("Score cannot be greater than Maximum Score"));
|
frappe.throw(__("Score cannot be greater than Maximum Score"));
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,9 @@ frappe.ui.form.on('Patient Appointment', {
|
|||||||
frm.add_custom_button(__('Cancel'), function() {
|
frm.add_custom_button(__('Cancel'), function() {
|
||||||
btn_update_status(frm, "Cancelled");
|
btn_update_status(frm, "Cancelled");
|
||||||
});
|
});
|
||||||
|
frm.add_custom_button(__('Reschedule'), function() {
|
||||||
|
check_and_set_availability(frm);
|
||||||
|
});
|
||||||
if(frm.doc.procedure_template){
|
if(frm.doc.procedure_template){
|
||||||
frm.add_custom_button(__("Procedure"),function(){
|
frm.add_custom_button(__("Procedure"),function(){
|
||||||
btn_create_procedure(frm);
|
btn_create_procedure(frm);
|
||||||
@ -59,7 +61,9 @@ frappe.ui.form.on('Patient Appointment', {
|
|||||||
frm.add_custom_button(__('Cancel'), function() {
|
frm.add_custom_button(__('Cancel'), function() {
|
||||||
btn_update_status(frm, "Cancelled");
|
btn_update_status(frm, "Cancelled");
|
||||||
});
|
});
|
||||||
|
frm.add_custom_button(__('Reschedule'), function() {
|
||||||
|
check_and_set_availability(frm);
|
||||||
|
});
|
||||||
if(frm.doc.procedure_template){
|
if(frm.doc.procedure_template){
|
||||||
frm.add_custom_button(__("Procedure"),function(){
|
frm.add_custom_button(__("Procedure"),function(){
|
||||||
btn_create_procedure(frm);
|
btn_create_procedure(frm);
|
||||||
@ -100,29 +104,27 @@ frappe.ui.form.on('Patient Appointment', {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
check_availability: function(frm) {
|
check_availability: function(frm) {
|
||||||
var { practitioner, appointment_date } = frm.doc;
|
check_and_set_availability(frm);
|
||||||
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) => {
|
onload:function(frm){
|
||||||
var data = r.message;
|
if(frm.is_new()) {
|
||||||
if(data.slot_details.length > 0){
|
frm.set_value("appointment_time", null);
|
||||||
show_availability(data);
|
frm.disable_save();
|
||||||
}else{
|
|
||||||
show_empty_state();
|
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
get_procedure_from_encounter: function(frm) {
|
||||||
|
get_procedure_prescribed(frm);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function show_empty_state() {
|
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({
|
frappe.msgprint({
|
||||||
title: __('Not Available'),
|
title: __('Not Available'),
|
||||||
message: __("Healthcare Practitioner {0} not available on {1}", [practitioner.bold(), appointment_date.bold()]),
|
message: __("Healthcare Practitioner {0} not available on {1}", [practitioner.bold(), appointment_date.bold()]),
|
||||||
@ -130,41 +132,103 @@ frappe.ui.form.on('Patient Appointment', {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function show_availability(data) {
|
function show_availability() {
|
||||||
|
let selected_practitioner = '';
|
||||||
var d = new frappe.ui.Dialog({
|
var d = new frappe.ui.Dialog({
|
||||||
title: __("Available slots"),
|
title: __("Available slots"),
|
||||||
fields: [{ fieldtype: 'HTML', fieldname: '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_label: __("Book"),
|
||||||
primary_action: function() {
|
primary_action: function() {
|
||||||
// book slot
|
frm.set_value('appointment_time', selected_slot);
|
||||||
var btn_selected = $wrapper.find('button.btn-selected-slot');
|
frm.set_value('service_unit', service_unit || '');
|
||||||
frm.set_value('appointment_time', btn_selected.attr('data-name'));
|
frm.set_value('duration', duration);
|
||||||
frm.set_value('service_unit', btn_selected.attr('data-service-unit') || '');
|
frm.set_value('practitioner', d.get_value('practitioner'));
|
||||||
frm.set_value('duration', btn_selected.attr('data-duration'));
|
frm.set_value('department', d.get_value('department'));
|
||||||
|
frm.set_value('appointment_date', d.get_value('appointment_date'));
|
||||||
d.hide();
|
d.hide();
|
||||||
frm.enable_save();
|
frm.enable_save();
|
||||||
frm.save();
|
frm.save();
|
||||||
frm.enable_save();
|
frm.enable_save();
|
||||||
|
d.get_primary_btn().attr('disabled', true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
var $wrapper = d.fields_dict.available_slots.$wrapper;
|
|
||||||
|
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
|
// disable dialog action initially
|
||||||
d.get_primary_btn().attr('disabled', true);
|
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_details = data.slot_details;
|
||||||
var slot_html = "";
|
var slot_html = "";
|
||||||
var duration = frm.doc.duration | 0;
|
for (let i = 0; i < slot_details.length; i++) {
|
||||||
$.each(slot_details, function(i, slot_detail){
|
slot_html = slot_html + `<label>${slot_details[i].slot_name}</label>`;
|
||||||
slot_html = slot_html + `<label>${slot_detail['slot_name']}</label>`;
|
slot_html = slot_html + `<br/>` + slot_details[i].avail_slot.map(slot => {
|
||||||
slot_html = slot_html + `<br/>` + slot_detail['avail_slot'].map(slot => {
|
|
||||||
let disabled = '';
|
let disabled = '';
|
||||||
let start_str = slot.from_time;
|
let start_str = slot.from_time;
|
||||||
let slot_start_time = moment(slot.from_time, 'HH:mm:ss');
|
let slot_start_time = moment(slot.from_time, 'HH:mm:ss');
|
||||||
let slot_to_time = moment(slot.to_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;
|
let interval = (slot_to_time - slot_start_time)/60000 | 0;
|
||||||
// iterate in all booked appointments, update the start time and duration
|
// iterate in all booked appointments, update the start time and duration
|
||||||
slot_detail['appointments'].forEach(function(booked) {
|
slot_details[i].appointments.forEach(function(booked) {
|
||||||
let booked_moment = moment(booked.appointment_time, 'HH:mm:ss');
|
let booked_moment = moment(booked.appointment_time, 'HH:mm:ss');
|
||||||
let end_time = booked_moment.clone().add(booked.duration, 'minutes');
|
let end_time = booked_moment.clone().add(booked.duration, 'minutes');
|
||||||
// Deal with 0 duration appointments
|
// Deal with 0 duration appointments
|
||||||
@ -181,17 +245,16 @@ frappe.ui.form.on('Patient Appointment', {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return `<button class="btn btn-default"
|
return `<button class="btn btn-default"
|
||||||
data-name=${start_str}
|
data-name=${start_str}
|
||||||
data-duration=${duration || interval}
|
data-duration=${interval}
|
||||||
data-service-unit="${slot_detail['service_unit'] || ''}"
|
data-service-unit="${slot_details[i].service_unit || ''}"
|
||||||
style="margin: 0 10px 10px 0; width: 72px;" ${disabled}>
|
style="margin: 0 10px 10px 0; width: 72px;" ${disabled}>
|
||||||
${start_str.substring(0, start_str.length - 3)}
|
${start_str.substring(0, start_str.length - 3)}
|
||||||
</button>`;
|
</button>`;
|
||||||
}).join("");
|
}).join("");
|
||||||
slot_html = slot_html + `<br/>`;
|
slot_html = slot_html + `<br/>`;
|
||||||
});
|
}
|
||||||
|
|
||||||
$wrapper
|
$wrapper
|
||||||
.css('margin-bottom', 0)
|
.css('margin-bottom', 0)
|
||||||
@ -202,26 +265,27 @@ frappe.ui.form.on('Patient Appointment', {
|
|||||||
$wrapper.on('click', 'button', function() {
|
$wrapper.on('click', 'button', function() {
|
||||||
var $btn = $(this);
|
var $btn = $(this);
|
||||||
$wrapper.find('button').removeClass('btn-primary');
|
$wrapper.find('button').removeClass('btn-primary');
|
||||||
$wrapper.find('button').removeClass('btn-selected-slot');
|
|
||||||
$btn.addClass('btn-primary');
|
$btn.addClass('btn-primary');
|
||||||
$btn.addClass('btn-selected-slot');
|
selected_slot = $btn.attr('data-name');
|
||||||
|
service_unit = $btn.attr('data-service-unit');
|
||||||
|
duration = $btn.attr('data-duration');
|
||||||
// enable dialog action
|
// enable dialog action
|
||||||
d.get_primary_btn().attr('disabled', null);
|
d.get_primary_btn().attr('disabled', null);
|
||||||
});
|
});
|
||||||
|
|
||||||
d.show();
|
}else {
|
||||||
|
// fd.available_slots.html("Please select a valid date.".bold())
|
||||||
|
show_empty_state(d.get_value('practitioner'), d.get_value('appointment_date'));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onload:function(frm){
|
freeze: true,
|
||||||
if(frm.is_new()) {
|
freeze_message: __("Fetching records......")
|
||||||
frm.set_value("appointment_time", null);
|
|
||||||
frm.disable_save();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
get_procedure_from_encounter: function(frm) {
|
|
||||||
get_procedure_prescribed(frm);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
}else{
|
||||||
|
fd.available_slots.html("Appointment date and Healthcare Practitioner are Mandatory".bold());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
var get_procedure_prescribed = function(frm){
|
var get_procedure_prescribed = function(frm){
|
||||||
if(frm.doc.patient){
|
if(frm.doc.patient){
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
{
|
{
|
||||||
"allow_copy": 1,
|
"allow_copy": 1,
|
||||||
|
"allow_events_in_timeline": 0,
|
||||||
"allow_guest_to_view": 0,
|
"allow_guest_to_view": 0,
|
||||||
"allow_import": 1,
|
"allow_import": 1,
|
||||||
"allow_rename": 0,
|
"allow_rename": 0,
|
||||||
"autoname": "HLC-APP-.YYYY.-.#####",
|
"autoname": "OP-.######",
|
||||||
"beta": 1,
|
"beta": 1,
|
||||||
"creation": "2017-05-04 11:52:40.941507",
|
"creation": "2017-05-04 11:52:40.941507",
|
||||||
"custom": 0,
|
"custom": 0,
|
||||||
@ -88,19 +89,19 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"fieldname": "department",
|
"fieldname": "appointment_type",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
"ignore_user_permissions": 1,
|
"ignore_user_permissions": 1,
|
||||||
"ignore_xss_filter": 0,
|
"ignore_xss_filter": 0,
|
||||||
"in_filter": 0,
|
"in_filter": 0,
|
||||||
"in_global_search": 0,
|
"in_global_search": 0,
|
||||||
"in_list_view": 1,
|
"in_list_view": 0,
|
||||||
"in_standard_filter": 1,
|
"in_standard_filter": 0,
|
||||||
"label": "Department",
|
"label": "Appointment Type",
|
||||||
"length": 0,
|
"length": 0,
|
||||||
"no_copy": 0,
|
"no_copy": 0,
|
||||||
"options": "Medical Department",
|
"options": "Appointment Type",
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
"precision": "",
|
"precision": "",
|
||||||
"print_hide": 0,
|
"print_hide": 0,
|
||||||
@ -109,7 +110,7 @@
|
|||||||
"remember_last_selected_value": 0,
|
"remember_last_selected_value": 0,
|
||||||
"report_hide": 0,
|
"report_hide": 0,
|
||||||
"reqd": 0,
|
"reqd": 0,
|
||||||
"search_index": 1,
|
"search_index": 0,
|
||||||
"set_only_once": 1,
|
"set_only_once": 1,
|
||||||
"translatable": 0,
|
"translatable": 0,
|
||||||
"unique": 0
|
"unique": 0
|
||||||
@ -121,19 +122,19 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"fieldname": "practitioner",
|
"description": "In Minutes",
|
||||||
"fieldtype": "Link",
|
"fieldname": "duration",
|
||||||
|
"fieldtype": "Int",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
"ignore_user_permissions": 1,
|
"ignore_user_permissions": 0,
|
||||||
"ignore_xss_filter": 0,
|
"ignore_xss_filter": 0,
|
||||||
"in_filter": 0,
|
"in_filter": 1,
|
||||||
"in_global_search": 0,
|
"in_global_search": 0,
|
||||||
"in_list_view": 1,
|
"in_list_view": 0,
|
||||||
"in_standard_filter": 1,
|
"in_standard_filter": 0,
|
||||||
"label": "Healthcare Practitioner",
|
"label": "Duration",
|
||||||
"length": 0,
|
"length": 0,
|
||||||
"no_copy": 0,
|
"no_copy": 0,
|
||||||
"options": "Healthcare Practitioner",
|
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
"precision": "",
|
"precision": "",
|
||||||
"print_hide": 0,
|
"print_hide": 0,
|
||||||
@ -141,8 +142,109 @@
|
|||||||
"read_only": 0,
|
"read_only": 0,
|
||||||
"remember_last_selected_value": 0,
|
"remember_last_selected_value": 0,
|
||||||
"report_hide": 0,
|
"report_hide": 0,
|
||||||
"reqd": 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": "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,
|
||||||
|
"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,
|
"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,
|
"set_only_once": 1,
|
||||||
"translatable": 0,
|
"translatable": 0,
|
||||||
"unique": 0
|
"unique": 0
|
||||||
@ -219,7 +321,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"fieldname": "procedure_template",
|
"fieldname": "service_unit",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
"ignore_user_permissions": 0,
|
"ignore_user_permissions": 0,
|
||||||
@ -228,10 +330,10 @@
|
|||||||
"in_global_search": 0,
|
"in_global_search": 0,
|
||||||
"in_list_view": 0,
|
"in_list_view": 0,
|
||||||
"in_standard_filter": 0,
|
"in_standard_filter": 0,
|
||||||
"label": "Procedure",
|
"label": "Service Unit",
|
||||||
"length": 0,
|
"length": 0,
|
||||||
"no_copy": 0,
|
"no_copy": 0,
|
||||||
"options": "Clinical Procedure Template",
|
"options": "Healthcare Service Unit",
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
"precision": "",
|
"precision": "",
|
||||||
"print_hide": 0,
|
"print_hide": 0,
|
||||||
@ -245,103 +347,6 @@
|
|||||||
"translatable": 0,
|
"translatable": 0,
|
||||||
"unique": 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,
|
|
||||||
"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,
|
|
||||||
"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,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"allow_bulk_edit": 0,
|
||||||
"allow_in_quick_entry": 0,
|
"allow_in_quick_entry": 0,
|
||||||
@ -382,7 +387,104 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"fieldname": "column_break_1",
|
"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": "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,
|
||||||
|
"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,
|
||||||
|
"fieldname": "column_break_17",
|
||||||
"fieldtype": "Column Break",
|
"fieldtype": "Column Break",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
"ignore_user_permissions": 0,
|
"ignore_user_permissions": 0,
|
||||||
@ -391,10 +493,72 @@
|
|||||||
"in_global_search": 0,
|
"in_global_search": 0,
|
||||||
"in_list_view": 0,
|
"in_list_view": 0,
|
||||||
"in_standard_filter": 0,
|
"in_standard_filter": 0,
|
||||||
"label": "",
|
|
||||||
"length": 0,
|
"length": 0,
|
||||||
"no_copy": 0,
|
"no_copy": 0,
|
||||||
"options": "",
|
"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_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,
|
||||||
|
"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,
|
"permlevel": 0,
|
||||||
"precision": "",
|
"precision": "",
|
||||||
"print_hide": 0,
|
"print_hide": 0,
|
||||||
@ -415,8 +579,8 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"fieldname": "service_unit",
|
"fieldname": "section_break_16",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Section Break",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
"ignore_user_permissions": 0,
|
"ignore_user_permissions": 0,
|
||||||
"ignore_xss_filter": 0,
|
"ignore_xss_filter": 0,
|
||||||
@ -424,10 +588,8 @@
|
|||||||
"in_global_search": 0,
|
"in_global_search": 0,
|
||||||
"in_list_view": 0,
|
"in_list_view": 0,
|
||||||
"in_standard_filter": 0,
|
"in_standard_filter": 0,
|
||||||
"label": "Service Unit",
|
|
||||||
"length": 0,
|
"length": 0,
|
||||||
"no_copy": 0,
|
"no_copy": 0,
|
||||||
"options": "Healthcare Service Unit",
|
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
"precision": "",
|
"precision": "",
|
||||||
"print_hide": 0,
|
"print_hide": 0,
|
||||||
@ -437,7 +599,7 @@
|
|||||||
"report_hide": 0,
|
"report_hide": 0,
|
||||||
"reqd": 0,
|
"reqd": 0,
|
||||||
"search_index": 0,
|
"search_index": 0,
|
||||||
"set_only_once": 1,
|
"set_only_once": 0,
|
||||||
"translatable": 0,
|
"translatable": 0,
|
||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
@ -510,6 +672,37 @@
|
|||||||
"translatable": 0,
|
"translatable": 0,
|
||||||
"unique": 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_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_bulk_edit": 0,
|
||||||
"allow_in_quick_entry": 0,
|
"allow_in_quick_entry": 0,
|
||||||
@ -543,73 +736,6 @@
|
|||||||
"translatable": 0,
|
"translatable": 0,
|
||||||
"unique": 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,
|
|
||||||
"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,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"allow_bulk_edit": 0,
|
||||||
"allow_in_quick_entry": 0,
|
"allow_in_quick_entry": 0,
|
||||||
@ -978,7 +1104,7 @@
|
|||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"max_attachments": 0,
|
"max_attachments": 0,
|
||||||
"modified": "2018-09-13 10:15:45.704550",
|
"modified": "2018-11-14 13:24:01.529536",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Healthcare",
|
"module": "Healthcare",
|
||||||
"name": "Patient Appointment",
|
"name": "Patient Appointment",
|
||||||
|
@ -12,7 +12,7 @@ app_license = "GNU General Public License (v3)"
|
|||||||
source_link = "https://github.com/frappe/erpnext"
|
source_link = "https://github.com/frappe/erpnext"
|
||||||
|
|
||||||
develop_version = '12.x.x-develop'
|
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"
|
error_report_email = "support@erpnext.com"
|
||||||
|
|
||||||
|
@ -1 +0,0 @@
|
|||||||
from __future__ import unicode_literals
|
|
@ -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];
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
|
@ -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"
|
|
||||||
}
|
|
@ -39,8 +39,5 @@ frappe.query_reports["Production Analytics"] = {
|
|||||||
default: "Monthly",
|
default: "Monthly",
|
||||||
reqd: 1
|
reqd: 1
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
"formatter": function(value, row, column, data) {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -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_default_dispatch_notification_template
|
||||||
erpnext.patches.v11_0.add_market_segments
|
erpnext.patches.v11_0.add_market_segments
|
||||||
erpnext.patches.v11_0.add_sales_stages
|
erpnext.patches.v11_0.add_sales_stages
|
||||||
execute:frappe.delete_doc("Page", "sales-analytics")
|
execute:frappe.delete_doc_if_exists("Page", "sales-analytics")
|
||||||
execute:frappe.delete_doc("Page", "purchase-analytics")
|
execute:frappe.delete_doc_if_exists("Page", "purchase-analytics")
|
||||||
execute:frappe.delete_doc("Page", "stock-analytics")
|
execute:frappe.delete_doc_if_exists("Page", "stock-analytics")
|
||||||
execute:frappe.delete_doc("Page", "production-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.ewaybill_fields_gst_india #2018-11-13
|
||||||
erpnext.patches.v11_0.drop_column_max_days_allowed
|
erpnext.patches.v11_0.drop_column_max_days_allowed
|
||||||
erpnext.patches.v11_0.change_healthcare_desktop_icons
|
erpnext.patches.v11_0.change_healthcare_desktop_icons
|
||||||
|
@ -3,12 +3,18 @@ from frappe import _
|
|||||||
|
|
||||||
def execute():
|
def execute():
|
||||||
""" assign lft and rgt appropriately """
|
""" 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")
|
||||||
frappe.reload_doc("healthcare", "doctype", "healthcare_service_unit_type")
|
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({
|
frappe.get_doc({
|
||||||
'doctype': 'Healthcare Service Unit',
|
'doctype': 'Healthcare Service Unit',
|
||||||
'healthcare_service_unit_name': _('All Healthcare Service Units'),
|
'healthcare_service_unit_name': _('All Healthcare Service Units'),
|
||||||
'is_group': 1
|
'is_group': 1,
|
||||||
|
'company': company
|
||||||
}).insert(ignore_permissions=True)
|
}).insert(ignore_permissions=True)
|
||||||
|
|
||||||
|
@ -103,12 +103,32 @@ $.extend(erpnext, {
|
|||||||
$.extend(erpnext.utils, {
|
$.extend(erpnext.utils, {
|
||||||
set_party_dashboard_indicators: function(frm) {
|
set_party_dashboard_indicators: function(frm) {
|
||||||
if(frm.doc.__onload && frm.doc.__onload.dashboard_info) {
|
if(frm.doc.__onload && frm.doc.__onload.dashboard_info) {
|
||||||
var info = frm.doc.__onload.dashboard_info;
|
var company_wise_info = frm.doc.__onload.dashboard_info;
|
||||||
frm.dashboard.add_indicator(__('Annual Billing: {0}',
|
if(company_wise_info.length > 1) {
|
||||||
[format_currency(info.billing_this_year, info.currency)]), 'blue');
|
frm.dashboard.stats_area.removeClass('hidden');
|
||||||
frm.dashboard.add_indicator(__('Total Unpaid: {0}',
|
frm.dashboard.stats_area_row.addClass('flex');
|
||||||
[format_currency(info.total_unpaid, info.currency)]),
|
frm.dashboard.stats_area_row.css('flex-wrap', 'wrap');
|
||||||
info.total_unpaid ? 'orange' : 'green');
|
company_wise_info.forEach(function(info) {
|
||||||
|
frm.dashboard.stats_area_row.append(
|
||||||
|
'<div class="flex-column col-xs-6">'+
|
||||||
|
'<div style="margin-bottom:20px"><h6>'+info.company+'</h6></div>'+
|
||||||
|
'<div class="badge-link small" style="margin-bottom:10px">Annual Billing: '
|
||||||
|
+format_currency(info.billing_this_year, info.currency)+'</div>'+
|
||||||
|
'<div class="badge-link small" style="margin-bottom:20px">Total Unpaid: '
|
||||||
|
+format_currency(info.total_unpaid, info.currency)+'</div>'+
|
||||||
|
'</div>'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
frm.dashboard.stats_area.removeClass('hidden');
|
||||||
|
frm.dashboard.stats_area_row.append(
|
||||||
|
'</div><div class="col-xs-6 small" style="margin-bottom:10px">Annual Billing: <b>'
|
||||||
|
+format_currency(company_wise_info[0].billing_this_year, company_wise_info[0].currency)+'</b></div>' +
|
||||||
|
'<div class="col-xs-6 small" style="margin-bottom:10px">Total Unpaid: <b>'
|
||||||
|
+format_currency(company_wise_info[0].billing_this_year, company_wise_info[0].currency)+'</b></div>'
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -320,7 +320,7 @@ frappe.ui.form.ItemQuickEntryForm = frappe.ui.form.QuickEntryForm.extend({
|
|||||||
["attribute_value", "like", e.target.value + "%"]
|
["attribute_value", "like", e.target.value + "%"]
|
||||||
],
|
],
|
||||||
fields: ["attribute_value"],
|
fields: ["attribute_value"],
|
||||||
parent: "Item"
|
parent: "Item Attribute"
|
||||||
},
|
},
|
||||||
callback: function(r) {
|
callback: function(r) {
|
||||||
if (r.message) {
|
if (r.message) {
|
||||||
|
@ -1 +0,0 @@
|
|||||||
Trends of sales by Item, Item Group, Customer etc.
|
|
@ -1 +0,0 @@
|
|||||||
from __future__ import unicode_literals
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
@ -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"
|
|
||||||
}
|
|
@ -67,6 +67,9 @@ frappe.query_reports["Sales Analytics"] = {
|
|||||||
reqd: 1
|
reqd: 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
after_datatable_render: function(datatable_obj) {
|
||||||
|
$(datatable_obj.wrapper).find(".dt-row-0").find('input[type=checkbox]').click();
|
||||||
|
},
|
||||||
get_datatable_options(options) {
|
get_datatable_options(options) {
|
||||||
return Object.assign(options, {
|
return Object.assign(options, {
|
||||||
checkboxColumn: true,
|
checkboxColumn: true,
|
||||||
@ -106,12 +109,12 @@ frappe.query_reports["Sales Analytics"] = {
|
|||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
frappe.query_report.chart.update(new_data)
|
frappe.query_report.chart.update(new_data)
|
||||||
},200)
|
}, 500)
|
||||||
|
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
frappe.query_report.chart.draw(true);
|
frappe.query_report.chart.draw(true);
|
||||||
}, 800)
|
}, 1000)
|
||||||
|
|
||||||
frappe.query_report.raw_chart_data = new_data;
|
frappe.query_report.raw_chart_data = new_data;
|
||||||
},
|
},
|
||||||
|
@ -212,11 +212,11 @@ class Analytics(object):
|
|||||||
|
|
||||||
def get_period(self, posting_date):
|
def get_period(self, posting_date):
|
||||||
if self.filters.range == 'Weekly':
|
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':
|
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':
|
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:
|
else:
|
||||||
year = get_fiscal_year(posting_date, company=self.filters.company)
|
year = get_fiscal_year(posting_date, company=self.filters.company)
|
||||||
period = str(year[2])
|
period = str(year[2])
|
||||||
@ -280,8 +280,7 @@ class Analytics(object):
|
|||||||
self.chart = {
|
self.chart = {
|
||||||
"data": {
|
"data": {
|
||||||
'labels': labels,
|
'labels': labels,
|
||||||
'datasets':[
|
'datasets':[]
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"type": "line"
|
"type": "line"
|
||||||
}
|
}
|
@ -35,52 +35,52 @@ class TestAnalytics(unittest.TestCase):
|
|||||||
{
|
{
|
||||||
"entity": "_Test Customer 1",
|
"entity": "_Test Customer 1",
|
||||||
"entity_name": "_Test Customer 1",
|
"entity_name": "_Test Customer 1",
|
||||||
"apr": 0.0,
|
"apr_2017": 0.0,
|
||||||
"may": 0.0,
|
"may_2017": 0.0,
|
||||||
"jun": 0.0,
|
"jun_2017": 0.0,
|
||||||
"jul": 0.0,
|
"jul_2017": 0.0,
|
||||||
"aug": 0.0,
|
"aug_2017": 0.0,
|
||||||
"sep": 0.0,
|
"oct_2017": 0.0,
|
||||||
"oct": 0.0,
|
"sep_2017": 0.0,
|
||||||
"nov": 0.0,
|
"nov_2017": 0.0,
|
||||||
"dec": 0.0,
|
"dec_2017": 0.0,
|
||||||
"jan": 0.0,
|
"jan_2018": 0.0,
|
||||||
"feb": 2000.0,
|
"feb_2018": 2000.0,
|
||||||
"mar": 0.0,
|
"mar_2018": 0.0,
|
||||||
"total":2000.0
|
"total":2000.0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"entity": "_Test Customer 2",
|
"entity": "_Test Customer 2",
|
||||||
"entity_name": "_Test Customer 2",
|
"entity_name": "_Test Customer 2",
|
||||||
"apr": 0.0,
|
"apr_2017": 0.0,
|
||||||
"may": 0.0,
|
"may_2017": 0.0,
|
||||||
"jun": 0.0,
|
"jun_2017": 0.0,
|
||||||
"jul": 0.0,
|
"jul_2017": 0.0,
|
||||||
"aug": 0.0,
|
"aug_2017": 0.0,
|
||||||
"sep": 1500.0,
|
"sep_2017": 1500.0,
|
||||||
"oct": 1000.0,
|
"oct_2017": 1000.0,
|
||||||
"nov": 0.0,
|
"nov_2017": 0.0,
|
||||||
"dec": 0.0,
|
"dec_2017": 0.0,
|
||||||
"jan": 0.0,
|
"jan_2018": 0.0,
|
||||||
"feb": 0.0,
|
"feb_2018": 0.0,
|
||||||
"mar": 0.0,
|
"mar_2018": 0.0,
|
||||||
"total":2500.0
|
"total":2500.0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"entity": "_Test Customer 3",
|
"entity": "_Test Customer 3",
|
||||||
"entity_name": "_Test Customer 3",
|
"entity_name": "_Test Customer 3",
|
||||||
"apr": 0.0,
|
"apr_2017": 0.0,
|
||||||
"may": 0.0,
|
"may_2017": 0.0,
|
||||||
"jun": 2000.0,
|
"jun_2017": 2000.0,
|
||||||
"jul": 1000.0,
|
"jul_2017": 1000.0,
|
||||||
"aug": 0.0,
|
"aug_2017": 0.0,
|
||||||
"sep": 0.0,
|
"sep_2017": 0.0,
|
||||||
"oct": 0.0,
|
"oct_2017": 0.0,
|
||||||
"nov": 0.0,
|
"nov_2017": 0.0,
|
||||||
"dec": 0.0,
|
"dec_2017": 0.0,
|
||||||
"jan": 0.0,
|
"jan_2018": 0.0,
|
||||||
"feb": 0.0,
|
"feb_2018": 0.0,
|
||||||
"mar": 0.0,
|
"mar_2018": 0.0,
|
||||||
"total": 3000.0
|
"total": 3000.0
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -103,18 +103,18 @@ class TestAnalytics(unittest.TestCase):
|
|||||||
expected_first_row = {
|
expected_first_row = {
|
||||||
"entity": "All Customer Groups",
|
"entity": "All Customer Groups",
|
||||||
"indent": 0,
|
"indent": 0,
|
||||||
"apr": 0.0,
|
"apr_2017": 0.0,
|
||||||
"may": 0.0,
|
"may_2017": 0.0,
|
||||||
"jun": 2000.0,
|
"jun_2017": 2000.0,
|
||||||
"jul": 1000.0,
|
"jul_2017": 1000.0,
|
||||||
"aug": 0.0,
|
"aug_2017": 0.0,
|
||||||
"sep": 1500.0,
|
"sep_2017": 1500.0,
|
||||||
"oct": 1000.0,
|
"oct_2017": 1000.0,
|
||||||
"nov": 0.0,
|
"nov_2017": 0.0,
|
||||||
"dec": 0.0,
|
"dec_2017": 0.0,
|
||||||
"jan": 0.0,
|
"jan_2018": 0.0,
|
||||||
"feb": 2000.0,
|
"feb_2018": 2000.0,
|
||||||
"mar": 0.0,
|
"mar_2018": 0.0,
|
||||||
"total":7500.0
|
"total":7500.0
|
||||||
}
|
}
|
||||||
self.assertEqual(expected_first_row, report[1][0])
|
self.assertEqual(expected_first_row, report[1][0])
|
||||||
@ -136,52 +136,52 @@ class TestAnalytics(unittest.TestCase):
|
|||||||
{
|
{
|
||||||
"entity": "_Test Customer 1",
|
"entity": "_Test Customer 1",
|
||||||
"entity_name": "_Test Customer 1",
|
"entity_name": "_Test Customer 1",
|
||||||
"apr": 0.0,
|
"apr_2017": 0.0,
|
||||||
"may": 0.0,
|
"may_2017": 0.0,
|
||||||
"jun": 0.0,
|
"jun_2017": 0.0,
|
||||||
"jul": 0.0,
|
"jul_2017": 0.0,
|
||||||
"aug": 0.0,
|
"aug_2017": 0.0,
|
||||||
"sep": 0.0,
|
"sep_2017": 0.0,
|
||||||
"oct": 0.0,
|
"oct_2017": 0.0,
|
||||||
"nov": 0.0,
|
"nov_2017": 0.0,
|
||||||
"dec": 0.0,
|
"dec_2017": 0.0,
|
||||||
"jan": 0.0,
|
"jan_2018": 0.0,
|
||||||
"feb": 20.0,
|
"feb_2018": 20.0,
|
||||||
"mar": 0.0,
|
"mar_2018": 0.0,
|
||||||
"total":20.0
|
"total":20.0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"entity": "_Test Customer 2",
|
"entity": "_Test Customer 2",
|
||||||
"entity_name": "_Test Customer 2",
|
"entity_name": "_Test Customer 2",
|
||||||
"apr": 0.0,
|
"apr_2017": 0.0,
|
||||||
"may": 0.0,
|
"may_2017": 0.0,
|
||||||
"jun": 0.0,
|
"jun_2017": 0.0,
|
||||||
"jul": 0.0,
|
"jul_2017": 0.0,
|
||||||
"aug": 0.0,
|
"aug_2017": 0.0,
|
||||||
"sep": 15.0,
|
"sep_2017": 15.0,
|
||||||
"oct": 10.0,
|
"oct_2017": 10.0,
|
||||||
"nov": 0.0,
|
"nov_2017": 0.0,
|
||||||
"dec": 0.0,
|
"dec_2017": 0.0,
|
||||||
"jan": 0.0,
|
"jan_2018": 0.0,
|
||||||
"feb": 0.0,
|
"feb_2018": 0.0,
|
||||||
"mar": 0.0,
|
"mar_2018": 0.0,
|
||||||
"total":25.0
|
"total":25.0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"entity": "_Test Customer 3",
|
"entity": "_Test Customer 3",
|
||||||
"entity_name": "_Test Customer 3",
|
"entity_name": "_Test Customer 3",
|
||||||
"apr": 0.0,
|
"apr_2017": 0.0,
|
||||||
"may": 0.0,
|
"may_2017": 0.0,
|
||||||
"jun": 20.0,
|
"jun_2017": 20.0,
|
||||||
"jul": 10.0,
|
"jul_2017": 10.0,
|
||||||
"aug": 0.0,
|
"aug_2017": 0.0,
|
||||||
"sep": 0.0,
|
"sep_2017": 0.0,
|
||||||
"oct": 0.0,
|
"oct_2017": 0.0,
|
||||||
"nov": 0.0,
|
"nov_2017": 0.0,
|
||||||
"dec": 0.0,
|
"dec_2017": 0.0,
|
||||||
"jan": 0.0,
|
"jan_2018": 0.0,
|
||||||
"feb": 0.0,
|
"feb_2018": 0.0,
|
||||||
"mar": 0.0,
|
"mar_2018": 0.0,
|
||||||
"total": 30.0
|
"total": 30.0
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -519,7 +519,7 @@ $.extend(erpnext.item, {
|
|||||||
fields: ["attribute_value"],
|
fields: ["attribute_value"],
|
||||||
limit_start: 0,
|
limit_start: 0,
|
||||||
limit_page_length: 500,
|
limit_page_length: 500,
|
||||||
parent: "Item",
|
parent: "Item Attribute",
|
||||||
order_by: "idx"
|
order_by: "idx"
|
||||||
}
|
}
|
||||||
}).then((r) => {
|
}).then((r) => {
|
||||||
@ -657,7 +657,7 @@ $.extend(erpnext.item, {
|
|||||||
frappe.call({
|
frappe.call({
|
||||||
method:"erpnext.stock.doctype.item.item.get_item_attribute",
|
method:"erpnext.stock.doctype.item.item.get_item_attribute",
|
||||||
args:{
|
args:{
|
||||||
parent: i,
|
parent: "Item Attribute",
|
||||||
attribute_value: term
|
attribute_value: term
|
||||||
},
|
},
|
||||||
callback: function(r) {
|
callback: function(r) {
|
||||||
|
@ -32,6 +32,10 @@ class StockExistsForTemplate(frappe.ValidationError):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class InvalidBarcode(frappe.ValidationError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class Item(WebsiteGenerator):
|
class Item(WebsiteGenerator):
|
||||||
website = frappe._dict(
|
website = frappe._dict(
|
||||||
page_title_field="item_name",
|
page_title_field="item_name",
|
||||||
@ -511,19 +515,19 @@ class Item(WebsiteGenerator):
|
|||||||
from stdnum import ean
|
from stdnum import ean
|
||||||
if len(self.barcodes) > 0:
|
if len(self.barcodes) > 0:
|
||||||
for item_barcode in self.barcodes:
|
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:
|
if item_barcode.barcode:
|
||||||
duplicate = frappe.db.sql(
|
duplicate = frappe.db.sql(
|
||||||
"""select parent from `tabItem Barcode` where barcode = %s and parent != %s""", (item_barcode.barcode, self.name))
|
"""select parent from `tabItem Barcode` where barcode = %s and parent != %s""", (item_barcode.barcode, self.name))
|
||||||
if duplicate:
|
if duplicate:
|
||||||
frappe.throw(_("Barcode {0} already used in Item {1}").format(
|
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
|
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):
|
if not ean.is_valid(item_barcode.barcode):
|
||||||
frappe.throw(_("Barcode {0} is not a valid {1} code").format(
|
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):
|
def validate_warehouse_for_reorder(self):
|
||||||
'''Validate Reorder level table for duplicate and conditional mandatory'''
|
'''Validate Reorder level table for duplicate and conditional mandatory'''
|
||||||
|
@ -8,7 +8,7 @@ import frappe
|
|||||||
from frappe.test_runner import make_test_objects
|
from frappe.test_runner import make_test_objects
|
||||||
from erpnext.controllers.item_variant import (create_variant, ItemVariantExistsError,
|
from erpnext.controllers.item_variant import (create_variant, ItemVariantExistsError,
|
||||||
InvalidItemAttributeValueError, get_variant)
|
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 erpnext.stock.doctype.item.item import get_uom_conv_factor
|
||||||
from frappe.model.rename_doc import rename_doc
|
from frappe.model.rename_doc import rename_doc
|
||||||
from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
|
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
|
item_doc.has_variants = 1
|
||||||
self.assertRaises(StockExistsForTemplate, item_doc.save)
|
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):
|
def set_item_variant_settings(fields):
|
||||||
doc = frappe.get_doc('Item Variant Settings')
|
doc = frappe.get_doc('Item Variant Settings')
|
||||||
doc.set('fields', fields)
|
doc.set('fields', fields)
|
||||||
|
@ -181,7 +181,7 @@ class StockReconciliation(StockController):
|
|||||||
frappe.throw(_("Valuation Rate required for Item in row {0}").format(row.idx))
|
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")
|
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)):
|
or (not previous_sle and not row.qty)):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
@ -1 +0,0 @@
|
|||||||
Trends of Items quantities and values.
|
|
@ -1 +0,0 @@
|
|||||||
from __future__ import unicode_literals
|
|
@ -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")
|
|
||||||
});
|
|
||||||
};
|
|
@ -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"
|
|
||||||
}
|
|
@ -71,16 +71,8 @@ frappe.query_reports["Stock Analytics"] = {
|
|||||||
reqd: 1
|
reqd: 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"formatter": function(value, row, column, data) {
|
after_datatable_render: function(datatable_obj) {
|
||||||
if(!value && (column.fieldname == 'brand' || column.fieldname == 'uom')){
|
$(datatable_obj.wrapper).find(".dt-row-0").find('input[type=checkbox]').click();
|
||||||
value = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
if(Number(value)){
|
|
||||||
value = value.toFixed(2)
|
|
||||||
}
|
|
||||||
|
|
||||||
return value;
|
|
||||||
},
|
},
|
||||||
get_datatable_options(options) {
|
get_datatable_options(options) {
|
||||||
return Object.assign(options, {
|
return Object.assign(options, {
|
||||||
@ -120,16 +112,16 @@ frappe.query_reports["Stock Analytics"] = {
|
|||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
frappe.query_report.chart.update(new_data)
|
frappe.query_report.chart.update(new_data)
|
||||||
},200)
|
},500)
|
||||||
|
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
frappe.query_report.chart.draw(true);
|
frappe.query_report.chart.draw(true);
|
||||||
}, 800)
|
}, 1000)
|
||||||
|
|
||||||
frappe.query_report.raw_chart_data = new_data;
|
frappe.query_report.raw_chart_data = new_data;
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
|
@ -99,11 +99,11 @@ def get_period(posting_date, filters):
|
|||||||
months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
|
months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
|
||||||
|
|
||||||
if filters.range == 'Weekly':
|
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':
|
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':
|
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:
|
else:
|
||||||
year = get_fiscal_year(posting_date, company=filters.company)
|
year = get_fiscal_year(posting_date, company=filters.company)
|
||||||
period = str(year[2])
|
period = str(year[2])
|
||||||
|
@ -178,7 +178,7 @@ class update_entries_after(object):
|
|||||||
# rounding as per precision
|
# rounding as per precision
|
||||||
self.stock_value = flt(self.stock_value, self.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
|
stock_value_difference = sle.actual_qty * self.valuation_rate
|
||||||
else:
|
else:
|
||||||
stock_value_difference = self.stock_value - self.prev_stock_value
|
stock_value_difference = self.stock_value - self.prev_stock_value
|
||||||
|
Loading…
Reference in New Issue
Block a user