feat: show only available items in point of sale (#23667)

* feat: show available items in pos

* feat: show selected pos profile on pos screen

* fix: codacy

* fix: codacy
This commit is contained in:
Saqib
2020-10-19 11:37:22 +05:30
committed by GitHub
parent 334c282f7b
commit 8e7a755aeb
5 changed files with 91 additions and 137 deletions

View File

@@ -1,4 +1,5 @@
{ {
"actions": [],
"allow_rename": 1, "allow_rename": 1,
"autoname": "Prompt", "autoname": "Prompt",
"creation": "2013-05-24 12:15:51", "creation": "2013-05-24 12:15:51",
@@ -22,6 +23,7 @@
"allow_user_to_edit_discount", "allow_user_to_edit_discount",
"allow_print_before_pay", "allow_print_before_pay",
"display_items_in_stock", "display_items_in_stock",
"hide_unavailable_items",
"section_break_15", "section_break_15",
"applicable_for_users", "applicable_for_users",
"section_break_11", "section_break_11",
@@ -389,11 +391,18 @@
"fieldtype": "Link", "fieldtype": "Link",
"label": "Tax Category", "label": "Tax Category",
"options": "Tax Category" "options": "Tax Category"
},
{
"default": "0",
"fieldname": "hide_unavailable_items",
"fieldtype": "Check",
"label": "Hide Unavailable Items"
} }
], ],
"icon": "icon-cog", "icon": "icon-cog",
"idx": 1, "idx": 1,
"modified": "2020-01-24 15:52:03.797701", "links": [],
"modified": "2020-10-16 04:33:57.283873",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "POS Profile", "name": "POS Profile",

View File

@@ -1,123 +1,39 @@
{ {
"allow_copy": 0, "actions": [],
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"beta": 0,
"creation": "2017-10-27 16:46:06.060930", "creation": "2017-10-27 16:46:06.060930",
"custom": 0,
"docstatus": 0,
"doctype": "DocType", "doctype": "DocType",
"document_type": "",
"editable_grid": 1, "editable_grid": 1,
"engine": "InnoDB", "engine": "InnoDB",
"field_order": [
"default",
"user"
],
"fields": [ "fields": [
{ {
"allow_bulk_edit": 0, "default": "0",
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "default", "fieldname": "default",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1, "in_list_view": 1,
"in_standard_filter": 0, "label": "Default"
"label": "Default",
"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,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "user", "fieldname": "user",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1, "in_list_view": 1,
"in_standard_filter": 0,
"label": "User", "label": "User",
"length": 0, "options": "User"
"no_copy": 0,
"options": "User",
"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,
"unique": 0
} }
], ],
"has_web_view": 0, "istable": 1,
"hide_heading": 0, "links": [],
"hide_toolbar": 0, "modified": "2020-10-16 04:33:27.594859",
"idx": 0,
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-11-23 17:13:16.005475",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "POS Profile User", "name": "POS Profile User",
"name_case": "",
"owner": "Administrator", "owner": "Administrator",
"permissions": [ "permissions": [],
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
}
],
"quick_entry": 1, "quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 0,
"sort_field": "modified", "sort_field": "modified",
"sort_order": "DESC", "sort_order": "DESC",
"track_changes": 1, "track_changes": 1
"track_seen": 0
} }

View File

@@ -175,6 +175,13 @@ def get_items_list(pos_profile, company):
if args_list: if args_list:
cond = "and i.item_group in (%s)" % (', '.join(['%s'] * len(args_list))) cond = "and i.item_group in (%s)" % (', '.join(['%s'] * len(args_list)))
bin_join = bin_cond = ""
if pos_profile.get('hide_unavailable_items'):
bin_join = ",`tabBin` b"
bin_cond = "and i.item_code = b.item_code and ifnull(b.actual_qty, 0) > 0 "
if pos_profile.get('warehouse'):
bin_cond += "and b.warehouse = {}".format(frappe.db.escape(pos_profile.get('warehouse')))
return frappe.db.sql(""" return frappe.db.sql("""
select select
i.name, i.item_code, i.item_name, i.description, i.item_group, i.has_batch_no, i.name, i.item_code, i.item_name, i.description, i.item_group, i.has_batch_no,
@@ -186,11 +193,13 @@ def get_items_list(pos_profile, company):
left join `tabItem Default` id on id.parent = i.name and id.company = %s left join `tabItem Default` id on id.parent = i.name and id.company = %s
left join `tabItem Tax` it on it.parent = i.name left join `tabItem Tax` it on it.parent = i.name
left join `tabUOM Conversion Detail` c on i.name = c.parent and i.sales_uom = c.uom left join `tabUOM Conversion Detail` c on i.name = c.parent and i.sales_uom = c.uom
{bin_join}
where where
i.disabled = 0 and i.has_variants = 0 and i.is_sales_item = 1 i.disabled = 0 and i.has_variants = 0 and i.is_sales_item = 1
{cond} {cond}
{bin_cond}
group by i.item_code group by i.item_code
""".format(cond=cond), tuple([company] + args_list), as_dict=1) """.format(cond=cond, bin_join=bin_join, bin_cond=bin_cond), tuple([company] + args_list), as_dict=1)
def get_item_groups(pos_profile): def get_item_groups(pos_profile):

View File

@@ -81,7 +81,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
me.page.set_indicator(__("Online"), "green") me.page.set_indicator(__("Online"), "green")
} }
} }
}) });
}, },
onload: function () { onload: function () {
@@ -278,6 +278,14 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
}) })
}, },
set_pos_profile_title(pos_profile) {
this.page.set_title_sub(
`<span class="indicator blue">
<a class="text-muted" href="#Form/POS Profile/${pos_profile}">${pos_profile}</a>
</span>`
);
},
get_data_from_server: function (callback) { get_data_from_server: function (callback) {
var me = this; var me = this;
frappe.call({ frappe.call({
@@ -286,6 +294,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
freeze_message: __("Master data syncing, it might take some time"), freeze_message: __("Master data syncing, it might take some time"),
callback: function (r) { callback: function (r) {
localStorage.setItem('doc', JSON.stringify(r.message.doc)); localStorage.setItem('doc', JSON.stringify(r.message.doc));
me.set_pos_profile_title(r.message.pos_profile.name);
me.init_master_data(r) me.init_master_data(r)
me.set_interval_for_si_sync(); me.set_interval_for_si_sync();
me.check_internet_connection(); me.check_internet_connection();

View File

@@ -16,7 +16,9 @@ def get_items(start, page_length, price_list, item_group, search_value="", pos_p
display_items_in_stock = 0 display_items_in_stock = 0
if pos_profile: if pos_profile:
warehouse, display_items_in_stock = frappe.db.get_value('POS Profile', pos_profile, ['warehouse', 'display_items_in_stock']) warehouse, display_items_in_stock, hide_unavailable_items = frappe.db.get_value(
'POS Profile', pos_profile, ['warehouse', 'display_items_in_stock', 'hide_unavailable_items']
)
if not frappe.db.exists('Item Group', item_group): if not frappe.db.exists('Item Group', item_group):
item_group = get_root_of('Item Group') item_group = get_root_of('Item Group')
@@ -37,24 +39,31 @@ def get_items(start, page_length, price_list, item_group, search_value="", pos_p
lft, rgt = frappe.db.get_value('Item Group', item_group, ['lft', 'rgt']) lft, rgt = frappe.db.get_value('Item Group', item_group, ['lft', 'rgt'])
# locate function is used to sort by closest match from the beginning of the value # locate function is used to sort by closest match from the beginning of the value
bin_join = bin_cond = ""
if hide_unavailable_items:
bin_join = ",`tabBin` b"
bin_cond = "and i.item_code = b.item_code and ifnull(b.actual_qty, 0) > 0 "
if warehouse:
bin_cond += "and b.warehouse = {}".format(frappe.db.escape(warehouse))
result = [] result = []
items_data = frappe.db.sql(""" items_data = frappe.db.sql("""
SELECT SELECT
name AS item_code, i.name AS item_code,
item_name, i.item_name,
stock_uom, i.stock_uom,
image AS item_image, i.image AS item_image,
idx AS idx, i.idx AS idx,
is_stock_item i.is_stock_item
FROM FROM
`tabItem` `tabItem` i {bin_join}
WHERE WHERE
disabled = 0 disabled = 0
AND has_variants = 0 AND i.has_variants = 0
AND is_sales_item = 1 AND i.is_sales_item = 1
AND item_group in (SELECT name FROM `tabItem Group` WHERE lft >= {lft} AND rgt <= {rgt}) AND i.item_group in (SELECT name FROM `tabItem Group` WHERE lft >= {lft} AND rgt <= {rgt})
AND {condition} {condition} {bin_cond}
ORDER BY ORDER BY
idx desc idx desc
LIMIT LIMIT
@@ -64,7 +73,9 @@ def get_items(start, page_length, price_list, item_group, search_value="", pos_p
page_length=page_length, page_length=page_length,
lft=lft, lft=lft,
rgt=rgt, rgt=rgt,
condition=condition condition=condition,
bin_join=bin_join,
bin_cond=bin_cond
), as_dict=1) ), as_dict=1)
if items_data: if items_data:
@@ -154,16 +165,16 @@ def search_serial_or_batch_or_barcode_number(search_value):
def get_conditions(item_code, serial_no, batch_no, barcode): def get_conditions(item_code, serial_no, batch_no, barcode):
if serial_no or batch_no or barcode: if serial_no or batch_no or barcode:
return "name = {0}".format(frappe.db.escape(item_code)) return "and i.name = {0}".format(frappe.db.escape(item_code))
return """(name like {item_code} return ("""and (i.name like {item_code} or i.item_name like {item_code})"""
or item_name like {item_code})""".format(item_code = frappe.db.escape('%' + item_code + '%')) .format(item_code=frappe.db.escape('%' + item_code + '%')))
def get_item_group_condition(pos_profile): def get_item_group_condition(pos_profile):
cond = "and 1=1" cond = "and 1=1"
item_groups = get_item_groups(pos_profile) item_groups = get_item_groups(pos_profile)
if item_groups: if item_groups:
cond = "and item_group in (%s)"%(', '.join(['%s']*len(item_groups))) cond = "and i.item_group in (%s)"%(', '.join(['%s']*len(item_groups)))
return cond % tuple(item_groups) return cond % tuple(item_groups)