diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.js b/erpnext/accounts/doctype/journal_entry/journal_entry.js index 370d529908..3183b08c29 100644 --- a/erpnext/accounts/doctype/journal_entry/journal_entry.js +++ b/erpnext/accounts/doctype/journal_entry/journal_entry.js @@ -50,6 +50,7 @@ erpnext.accounts.JournalEntry = frappe.ui.form.Controller.extend({ }, load_defaults: function() { + this.frm.show_print_first = true; if(this.frm.doc.__islocal && this.frm.doc.company) { frappe.model.set_default_values(this.frm.doc); $.each(this.frm.doc.accounts || [], function(i, jvd) { @@ -360,7 +361,7 @@ frappe.ui.form.on("Journal Entry Account", { credit: function(frm, dt, dn) { cur_frm.cscript.update_totals(frm.doc); }, - + exchange_rate: function(frm, cdt, cdn) { var company_currency = frappe.get_doc(":Company", frm.doc.company).default_currency; var row = locals[cdt][cdn]; @@ -368,7 +369,7 @@ frappe.ui.form.on("Journal Entry Account", { if(row.account_currency == company_currency || !frm.doc.multi_currency) { frappe.model.set_value(cdt, cdn, "exchange_rate", 1); } - + erpnext.journal_entry.set_debit_credit_in_company_currency(frm, cdt, cdn); } }) @@ -404,7 +405,7 @@ $.extend(erpnext.journal_entry, { frappe.model.set_value(cdt, cdn, "credit", flt(flt(row.credit_in_account_currency)*row.exchange_rate), precision("credit", row)); - + cur_frm.cscript.update_totals(frm.doc); }, diff --git a/erpnext/controllers/queries.py b/erpnext/controllers/queries.py index b94b3ebd87..b40e6f4811 100644 --- a/erpnext/controllers/queries.py +++ b/erpnext/controllers/queries.py @@ -160,10 +160,10 @@ def tax_account_query(doctype, txt, searchfield, start, page_len, filters): return tax_accounts -def item_query(doctype, txt, searchfield, start, page_len, filters): +def item_query(doctype, txt, searchfield, start, page_len, filters, as_dict=False): conditions = [] - return frappe.db.sql("""select tabItem.name,tabItem.item_group, + return frappe.db.sql("""select tabItem.name, tabItem.item_group, tabItem.image, if(length(tabItem.item_name) > 40, concat(substr(tabItem.item_name, 1, 40), "..."), item_name) as item_name, if(length(tabItem.description) > 40, \ @@ -192,7 +192,7 @@ def item_query(doctype, txt, searchfield, start, page_len, filters): "_txt": txt.replace("%", ""), "start": start, "page_len": page_len - }) + }, as_dict=as_dict) def bom(doctype, txt, searchfield, start, page_len, filters): conditions = [] @@ -209,11 +209,11 @@ def bom(doctype, txt, searchfield, start, page_len, filters): limit %(start)s, %(page_len)s """.format( fcond=get_filters_cond(doctype, filters, conditions), mcond=get_match_cond(doctype), - key=frappe.db.escape(searchfield)), + key=frappe.db.escape(searchfield)), { 'txt': "%%%s%%" % frappe.db.escape(txt), '_txt': txt.replace("%", ""), - 'start': start, + 'start': start, 'page_len': page_len }) @@ -346,13 +346,13 @@ def get_income_account(doctype, txt, searchfield, start, page_len, filters): @frappe.whitelist() def get_expense_account(doctype, txt, searchfield, start, page_len, filters): from erpnext.controllers.queries import get_match_cond - + if not filters: filters = {} condition = "" if filters.get("company"): condition += "and tabAccount.company = %(company)s" - + return frappe.db.sql("""select tabAccount.name from `tabAccount` where (tabAccount.report_type = "Profit and Loss" or tabAccount.account_type in ("Expense Account", "Fixed Asset", "Temporary")) @@ -360,7 +360,7 @@ def get_expense_account(doctype, txt, searchfield, start, page_len, filters): and tabAccount.docstatus!=2 and tabAccount.{key} LIKE %(txt)s {condition} {match_condition}""" - .format(condition=condition, key=frappe.db.escape(searchfield), + .format(condition=condition, key=frappe.db.escape(searchfield), match_condition=get_match_cond(doctype)), { 'company': filters.get("company", ""), 'txt': "%%%s%%" % frappe.db.escape(txt) diff --git a/erpnext/public/build.json b/erpnext/public/build.json index ff8bf94269..b3da719691 100644 --- a/erpnext/public/build.json +++ b/erpnext/public/build.json @@ -18,6 +18,8 @@ "public/js/pos/pos_bill_item.html", "public/js/pos/pos_item.html", "public/js/pos/pos_tax_row.html", - "public/js/pos/pos.js" + "public/js/pos/pos.js", + "public/js/utils/item_selector.js", + "public/js/templates/item_selector.html" ] } diff --git a/erpnext/public/css/erpnext.css b/erpnext/public/css/erpnext.css index 621efb55d7..d1d26bc4a8 100644 --- a/erpnext/public/css/erpnext.css +++ b/erpnext/public/css/erpnext.css @@ -13,17 +13,20 @@ margin: -10px auto; } /* pos */ +.pos-item-area { + padding: 0px 10px; +} +.pos-item-wrapper { + padding: 5px; +} .pos-item { - display: inline-block; overflow: hidden; text-overflow: ellipsis; cursor: pointer; padding: 5px; - height: 0px; - padding-bottom: 38%; - width: 30%; - margin: 1.6%; + padding-bottom: 15px; border: 1px solid #d1d8dd; + margin-bottom: 5px; } .pos-item-text { padding: 0px 5px; @@ -36,7 +39,13 @@ border: 1px dashed #d1d8dd; } .pos-item-image { - padding-bottom: 100%; + width: 100%; + height: 0px; + padding: 50% 0; + text-align: center; + line-height: 0; + color: #fff; + font-size: 30px; background-size: cover; border: 1px solid transparent; background-position: top center; diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js index dc6d4cdc81..9e2bd22caa 100644 --- a/erpnext/public/js/controllers/transaction.js +++ b/erpnext/public/js/controllers/transaction.js @@ -8,6 +8,7 @@ frappe.require("assets/erpnext/js/utils.js"); erpnext.TransactionController = erpnext.taxes_and_totals.extend({ onload: function() { var me = this; + this.frm.show_print_first = true; if(this.frm.doc.__islocal) { var today = get_today(), currency = frappe.defaults.get_user_default("currency"); @@ -81,7 +82,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ me.calculate_taxes_and_totals(); } if(frappe.meta.get_docfield(this.frm.doc.doctype + " Item", "item_code")) { - cur_frm.get_field("items").grid.set_multiple_add("item_code", "qty"); + this.setup_item_selector(); } }, @@ -890,7 +891,16 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ rate = flt(item.rate) * flt(this.frm.doc.conversion_rate || 1); item.gross_profit = flt(((rate - item.valuation_rate) * item.qty), precision("amount", item)); } + }, + + setup_item_selector: function() { + if(!this.item_selector) { + this.item_selector = new erpnext.ItemSelector({frm: this.frm}); + } } + + + }); frappe.ui.form.on(cur_frm.doctype + " Item", "rate", function(frm, cdt, cdn) { diff --git a/erpnext/public/js/pos/pos.html b/erpnext/public/js/pos/pos.html index d12b9b28bb..36ef7c958c 100644 --- a/erpnext/public/js/pos/pos.html +++ b/erpnext/public/js/pos/pos.html @@ -47,7 +47,10 @@ -
+
+
+ +
diff --git a/erpnext/public/js/pos/pos.js b/erpnext/public/js/pos/pos.js index a239bbc09f..60801e628a 100644 --- a/erpnext/public/js/pos/pos.js +++ b/erpnext/public/js/pos/pos.js @@ -131,7 +131,9 @@ erpnext.pos.PointOfSale = Class.extend({ item_code: obj.name, item_price: format_currency(obj.price_list_rate, obj.currency), item_name: obj.name===obj.item_name ? "" : obj.item_name, - item_image: obj.image ? "url('" + obj.image + "')" : null + item_image: obj.image ? "url('" + obj.image + "')" : null, + color: frappe.get_palette(obj.item_name), + abbr: frappe.get_abbr(obj.item_name) })).tooltip().appendTo($wrap); }); } diff --git a/erpnext/public/js/pos/pos_item.html b/erpnext/public/js/pos/pos_item.html index 1235db9b84..aec36a7f80 100644 --- a/erpnext/public/js/pos/pos_item.html +++ b/erpnext/public/js/pos/pos_item.html @@ -1,9 +1,13 @@ -
-
+
+
+
+ {% if (!item_image) { %}{{ abbr }}{% } %} +
+
+
{%= item_name ? (item_name + " (" + item_code + ")") : item_code %}
+
{%= item_price %}
+
-
-
{%= item_name ? (item_name + " (" + item_code + ")") : item_code %}
-
{%= item_price %}
-
-
+
\ No newline at end of file diff --git a/erpnext/public/js/templates/item_selector.html b/erpnext/public/js/templates/item_selector.html new file mode 100644 index 0000000000..47da67c8ee --- /dev/null +++ b/erpnext/public/js/templates/item_selector.html @@ -0,0 +1,16 @@ +
+{% for (var i=0; i < data.length; i++) { var item = data[i]; %} +
+
+
+ {% if(!item.image) { %}{{ item.abbr }}{% } %} +
+
+
{{ item.name }}
+
+
+
+{% } %} +
\ No newline at end of file diff --git a/erpnext/public/js/utils/item_selector.js b/erpnext/public/js/utils/item_selector.js new file mode 100644 index 0000000000..7d0bd15954 --- /dev/null +++ b/erpnext/public/js/utils/item_selector.js @@ -0,0 +1,94 @@ +erpnext.ItemSelector = Class.extend({ + init: function(opts) { + $.extend(this, opts); + + this.grid = this.frm.get_field("items").grid; + this.setup(); + }, + + setup: function() { + var me = this; + if(!this.grid.add_items_button) { + this.grid.add_items_button = this.grid.add_custom_button(__('Add Items'), function() { + if(!me.dialog) { + me.make_dialog(); + } + me.dialog.show(); + me.render_items(); + }); + } + }, + + make_dialog: function() { + this.dialog = new frappe.ui.Dialog({ + title: __('Add Items') + }); + var body = $(this.dialog.body); + body.html('

\ +
'); + + this.dialog.input = body.find('.form-control'); + this.dialog.results = body.find('.results'); + + var me = this; + this.dialog.results.on('click', '.pos-item', function() { + me.add_item($(this).attr('data-name')) + }); + + this.dialog.input.on('keyup', function() { + if(me.timeout_id) { + clearTimeout(me.timeout_id); + } + me.timeout_id = setTimeout(function() { + me.render_items(); + me.timeout_id = undefined; + }, 500); + }); + }, + + add_item: function(item_code) { + // add row or update qty + var added = false; + + // find row with item if exists + $.each(this.frm.doc.items || [], function(i, d) { + if(d.item_code===item_code) { + frappe.model.set_value(d.doctype, d.name, 'qty', d.qty + 1); + show_alert(__("Added {0} ({1})", [item_code, d.qty])); + added = true; + return false; + } + }); + + if(!added) { + var d = this.grid.add_new_row(); + frappe.model.set_value(d.doctype, d.name, 'item_code', item_code); + + // after item fetch + frappe.after_ajax(function() { + setTimeout(function() { + frappe.model.set_value(d.doctype, d.name, 'qty', 1); + show_alert(__("Added {0} ({1})", [item_code, 1])); + }, 100); + }); + } + + }, + + render_items: function() { + var args = erpnext.queries.item(); + args.txt = this.dialog.input.val(); + args.as_dict = 1; + + var me = this; + frappe.link_search("Item", args, function(r) { + $.each(r.values, function(i, d) { + if(!d.image) { + d.abbr = frappe.get_abbr(d.item_name); + d.color = frappe.get_palette(d.item_name); + } + }); + me.dialog.results.html(frappe.render_template('item_selector', {'data':r.values})); + }); + } +}) \ No newline at end of file diff --git a/erpnext/public/less/erpnext.less b/erpnext/public/less/erpnext.less index 813a5677cc..29d1533f48 100644 --- a/erpnext/public/less/erpnext.less +++ b/erpnext/public/less/erpnext.less @@ -16,20 +16,23 @@ } /* pos */ -.pos { + +.pos-item-area { + padding: 0px 10px; +} + +.pos-item-wrapper { + padding: 5px; } .pos-item { - display: inline-block; overflow: hidden; text-overflow: ellipsis; cursor: pointer; padding: 5px; - height: 0px; - padding-bottom: 38%; - width: 30%; - margin: 1.6%; + padding-bottom: 15px; border: 1px solid #d1d8dd; + margin-bottom: 5px; } .pos-item-text { @@ -46,7 +49,13 @@ } .pos-item-image { - padding-bottom: 100%; + width: 100%; + height: 0px; + padding: 50% 0; + text-align: center; + line-height: 0; + color: #fff; + font-size: 30px; background-size: cover; border: 1px solid transparent; background-position: top center; @@ -130,7 +139,7 @@ .discount-field-col { padding-left: 0px; } - + .input-group { margin-top: 2px; } diff --git a/erpnext/selling/doctype/customer/customer.json b/erpnext/selling/doctype/customer/customer.json index 09f29cd3a8..6974eb5234 100644 --- a/erpnext/selling/doctype/customer/customer.json +++ b/erpnext/selling/doctype/customer/customer.json @@ -300,7 +300,7 @@ { "allow_on_submit": 0, "bold": 0, - "collapsible": 0, + "collapsible": 1, "fieldname": "currency_and_price_list", "fieldtype": "Section Break", "hidden": 0, @@ -308,7 +308,7 @@ "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, - "label": "", + "label": "Currency and Price List", "length": 0, "no_copy": 0, "permlevel": 0, @@ -525,7 +525,7 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 1, - "collapsible_depends_on": "accounts", + "collapsible_depends_on": "", "fieldname": "default_receivable_accounts", "fieldtype": "Section Break", "hidden": 0, @@ -533,7 +533,7 @@ "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, - "label": "Default Receivable Accounts", + "label": "Accounting", "length": 0, "no_copy": 0, "permlevel": 0, @@ -927,7 +927,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2016-04-06 03:15:14.488537", + "modified": "2016-04-07 01:25:25.676480", "modified_by": "Administrator", "module": "Selling", "name": "Customer", diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.js b/erpnext/stock/doctype/stock_entry/stock_entry.js index 1cd085235f..46f8c70d21 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.js +++ b/erpnext/stock/doctype/stock_entry/stock_entry.js @@ -55,12 +55,15 @@ erpnext.stock.StockEntry = erpnext.stock.StockController.extend({ onload_post_render: function() { var me = this; - cur_frm.get_field("items").grid.set_multiple_add("item_code", "qty"); this.set_default_account(function() { if(me.frm.doc.__islocal && me.frm.doc.company && !me.frm.doc.amended_from) { cur_frm.script_manager.trigger("company"); } }); + + if(!this.item_selector) { + this.item_selector = new erpnext.ItemSelector({frm: this.frm}); + } }, refresh: function() {