From d0cee1b61b6cf6748fb2b4c722eb67e42fcb3f26 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Fri, 20 May 2016 12:54:44 +0530 Subject: [PATCH] [fix] minor fixes to pos --- .../doctype/party_account/party_account.json | 35 ++---- erpnext/accounts/doctype/sales_invoice/pos.py | 18 +-- erpnext/accounts/page/pos/pos.js | 115 +++++++++--------- .../doctype/sales_team/sales_team.json | 63 +++------- erpnext/setup/setup_wizard/domainify.py | 12 +- 5 files changed, 101 insertions(+), 142 deletions(-) diff --git a/erpnext/accounts/doctype/party_account/party_account.json b/erpnext/accounts/doctype/party_account/party_account.json index 45275310b0..e30346a07b 100644 --- a/erpnext/accounts/doctype/party_account/party_account.json +++ b/erpnext/accounts/doctype/party_account/party_account.json @@ -2,6 +2,7 @@ "allow_copy": 0, "allow_import": 0, "allow_rename": 0, + "beta": 0, "creation": "2014-08-29 16:02:39.740505", "custom": 0, "docstatus": 0, @@ -16,6 +17,7 @@ "fieldtype": "Link", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 1, "label": "Company", @@ -24,6 +26,7 @@ "options": "Company", "permlevel": 0, "print_hide": 0, + "print_hide_if_no_value": 0, "read_only": 0, "report_hide": 0, "reqd": 1, @@ -31,29 +34,6 @@ "set_only_once": 0, "unique": 0 }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "fieldname": "col_break1", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "in_filter": 0, - "in_list_view": 0, - "label": "", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0, - "width": "50%" - }, { "allow_on_submit": 0, "bold": 0, @@ -62,6 +42,7 @@ "fieldtype": "Link", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 1, "label": "Account", @@ -70,6 +51,7 @@ "options": "Account", "permlevel": 0, "print_hide": 0, + "print_hide_if_no_value": 0, "read_only": 0, "report_hide": 0, "reqd": 1, @@ -80,21 +62,24 @@ ], "hide_heading": 0, "hide_toolbar": 0, + "idx": 0, "in_create": 0, "in_dialog": 0, "is_submittable": 0, "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2015-11-16 06:29:51.450360", + "modified": "2016-05-20 11:47:16.625828", "modified_by": "Administrator", "module": "Accounts", "name": "Party Account", "name_case": "", "owner": "Administrator", "permissions": [], + "quick_entry": 1, "read_only": 0, "read_only_onload": 0, "sort_field": "modified", - "sort_order": "DESC" + "sort_order": "DESC", + "track_seen": 0 } \ No newline at end of file diff --git a/erpnext/accounts/doctype/sales_invoice/pos.py b/erpnext/accounts/doctype/sales_invoice/pos.py index 9bea107423..4ec2524529 100644 --- a/erpnext/accounts/doctype/sales_invoice/pos.py +++ b/erpnext/accounts/doctype/sales_invoice/pos.py @@ -19,7 +19,7 @@ def get_pos_data(): if pos_profile.get('name'): pos_profile = frappe.get_doc('POS Profile', pos_profile.get('name')) else: - frappe.msgprint(_("Warning Message: Create pos profile")) + frappe.msgprint(_("Warning Message: Create POS Profile")) update_pos_profile_data(doc, pos_profile) update_multi_mode_option(doc, pos_profile) @@ -47,7 +47,7 @@ def update_pos_profile_data(doc, pos_profile): update_tax_table(doc) doc.currency = pos_profile.get('currency') or company_data.default_currency - doc.conversion_rate = 1.0 + doc.conversion_rate = 1.0 if doc.currency != company_data.default_currency: doc.conversion_rate = get_exchange_rate(doc.currency, company_data.default_currency) doc.selling_price_list = pos_profile.get('selling_price_list') or frappe.db.get_value('Selling Settings', None, 'selling_price_list') @@ -57,16 +57,16 @@ def update_pos_profile_data(doc, pos_profile): doc.apply_discount_on = pos_profile.get('apply_discount_on') or '' doc.customer_group = pos_profile.get('customer_group') or get_root('Customer Group') doc.territory = pos_profile.get('territory') or get_root('Territory') - + def get_root(table): - root = frappe.db.sql(""" select name from `tab%(table)s` having + root = frappe.db.sql(""" select name from `tab%(table)s` having min(lft)"""%{'table': table}, as_dict=1) - - return root[0].name + + return root[0].name def update_multi_mode_option(doc, pos_profile): from frappe.model import default_fields - + if not pos_profile: return @@ -100,7 +100,7 @@ def get_items(doc, pos_profile): 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 = frappe.db.sql_list("""select name from `tabSerial No` where warehouse= %(warehouse)s + item.serial_nos = frappe.db.sql_list("""select name from `tabSerial No` where warehouse= %(warehouse)s and item_code = %(item_code)s""", {'warehouse': item.default_warehouse, 'item_code': item.item_code}) item_list.append(item) @@ -118,7 +118,7 @@ def get_pricing_rules(doc): return frappe.db.sql(""" Select * from `tabPricing Rule` where docstatus < 2 and disable = 0 and selling = 1 and ifnull(company, '') in (%(company)s, '') and ifnull(for_price_list, '') in (%(price_list)s, '') and %(date)s between - ifnull(valid_from, '2000-01-01') and ifnull(valid_upto, '2500-12-31') order by priority desc, name desc""", + ifnull(valid_from, '2000-01-01') and ifnull(valid_upto, '2500-12-31') order by priority desc, name desc""", {'company': doc.company, 'price_list': doc.selling_price_list, 'date': nowdate()}, as_dict=1) def get_mode_of_payment(doc): diff --git a/erpnext/accounts/page/pos/pos.js b/erpnext/accounts/page/pos/pos.js index 2162563f22..386ed9ed93 100644 --- a/erpnext/accounts/page/pos/pos.js +++ b/erpnext/accounts/page/pos/pos.js @@ -27,7 +27,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ this.set_interval_for_si_sync(); this.si_docs = this.get_doc_from_localstorage(); }, - + on_refresh_page: function() { var me = this; if(this.load){ @@ -63,19 +63,23 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ onload: function(){ var me = this; this.get_data_from_server(function(){ - me.create_new(); + me.create_new(); }); - + this.check_internet_connection(); }, make_menu_list: function(){ var me = this; - this.page.add_menu_item(__("Unsync Records"), function(){ + this.page.add_menu_item(__("New Sales Invoice"), function() { + me.create_new() + }) + + this.page.add_menu_item(__("View Offline Records"), function(){ me.show_unsync_invoice_list() }); - + this.page.add_menu_item(__("Sync Master Data"), function(){ me.get_data_from_server(function(){ me.load_data() @@ -83,10 +87,10 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ me.make_item_list() }) }); - - this.page.add_menu_item(__("New Sales Invoice"), function() { - me.create_new() - }) + + this.page.add_menu_item(__("POS Profile"), function() { + frappe.set_route('POS Profile'); + }); }, show_unsync_invoice_list: function(){ @@ -96,7 +100,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ this.list_dialog = new frappe.ui.Dialog({ title: 'Invoice List' }); - + this.list_dialog.show(); this.list_body = this.list_dialog.body; $(this.list_body).append('
\ @@ -117,7 +121,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ })).appendTo($(me.list_body)); } }) - + $(this.list_body).find('.list-row').click(function() { me.name = $(this).attr('invoice-name') doc_data = me.get_invoice_doc(me.si_docs) @@ -130,7 +134,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ } }) }, - + set_missing_values: function(){ var me = this; doc = JSON.parse(localStorage.getItem('doc')) @@ -147,7 +151,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ for(key in data){ return key == me.name } - }) + }) }, get_data_from_server: function(callback){ @@ -169,7 +173,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ } }) }, - + create_new: function(){ var me = this; this.frm = {} @@ -188,7 +192,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ frappe.meta.sync(data) }) - this.print_template = frappe.render_template("print_template", + this.print_template = frappe.render_template("print_template", {content: window.print_template, title:"POS"}) }, @@ -227,15 +231,15 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ parent: this.wrapper.find(".search-area"), only_input: true, }); - + this.search.make_input(); this.search.$input.on("keyup", function() { setTimeout(function() { me.items = me.get_items(); - me.make_item_list(); + me.make_item_list(); }, 1000); }); - + this.party_field = frappe.ui.form.make_control({ df: { "fieldtype": "Data", @@ -247,23 +251,23 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ parent: this.wrapper.find(".party-area"), only_input: true, }); - + this.party_field.make_input(); }, make_customer: function() { var me = this; - + if(this.customers.length == 1){ this.party_field.$input.val(this.customers[0].name); this.frm.doc.customer = this.customers[0].name; } - + this.party_field.$input.autocomplete({ source: function (request, response) { me.customer_data = me.get_customers(request.term) response($.map(me.customer_data, function(data){ - return {label: data.name, value: data.name, + return {label: data.name, value: data.name, customer_group: data.customer_group, territory: data.territory} })) }, @@ -285,8 +289,9 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ var me = this; key = key.toLowerCase() return $.grep(this.customers, function(data) { - if(data.name.toLowerCase().match(key) || data.customer_name.toLowerCase().match(key) - || data.customer_group.toLowerCase().match(key)){ + if(data.name.toLowerCase().match(key) + || data.customer_name.toLowerCase().match(key) + || (data.customer_group && data.customer_group.toLowerCase().match(key))){ return data } }) @@ -300,7 +305,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ } me.item_timeout = null; - + var $wrap = me.wrapper.find(".item-list"); me.wrapper.find(".item-list").empty(); @@ -318,7 +323,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ } }); } - + if(this.items.length == 1){ this.search.$input.val(""); this.add_to_cart(); @@ -339,7 +344,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ var me = this; this.item_serial_no = {} - + if(item_code){ return $.grep(window.items, function(item){ if(item.item_code == item_code ){ @@ -374,13 +379,13 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ var item_code = $(this).parents(".pos-bill-item").attr("data-item-code"); me.update_qty_against_item_code(item_code, $(this).val()); }) - + $(this.wrapper).find("[data-action='increase-qty']").on("click", function(){ var item_code = $(this).parents(".pos-bill-item").attr("data-item-code"); var qty = flt($(this).parents(".pos-bill-item").find('.pos-item-qty').val()) + 1; me.update_qty_against_item_code(item_code, qty); }) - + $(this.wrapper).find("[data-action='decrease-qty']").on("click", function(){ var item_code = $(this).parents(".pos-bill-item").attr("data-item-code"); var qty = flt($(this).parents(".pos-bill-item").find('.pos-item-qty').val()) - 1; @@ -393,7 +398,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ if(qty < 0){ frappe.throw(__("Quantity must be positive")); } - + this.remove_item = [] $.each(this.frm.doc["items"] || [], function(i, d) { if (d.item_code == item_code) { @@ -417,10 +422,10 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ if(!in_list(me.remove_item, d.idx)){ d.idx = idx; me.items.push(d); - idx++; + idx++; } }); - + this.frm.doc["items"] = this.items; }, @@ -430,11 +435,11 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ this.wrapper.find('input.discount-percentage').on("change", function() { me.frm.doc.additional_discount_percentage = flt($(this).val(), precision("additional_discount_percentage")); total = me.frm.doc.grand_total - + if(me.frm.doc.apply_discount_on == 'Net Total'){ total = me.frm.doc.net_total } - + me.frm.doc.discount_amount = flt(total*flt(me.frm.doc.additional_discount_percentage) / 100, precision("discount_amount")); me.wrapper.find('input.discount-amount').val(me.frm.doc.discount_amount) me.refresh(); @@ -450,7 +455,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ customer_validate: function(){ var me = this; - + if(!this.frm.doc.customer){ frappe.throw(__("Please select customer")) } @@ -500,7 +505,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ 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.child.amount = flt(this.child.qty) * flt(this.child.rate); - this.child.serial_no = this.item_serial_no[this.child.item_code]; + this.child.serial_no = this.item_serial_no[this.child.item_code]; }, refresh: function() { @@ -519,15 +524,15 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ this.calculate_outstanding_amount(); this.set_totals(); }, - + get_company_currency: function() { return erpnext.get_currency(this.frm.doc.company); }, - + show_item_wise_taxes: function(){ return null; }, - + show_items_in_item_cart: function() { var me = this; var $items = this.wrapper.find(".items").empty(); @@ -557,7 +562,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ $(this.wrapper) .find(".tax-area").toggleClass("hide", (taxes && taxes.length) ? false : true) .find(".tax-table").empty(); - + $.each(taxes, function(i, d) { if (d.tax_amount && cint(d.included_in_print_rate) == 0) { $(frappe.render_template("pos_tax_row", { @@ -602,9 +607,9 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ this.page.clear_primary_action() } }, - + write_off_amount: function(){ - var me = this; + var me = this; var value = 0.0; if(this.frm.doc.outstanding_amount > 0){ @@ -614,9 +619,9 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ {fieldtype: "Check", fieldname: "write_off_amount", label: __("Write of Outstanding Amount")}, ] }); - + dialog.show(); - + dialog.fields_dict.write_off_amount.$input.change(function(){ write_off_amount = dialog.get_values().write_off_amount me.frm.doc.write_off_outstanding_amount_automatically = write_off_amount; @@ -624,7 +629,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ me.frm.doc.write_off_amount = flt(me.frm.doc.base_write_off_amount * me.frm.doc.conversion_rate, precision("write_off_amount")) me.calculate_outstanding_amount(); }) - + dialog.set_primary_action(__("Submit"), function(){ dialog.hide() me.submit_invoice() @@ -633,7 +638,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ this.submit_invoice() } }, - + submit_invoice: function(){ var me = this; frappe.confirm(__("Do you really want to submit the invoice?"), function () { @@ -652,12 +657,12 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ disable_input_field: function(){ var pointer_events = 'inherit' $(this.wrapper).find('input').attr("disabled", false); - + if(this.frm.doc.docstatus == 1){ pointer_events = 'none' - $(this.wrapper).find('input').attr("disabled", true); + $(this.wrapper).find('input').attr("disabled", true); } - + $(this.wrapper).find('.pos-bill-wrapper').css('pointer-events', pointer_events); $(this.wrapper).find('.pos-items-section').css('pointer-events', pointer_events); this.set_primary_action(); @@ -786,7 +791,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ item_code = key; serial_no = me.item_serial_no[key] } - + if(item_code && serial_no){ $.each(this.frm.doc.items, function(index, data){ if(data.item_code == item_code){ @@ -852,16 +857,16 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ var priority_list = [] if(pricing_rule.length > 1){ - + $.each(pricing_rule, function(index, data){ - pricing_rule_name += data.name + ',' + pricing_rule_name += data.name + ',' priority_list.push(data.priority) if(priority <= data.priority){ priority = data.priority pricing_rule_list.push(data) } }) - + count = 0 $.each(priority_list, function(index, value){ if(value == priority){ @@ -874,11 +879,11 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ 'pricing_rule': pricing_rule_name }))) } - + return pricing_rule_list } }, - + validate_warehouse: function(){ if(!this.items[0].default_warehouse){ frappe.throw(__("Deafault warehouse is required for selected item")) diff --git a/erpnext/selling/doctype/sales_team/sales_team.json b/erpnext/selling/doctype/sales_team/sales_team.json index d15ce0837e..8e7772c6ae 100644 --- a/erpnext/selling/doctype/sales_team/sales_team.json +++ b/erpnext/selling/doctype/sales_team/sales_team.json @@ -2,10 +2,12 @@ "allow_copy": 0, "allow_import": 0, "allow_rename": 0, + "beta": 0, "creation": "2013-04-19 13:30:51", "custom": 0, "docstatus": 0, "doctype": "DocType", + "document_type": "Setup", "fields": [ { "allow_on_submit": 1, @@ -15,6 +17,7 @@ "fieldtype": "Link", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 1, "in_list_view": 1, "label": "Sales Person", @@ -25,6 +28,7 @@ "options": "Sales Person", "permlevel": 0, "print_hide": 0, + "print_hide_if_no_value": 0, "print_width": "200px", "read_only": 0, "report_hide": 0, @@ -42,6 +46,7 @@ "fieldtype": "Data", "hidden": 1, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 1, "label": "Contact No.", @@ -51,6 +56,7 @@ "oldfieldtype": "Data", "permlevel": 0, "print_hide": 0, + "print_hide_if_no_value": 0, "print_width": "100px", "read_only": 0, "report_hide": 0, @@ -60,27 +66,6 @@ "unique": 0, "width": "100px" }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "fieldname": "col_break1", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "in_filter": 0, - "in_list_view": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, { "allow_on_submit": 1, "bold": 0, @@ -89,6 +74,7 @@ "fieldtype": "Float", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 1, "label": "Contribution (%)", @@ -98,6 +84,7 @@ "oldfieldtype": "Currency", "permlevel": 0, "print_hide": 0, + "print_hide_if_no_value": 0, "print_width": "100px", "read_only": 0, "report_hide": 0, @@ -115,6 +102,7 @@ "fieldtype": "Currency", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 1, "label": "Contribution to Net Total", @@ -125,6 +113,7 @@ "options": "Company:company:default_currency", "permlevel": 0, "print_hide": 0, + "print_hide_if_no_value": 0, "print_width": "120px", "read_only": 1, "report_hide": 0, @@ -142,6 +131,7 @@ "fieldtype": "Currency", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 1, "label": "Incentives", @@ -152,36 +142,13 @@ "options": "Company:company:default_currency", "permlevel": 0, "print_hide": 0, + "print_hide_if_no_value": 0, "read_only": 0, "report_hide": 0, "reqd": 0, "search_index": 0, "set_only_once": 0, "unique": 0 - }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "fieldname": "parenttype", - "fieldtype": "Data", - "hidden": 1, - "ignore_user_permissions": 0, - "in_filter": 1, - "in_list_view": 0, - "label": "Parenttype", - "length": 0, - "no_copy": 0, - "oldfieldname": "parenttype", - "oldfieldtype": "Data", - "permlevel": 0, - "print_hide": 1, - "read_only": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 1, - "set_only_once": 0, - "unique": 0 } ], "hide_heading": 0, @@ -193,12 +160,14 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2015-11-16 06:29:57.395852", + "modified": "2016-05-20 11:48:34.343879", "modified_by": "Administrator", "module": "Selling", "name": "Sales Team", "owner": "Administrator", "permissions": [], + "quick_entry": 1, "read_only": 0, - "read_only_onload": 0 + "read_only_onload": 0, + "track_seen": 0 } \ No newline at end of file diff --git a/erpnext/setup/setup_wizard/domainify.py b/erpnext/setup/setup_wizard/domainify.py index 5985708501..af4317e017 100644 --- a/erpnext/setup/setup_wizard/domainify.py +++ b/erpnext/setup/setup_wizard/domainify.py @@ -16,9 +16,9 @@ domains = { ['Stock Settings', None, 'show_barcode_field', 1] ] }, - - 'Retail': { - 'desktop_icons': ['POS', 'Item', 'Customer', 'Sales Invoice', 'Purchase Order', 'Warranty Claim', + + 'Retail': { + 'desktop_icons': ['POS', 'Item', 'Customer', 'Sales Invoice', 'Purchase Order', 'Warranty Claim', 'Accounts', 'Buying'], 'remove_roles': ['Manufacturing User', 'Manufacturing Manager'], 'properties': [ @@ -29,7 +29,7 @@ domains = { ['Stock Settings', None, 'show_barcode_field', 1] ] }, - + 'Distribution': { 'desktop_icons': ['Item', 'Customer', 'Supplier', 'Lead', 'Sales Order', 'Sales Invoice', 'CRM', 'Selling', 'Buying', 'Stock', 'Accounts', 'HR'], @@ -41,9 +41,9 @@ domains = { ['Stock Settings', None, 'show_barcode_field', 1] ] }, - + 'Services': { - 'desktop_icons': ['Project', 'Time Log', 'Customer', 'Sales Invoice', 'Lead', 'Opportunity', + 'desktop_icons': ['Project', 'Time Log', 'Customer', 'Sales Order', 'Sales Invoice', 'Lead', 'Opportunity', 'Expense Claim', 'Employee', 'HR'], 'remove_roles': ['Manufacturing User', 'Manufacturing Manager'], 'properties': [