[enhancement] Item Selector
This commit is contained in:
parent
9b8937d257
commit
203cc962f5
@ -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);
|
||||
},
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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"
|
||||
]
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -47,7 +47,10 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-7 pos-item-area">
|
||||
<div class="col-sm-7 pos-items-section">
|
||||
<div class="row pos-item-area">
|
||||
|
||||
</div>
|
||||
<div class="row pos-item-toolbar">
|
||||
<div class="search-area col-xs-12"></div>
|
||||
</div>
|
||||
|
@ -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);
|
||||
});
|
||||
}
|
||||
|
@ -1,9 +1,13 @@
|
||||
<div class="pos-item" data-item-code="{%= item_code %}" title="{%= item_name || item_code %}">
|
||||
<div class="pos-item-image {% if (!item_image) { %} no-image {% } %}"
|
||||
style="{% if (item_image) { %} background-image: {%= item_image %} {% } %}">
|
||||
<div class="pos-item-wrapper col-xs-3">
|
||||
<div class="pos-item" data-item-code="{%= item_code %}" title="{%= item_name || item_code %}">
|
||||
<div class="pos-item-image"
|
||||
style="{% if (item_image) { %} background-image: {{ item_image }} {% }
|
||||
else { %} background-color: {{ color }} {% } %}">
|
||||
{% if (!item_image) { %}{{ abbr }}{% } %}
|
||||
</div>
|
||||
<div class="pos-item-text">
|
||||
<h6 class="item-code text-ellipsis">{%= item_name ? (item_name + " (" + item_code + ")") : item_code %}</h6>
|
||||
<div class="small text-ellipsis">{%= item_price %}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pos-item-text">
|
||||
<h6 class="item-code text-ellipsis">{%= item_name ? (item_name + " (" + item_code + ")") : item_code %}</h6>
|
||||
<div class="small text-ellipsis">{%= item_price %}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
16
erpnext/public/js/templates/item_selector.html
Normal file
16
erpnext/public/js/templates/item_selector.html
Normal file
@ -0,0 +1,16 @@
|
||||
<div class="row pos-item-area">
|
||||
{% for (var i=0; i < data.length; i++) { var item = data[i]; %}
|
||||
<div class="col-xs-3 pos-item-wrapper">
|
||||
<div class="pos-item" data-name="{{ item.name }}">
|
||||
<div class="pos-item-image"
|
||||
{% if(item.image) { %}style="background-image: url({{ item.image }});"{% }
|
||||
else { %}style="background-color: {{ item.color }};"{% } %}>
|
||||
{% if(!item.image) { %}{{ item.abbr }}{% } %}
|
||||
</div>
|
||||
<div class="pos-item-text">
|
||||
<h6 class="item-code text-ellipsis">{{ item.name }}</h6>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% } %}
|
||||
</div>
|
94
erpnext/public/js/utils/item_selector.js
Normal file
94
erpnext/public/js/utils/item_selector.js
Normal file
@ -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('<div><p><input type="text" class="form-control"></p>\
|
||||
<br><div class="results"></div></div>');
|
||||
|
||||
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}));
|
||||
});
|
||||
}
|
||||
})
|
@ -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;
|
||||
}
|
||||
|
@ -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",
|
||||
|
@ -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() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user