fix master data sync performance issue
diff --git a/erpnext/accounts/doctype/sales_invoice/pos.py b/erpnext/accounts/doctype/sales_invoice/pos.py
index 11c68a3..e5c86dc 100644
--- a/erpnext/accounts/doctype/sales_invoice/pos.py
+++ b/erpnext/accounts/doctype/sales_invoice/pos.py
@@ -30,10 +30,16 @@
return {
'doc': doc,
'default_customer': pos_profile.get('customer'),
- 'items': get_items(doc, pos_profile),
+ 'items': get_items_list(pos_profile),
'customers': get_customers_list(pos_profile),
- 'pricing_rules': get_pricing_rules(doc),
+ 'serial_no_data': get_serial_no_data(pos_profile, doc.company),
+ 'batch_no_data': get_batch_no_data(),
+ 'tax_data': get_item_tax_data(),
+ 'price_list_data': get_price_list_data(doc.selling_price_list),
+ 'bin_data': get_bin_data(pos_profile),
+ 'pricing_rules': get_pricing_rule_data(doc),
'print_template': print_template,
+ 'pos_profile': pos_profile,
'meta': {
'invoice': frappe.get_meta('Sales Invoice'),
'items': frappe.get_meta('Sales Invoice Item'),
@@ -104,31 +110,6 @@
for tax in taxes:
doc.append('taxes', tax)
-def get_items(doc, pos_profile):
- item_list = []
- for item in get_items_list(pos_profile):
- item_doc = frappe.get_doc('Item', item.name)
- if item_doc.taxes:
- item.taxes = json.dumps(dict(([d.tax_type, d.tax_rate] for d in
- item_doc.get("taxes"))))
-
- item.price_list_rate = frappe.db.get_value('Item Price', {'item_code': item.name,
- 'price_list': doc.selling_price_list}, 'price_list_rate') or 0
- item.default_warehouse = pos_profile.get('warehouse') or \
- get_item_warehouse_for_company(doc.company, item.default_warehouse) or None
- item.expense_account = pos_profile.get('expense_account') or item.expense_account
- item.income_account = pos_profile.get('income_account') or item_doc.income_account
- item.cost_center = pos_profile.get('cost_center') or item_doc.selling_cost_center
- item.actual_qty = frappe.db.get_value('Bin', {'item_code': item.name,
- 'warehouse': item.default_warehouse}, 'actual_qty') or 0
- item.serial_nos = get_serial_nos(item, pos_profile, doc.company)
- item.batch_nos = frappe.db.sql_list("""select name from `tabBatch` where ifnull(expiry_date, '4000-10-10') > curdate()
- and item = %(item_code)s""", {'item_code': item.item_code})
-
- item_list.append(item)
-
- return item_list
-
def get_items_list(pos_profile):
cond = "1=1"
item_groups = []
@@ -138,8 +119,15 @@
cond = "item_group in (%s)"%(', '.join(['%s']*len(pos_profile.get('item_groups'))))
item_groups = [d.item_group for d in pos_profile.get('item_groups')]
- return frappe.db.sql(""" select * from tabItem where disabled = 0 and has_variants = 0
- and is_sales_item = 1 and {cond}""".format(cond=cond), tuple(item_groups), as_dict=1) or []
+ return frappe.db.sql("""
+ select
+ name, item_code, item_name, description, item_group, expense_account, has_batch_no,
+ has_serial_no, expense_account, selling_cost_center, stock_uom, image, default_warehouse
+ from
+ tabItem
+ where
+ disabled = 0 and has_variants = 0 and is_sales_item = 1 and {cond}
+ """.format(cond=cond), tuple(item_groups), as_dict=1)
def get_customers_list(pos_profile):
cond = "1=1"
@@ -150,30 +138,88 @@
cond = "customer_group in (%s)"%(', '.join(['%s']*len(pos_profile.get('customer_groups'))))
customer_groups = [d.customer_group for d in pos_profile.get('customer_groups')]
- return frappe.db.sql(""" select * from tabCustomer where disabled = 0
+ return frappe.db.sql(""" select name, customer_name, customer_group,
+ territory from tabCustomer where disabled = 0
and {cond}""".format(cond=cond), tuple(customer_groups), as_dict=1) or {}
-def get_item_warehouse_for_company(company, warehouse):
- if frappe.db.get_value('Warehouse', warehouse, 'company') != company:
- warehouse = None
- return warehouse
+def get_serial_no_data(pos_profile, company):
+ # get itemwise serial no data
+ # example {'Nokia Lumia 1020': {'SN0001': 'Pune'}}
+ # where Nokia Lumia 1020 is item code, SN0001 is serial no and Pune is warehouse
-def get_serial_nos(item, pos_profile, company):
cond = "1=1"
if pos_profile.get('update_stock') and pos_profile.get('warehouse'):
cond = "warehouse = '{0}'".format(pos_profile.get('warehouse'))
- serial_nos = frappe.db.sql("""select name, warehouse from `tabSerial No` where {0}
- and item_code = %(item_code)s and company = %(company)s
- """.format(cond), {'item_code': item.item_code, 'company': company}, as_dict=1)
+ serial_nos = frappe.db.sql("""select name, warehouse, item_code from `tabSerial No` where {0}
+ and company = %(company)s """.format(cond), {'company': company}, as_dict=1)
- serial_no_list = {}
- for serial_no in serial_nos:
- serial_no_list[serial_no.name] = serial_no.warehouse
+ itemwise_serial_no = {}
+ for sn in serial_nos:
+ if sn.item_code not in itemwise_serial_no:
+ itemwise_serial_no.setdefault(sn.item_code, {})
+ itemwise_serial_no[sn.item_code][sn.name] = sn.warehouse
- return serial_no_list
+ return itemwise_serial_no
-def get_pricing_rules(doc):
+def get_batch_no_data():
+ # get itemwise batch no data
+ # exmaple: {'LED-GRE': [Batch001, Batch002]}
+ # where LED-GRE is item code, SN0001 is serial no and Pune is warehouse
+
+ itemwise_batch = {}
+ batches = frappe.db.sql("""select name, item from `tabBatch`
+ where ifnull(expiry_date, '4000-10-10') >= curdate()""", as_dict=1)
+
+ for batch in batches:
+ if batch.item not in itemwise_batch:
+ itemwise_batch.setdefault(batch.item, [])
+ itemwise_batch[batch.item].append(batch.name)
+
+ return itemwise_batch
+
+def get_item_tax_data():
+ # get default tax of an item
+ # example: {'Consulting Services': {'Excise 12 - TS': '12.000'}}
+
+ itemwise_tax = {}
+ taxes = frappe.db.sql(""" select parent, tax_type, tax_rate from `tabItem Tax`""", as_dict=1)
+
+ for tax in taxes:
+ if tax.parent not in itemwise_tax:
+ itemwise_tax.setdefault(tax.parent, {})
+ itemwise_tax[tax.parent][tax.tax_type] = tax.tax_rate
+
+ return itemwise_tax
+
+def get_price_list_data(selling_price_list):
+ itemwise_price_list = {}
+ price_lists = frappe.db.sql("""Select ifnull(price_list_rate, 0) as price_list_rate,
+ item_code from `tabItem Price` ip where price_list = %(price_list)s""",
+ {'price_list': selling_price_list}, as_dict=1)
+
+ for item in price_lists:
+ itemwise_price_list[item.item_code] = item.price_list_rate
+
+ return itemwise_price_list
+
+def get_bin_data(pos_profile):
+ itemwise_bin_data = {}
+ cond = "1=1"
+ if pos_profile.get('warehouse'):
+ cond = "warehouse = '{0}'".format(pos_profile.get('warehouse'))
+
+ bin_data = frappe.db.sql(""" select item_code, warehouse, actual_qty from `tabBin`
+ where actual_qty > 0 and {cond}""".format(cond=cond), as_dict=1)
+
+ for bins in bin_data:
+ if bins.item_code not in itemwise_bin_data:
+ itemwise_bin_data.setdefault(bins.item_code, {})
+ itemwise_bin_data[bins.item_code][bins.warehouse] = bins.actual_qty
+
+ return itemwise_bin_data
+
+def get_pricing_rule_data(doc):
pricing_rules = ""
if doc.ignore_pricing_rule == 0:
pricing_rules = frappe.db.sql(""" Select * from `tabPricing Rule` where docstatus < 2
diff --git a/erpnext/accounts/page/pos/pos.js b/erpnext/accounts/page/pos/pos.js
index cfc9582..26bf3ea 100644
--- a/erpnext/accounts/page/pos/pos.js
+++ b/erpnext/accounts/page/pos/pos.js
@@ -25,7 +25,6 @@
this.set_indicator();
this.onload();
this.make_menu_list();
- this.set_interval_for_si_sync();
this.si_docs = this.get_doc_from_localstorage();
},
@@ -73,8 +72,6 @@
this.get_data_from_server(function(){
me.create_new();
});
-
- this.check_internet_connection();
},
make_menu_list: function(){
@@ -204,13 +201,10 @@
freeze: true,
freeze_message: __("Master data syncing, it might take some time"),
callback: function(r){
- window.items = r.message.items;
- window.customers = r.message.customers;
- window.pricing_rules = r.message.pricing_rules;
- window.meta = r.message.meta;
- window.print_template = r.message.print_template;
- me.default_customer = r.message.default_customer || null;
+ me.init_master_data(r)
localStorage.setItem('doc', JSON.stringify(r.message.doc));
+ me.set_interval_for_si_sync();
+ me.check_internet_connection();
if(callback){
callback();
}
@@ -218,6 +212,22 @@
})
},
+ init_master_data: function(r){
+ var me = this;
+ this.meta = r.message.meta;
+ this.item_data = r.message.items;
+ this.customers = r.message.customers;
+ this.serial_no_data = r.message.serial_no_data;
+ this.batch_no_data = r.message.batch_no_data;
+ this.tax_data = r.message.tax_data;
+ this.price_list_data = r.message.price_list_data;
+ this.bin_data = r.message.bin_data;
+ this.pricing_rules = r.message.pricing_rules;
+ this.print_template = r.message.print_template;
+ this.pos_profile_data = r.message.pos_profile;
+ this.default_customer = r.message.default_customer || null;
+ },
+
save_previous_entry : function(){
if(this.frm.doc.items.length > 0){
this.create_invoice()
@@ -233,20 +243,19 @@
},
load_data: function(load_doc){
- this.items = window.items;
- this.customers = window.customers;
- this.pricing_rules = window.pricing_rules;
+ var me = this;
+ this.items = this.item_data;
if(load_doc) {
this.frm.doc = JSON.parse(localStorage.getItem('doc'));
}
- $.each(window.meta, function(i, data){
+ $.each(this.meta, function(i, data){
frappe.meta.sync(data)
})
this.print_template = frappe.render_template("print_template",
- {content: window.print_template, title:"POS",
+ {content: this.print_template, title:"POS",
base_url: frappe.urllib.get_base_url(), print_css: frappe.boot.print_css})
},
@@ -392,7 +401,7 @@
if(index < 30){
$(frappe.render_template("pos_item", {
item_code: obj.name,
- item_price: format_currency(obj.price_list_rate, me.frm.doc.currency),
+ item_price: format_currency(me.price_list_data[obj.name], me.frm.doc.currency),
item_name: obj.name===obj.item_name ? "" : obj.item_name,
item_image: obj.image ? "url('" + obj.image + "')" : null,
color: frappe.get_palette(obj.item_name),
@@ -428,7 +437,7 @@
this.item_batch_no = {};
if(item_code){
- return $.grep(window.items, function(item){
+ return $.grep(this.item_data, function(item){
if(item.item_code == item_code ){
return true
}
@@ -441,14 +450,15 @@
search_status = true
if(key){
- return $.grep(window.items, function(item){
+ return $.grep(this.item_data, function(item){
if(search_status){
- if(in_list(item.batch_nos, me.search.$input.val())){
+ if(in_list(me.batch_no_data[item.item_code], me.search.$input.val())){
search_status = false;
return me.item_batch_no[item.item_code] = me.search.$input.val()
- } else if(in_list(Object.keys(item.serial_nos), me.search.$input.val())) {
+ } else if( me.serial_no_data[item.item_code]
+ && in_list(Object.keys(me.serial_no_data[item.item_code]), me.search.$input.val())) {
search_status = false;
- me.item_serial_no[item.item_code] = [me.search.$input.val(), item.serial_nos[me.search.$input.val()]]
+ me.item_serial_no[item.item_code] = [me.search.$input.val(), me.serial_no_data[item.item_code][me.search.$input.val()]]
return true
} else if(item.barcode == me.search.$input.val()) {
search_status = false;
@@ -460,7 +470,7 @@
}
})
}else{
- return window.items;
+ return this.item_data;
}
},
@@ -613,18 +623,18 @@
this.child.description = this.items[0].description;
this.child.qty = 1;
this.child.item_group = this.items[0].item_group;
- this.child.cost_center = this.items[0].cost_center;
- this.child.income_account = this.items[0].income_account;
+ this.child.cost_center = this.pos_profile_data['cost_center'] || this.items[0].cost_center;
+ this.child.income_account = this.pos_profile_data['income_account'] || this.items[0].income_account;
this.child.warehouse = (this.item_serial_no[this.child.item_code]
- ? this.item_serial_no[this.child.item_code][1] : this.items[0].default_warehouse);
- this.child.price_list_rate = flt(this.items[0].price_list_rate, 9) / flt(this.frm.doc.conversion_rate, 9);
- this.child.rate = flt(this.items[0].price_list_rate, 9) / flt(this.frm.doc.conversion_rate, 9);
- this.child.actual_qty = this.items[0].actual_qty;
+ ? this.item_serial_no[this.child.item_code][1] : (this.pos_profile_data['warehouse'] || this.items[0].default_warehouse) );
+ this.child.price_list_rate = flt(this.price_list_data[this.child.item_code], 9) / flt(this.frm.doc.conversion_rate, 9);
+ this.child.rate = flt(this.price_list_data[this.child.item_code], 9) / flt(this.frm.doc.conversion_rate, 9);
+ this.child.actual_qty = me.get_actual_qty(this.items[0]);
this.child.amount = flt(this.child.qty) * flt(this.child.rate);
this.child.batch_no = this.item_batch_no[this.child.item_code];
this.child.serial_no = (this.item_serial_no[this.child.item_code]
? this.item_serial_no[this.child.item_code][0] : '');
- this.child.item_tax_rate = this.items[0].taxes;
+ this.child.item_tax_rate = JSON.stringify(this.tax_data[this.child.item_code]);
},
update_paid_amount_status: function(update_paid_amount){
@@ -670,7 +680,7 @@
item_code: d.item_code,
item_name: (d.item_name===d.item_code || !d.item_name) ? "" : ("<br>" + d.item_name),
qty: d.qty,
- actual_qty: d.actual_qty,
+ actual_qty: me.actual_qty,
projected_qty: d.projected_qty,
rate: format_number(d.rate, me.frm.doc.currency),
amount: format_currency(d.amount, me.frm.doc.currency)
@@ -1066,8 +1076,18 @@
},
validate_warehouse: function(){
- if(!this.items[0].default_warehouse){
+ if(!this.items[0].default_warehouse && !this.pos_profile_data['warehouse']){
frappe.throw(__("Default warehouse is required for selected item"))
}
+ },
+
+ get_actual_qty: function(item) {
+ this.actual_qty = 0.0;
+ var warehouse = this.pos_profile_data['warehouse'] || item.default_warehouse;
+ if(warehouse && this.bin_data[item.item_code]) {
+ this.actual_qty = this.bin_data[item.item_code][warehouse] || 0;
+ }
+
+ return this.actual_qty
}
})
\ No newline at end of file