diff --git a/posawesome/fixtures/custom_field.json b/posawesome/fixtures/custom_field.json index adf2cdef..1be05905 100644 --- a/posawesome/fixtures/custom_field.json +++ b/posawesome/fixtures/custom_field.json @@ -438,7 +438,7 @@ "dt": "Batch", "fetch_from": null, "fetch_if_empty": 0, - "fieldname": "posa_btach_price", + "fieldname": "posa_batch_price", "fieldtype": "Float", "hidden": 0, "hide_border": 0, @@ -455,7 +455,7 @@ "length": 0, "mandatory_depends_on": null, "modified": "2020-10-26 02:31:58.913688", - "name": "Batch-posa_btach_price", + "name": "Batch-posa_batch_price", "no_copy": 0, "non_negative": 0, "options": null, @@ -3550,6 +3550,112 @@ "unique": 0, "width": null }, +{ + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "collapsible_depends_on": null, + "columns": 0, + "default": null, + "depends_on": null, + "description": null, + "docstatus": 0, + "doctype": "Custom Field", + "dt": "POS Profile", + "fetch_from": null, + "fetch_if_empty": 0, + "fieldname": "posa_limit_search", + "fieldtype": "Check", + "hidden": 0, + "hide_border": 0, + "hide_days": 0, + "hide_seconds": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_preview": 0, + "in_standard_filter": 0, + "insert_after": "posa_search_serial_no", + "label": "Limit Search Result", + "length": 0, + "mandatory_depends_on": null, + "modified": "2020-10-30 03:54:32.270370", + "name": "POS Profile-posa_limit_search", + "no_copy": 0, + "non_negative": 0, + "options": null, + "parent": null, + "parentfield": null, + "parenttype": null, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "print_width": null, + "read_only": 0, + "read_only_depends_on": null, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "translatable": 0, + "unique": 0, + "width": null + }, + { + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "collapsible_depends_on": null, + "columns": 0, + "default": "500", + "depends_on": "eval:(doc.posa_limit_search)", + "description": "For best performance keep this under 1500", + "docstatus": 0, + "doctype": "Custom Field", + "dt": "POS Profile", + "fetch_from": null, + "fetch_if_empty": 0, + "fieldname": "posa_search_limit", + "fieldtype": "Int", + "hidden": 0, + "hide_border": 0, + "hide_days": 0, + "hide_seconds": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_preview": 0, + "in_standard_filter": 0, + "insert_after": "posa_limit_search", + "label": "Set the limit number for the search result", + "length": 0, + "mandatory_depends_on": null, + "modified": "2020-10-30 03:54:32.270370", + "name": "POS Profile-posa_search_limit", + "no_copy": 0, + "non_negative": 0, + "options": null, + "parent": null, + "parentfield": null, + "parenttype": null, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "print_width": null, + "read_only": 0, + "read_only_depends_on": null, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "translatable": 0, + "unique": 0, + "width": null + }, { "allow_in_quick_entry": 0, "allow_on_submit": 0, diff --git a/posawesome/hooks.py b/posawesome/hooks.py index 303982e0..e2369314 100644 --- a/posawesome/hooks.py +++ b/posawesome/hooks.py @@ -168,7 +168,7 @@ "POS Profile-posa_allow_partial_payment", "POS Profile-posa_allow_credit_sale", "POS Profile-posa_pos_awesome_advance_settings", - "Batch-posa_btach_price", + "Batch-posa_batch_price", "POS Profile-posa_max_discount_allowed", "POS Profile-posa_allow_return", "POS Profile-posa_col_1", diff --git a/posawesome/posawesome/api/posapp.py b/posawesome/posawesome/api/posapp.py index 384b6074..95089877 100644 --- a/posawesome/posawesome/api/posapp.py +++ b/posawesome/posawesome/api/posapp.py @@ -118,19 +118,45 @@ def update_opening_shift_data(data, pos_profile): @frappe.whitelist() -def get_items(pos_profile, price_list=None): +def get_items(pos_profile, price_list=None, item_group="", search_value=""): pos_profile = json.loads(pos_profile) + data = dict() + + posa_display_items_in_stock = pos_profile.get("posa_display_items_in_stock") + search_serial_no = pos_profile.get("posa_search_serial_no") + posa_show_template_items = pos_profile.get("posa_show_template_items") + warehouse = pos_profile.get("warehouse") + limit_search = pos_profile.get("posa_limit_search") + search_limit = pos_profile.get("posa_search_limit") + if not price_list: price_list = pos_profile.get("selling_price_list") + + condition = "" + limit = "" condition += get_item_group_condition(pos_profile.get("name")) - if not pos_profile.get("posa_show_template_items"): + + if(limit_search): + if search_value: + data = search_serial_or_batch_or_barcode_number(search_value, search_serial_no) + + item_code = data.get("item_code") if data.get("item_code") else search_value + serial_no = data.get("serial_no") if data.get("serial_no") else "" + batch_no = data.get("batch_no") if data.get("batch_no") else "" + barcode = data.get("barcode") if data.get("barcode") else "" + + condition += get_conditions(item_code, serial_no, batch_no, barcode) + if(item_group): + condition += " AND item_group like '%{item_group}%'".format(item_group=item_group) + limit = " LIMIT {search_limit}".format(search_limit=search_limit) + + if not posa_show_template_items: condition += " AND has_variants = 0" result = [] - - items_data = frappe.db.sql( - """ + + items_data = frappe.db.sql(""" SELECT name AS item_code, item_name, @@ -152,12 +178,15 @@ def get_items(pos_profile, price_list=None): disabled = 0 AND is_sales_item = 1 AND is_fixed_asset = 0 - {0} + {condition} ORDER BY - name asc + item_name asc + {limit} """.format( - condition - ), + condition=condition, + limit=limit + ) + , as_dict=1, ) @@ -194,15 +223,15 @@ def get_items(pos_profile, price_list=None): fields=["barcode", "posa_uom"], ) serial_no_data = [] - if pos_profile.get("posa_search_serial_no"): + if search_serial_no: serial_no_data = frappe.get_all( "Serial No", - filters={"item_code": item_code, "status": "Active"}, + filters={"item_code": item_code, "status": "Active", "warehouse": warehouse}, fields=["name as serial_no"], ) - if pos_profile.get("posa_display_items_in_stock"): + if posa_display_items_in_stock: item_stock_qty = get_stock_availability( - item_code, pos_profile.get("warehouse") + item_code, warehouse ) attributes = "" if pos_profile.get("posa_show_template_items") and item.has_variants: @@ -214,7 +243,7 @@ def get_items(pos_profile, price_list=None): fields=["attribute", "attribute_value"], filters={"parent": item.item_code, "parentfield": "attributes"}, ) - if pos_profile.get("posa_display_items_in_stock") and ( + if posa_display_items_in_stock and ( not item_stock_qty or item_stock_qty < 0 ): pass @@ -227,7 +256,7 @@ def get_items(pos_profile, price_list=None): "currency": item_price.get("currency") or pos_profile.get("currency"), "item_barcode": item_barcode or [], - "actual_qty": 0, + "actual_qty": item_stock_qty or 0, "serial_no_data": serial_no_data or [], "attributes": attributes or "", "item_attributes": item_attributes or "", @@ -239,10 +268,10 @@ def get_items(pos_profile, price_list=None): def get_item_group_condition(pos_profile): - cond = "and 1=1" + cond = " and 1=1" item_groups = get_item_groups(pos_profile) if item_groups: - cond = "and item_group in (%s)" % (", ".join(["%s"] * len(item_groups))) + cond = " and item_group in (%s)" % (", ".join(["%s"] * len(item_groups))) return cond % tuple(item_groups) @@ -758,7 +787,7 @@ def get_items_details(pos_profile, items_data): serial_no_data = frappe.get_all( "Serial No", - filters={"item_code": item_code, "status": "Active"}, + filters={"item_code": item_code, "status": "Active", "warehouse": warehouse}, fields=["name as serial_no"], ) @@ -780,7 +809,7 @@ def get_items_details(pos_profile, items_data): "batch_no": batch.batch_no, "batch_qty": batch.qty, "expiry_date": batch_doc.expiry_date, - "btach_price": batch_doc.posa_btach_price, + "batch_price": batch_doc.posa_batch_price, } ) @@ -1537,3 +1566,27 @@ def set_payment_schedule(doc): d.base_payment_amount = flt( d.payment_amount * doc.get("conversion_rate"), d.precision("base_payment_amount") ) + +@frappe.whitelist() +def search_serial_or_batch_or_barcode_number(search_value, search_serial_no): + # search barcode no + barcode_data = frappe.db.get_value('Item Barcode', {'barcode': search_value}, ['barcode', 'parent as item_code'], as_dict=True) + if barcode_data: + return barcode_data + # search serial no + if search_serial_no: + serial_no_data = frappe.db.get_value('Serial No', search_value, ['name as serial_no', 'item_code'], as_dict=True) + if serial_no_data: + return serial_no_data + # search batch no + batch_no_data = frappe.db.get_value('Batch', search_value, ['name as batch_no', 'item as item_code'], as_dict=True) + if batch_no_data: + return batch_no_data + return {} + +def get_conditions(item_code, serial_no, batch_no, barcode): + + if serial_no or batch_no or barcode: + return " and name = {0}".format(frappe.db.escape(item_code)) + return (""" and (name like {item_code} or item_name like {item_code})""" + .format(item_code=frappe.db.escape('%' + item_code + '%'))) \ No newline at end of file diff --git a/posawesome/public/js/posapp/components/pos/Invoice.vue b/posawesome/public/js/posapp/components/pos/Invoice.vue index bdd89413..197df760 100644 --- a/posawesome/public/js/posapp/components/pos/Invoice.vue +++ b/posawesome/public/js/posapp/components/pos/Invoice.vue @@ -240,7 +240,7 @@ hide-details v-model.number="item.qty" type="number" - @change="calc_sotck_gty(item, $event)" + @change="calc_stock_qty(item, $event)" :disabled="!!item.posa_is_offer || !!item.posa_is_replace" > @@ -864,7 +864,7 @@ export default { if (item.qty == 0) { this.remove_item(item); } - this.calc_sotck_gty(item, item.qty); + this.calc_stock_qty(item, item.qty); this.$forceUpdate(); }, subtract_one(item) { @@ -872,7 +872,7 @@ export default { if (item.qty == 0) { this.remove_item(item); } - this.calc_sotck_gty(item, item.qty); + this.calc_stock_qty(item, item.qty); this.$forceUpdate(); }, @@ -918,14 +918,14 @@ export default { } if (!cur_item.has_batch_no) { cur_item.qty += item.qty || 1; - this.calc_sotck_gty(cur_item, cur_item.qty); + this.calc_stock_qty(cur_item, cur_item.qty); } else { if ( cur_item.stock_qty < cur_item.actual_batch_qty || !cur_item.batch_no ) { cur_item.qty += item.qty || 1; - this.calc_sotck_gty(cur_item, cur_item.qty); + this.calc_stock_qty(cur_item, cur_item.qty); } else { const new_item = this.get_new_item(cur_item); new_item.batch_no = ''; @@ -1219,6 +1219,16 @@ export default { value = false; } } + if(item.qty == 0){ + evntBus.$emit('show_mesage', { + text: __( + `Quantity for item '{0}' cannot be Zero (0)`, + [item.item_name] + ), + color: 'error', + }); + value = false; + } if ( item.max_discount > 0 && item.discount_percentage > item.max_discount @@ -1443,7 +1453,7 @@ export default { } } } - if (!item.btach_price) { + if (!item.batch_price) { if ( !item.is_free_item && !item.posa_is_offer && @@ -1588,13 +1598,13 @@ export default { item.discount_amount = 0; item.discount_percentage = 0; } - if (item.btach_price) { - item.price_list_rate = item.btach_price * new_uom.conversion_factor; + if (item.batch_price) { + item.price_list_rate = item.batch_price * new_uom.conversion_factor; } this.update_item_detail(item); }, - calc_sotck_gty(item, value) { + calc_stock_qty(item, value) { item.stock_qty = item.conversion_factor * value; }, @@ -1606,13 +1616,9 @@ export default { }); item.serial_no_selected_count = item.serial_no_selected.length; if (item.serial_no_selected_count != item.stock_qty) { - evntBus.$emit('show_mesage', { - text: __(`Selected Serial No QTY is {0} it should be {1}`, [ - item.serial_no_selected_count, - item.stock_qty, - ]), - color: 'warning', - }); + item.qty = item.serial_no_selected_count; + this.calc_stock_qty(item, item.qty); + this.$forceUpdate(); } }, @@ -1622,12 +1628,12 @@ export default { ); item.actual_batch_qty = batch_no.batch_qty; item.batch_no_expiry_date = batch_no.expiry_date; - if (batch_no.btach_price) { - item.btach_price = batch_no.btach_price; - item.price_list_rate = batch_no.btach_price; - item.rate = batch_no.btach_price; + if (batch_no.batch_price) { + item.batch_price = batch_no.batch_price; + item.price_list_rate = batch_no.batch_price; + item.rate = batch_no.batch_price; } else if (update) { - item.btach_price = null; + item.batch_price = null; this.update_item_detail(item); } }, diff --git a/posawesome/public/js/posapp/components/pos/ItemsSelector.vue b/posawesome/public/js/posapp/components/pos/ItemsSelector.vue index 39689cbc..84a5ecd2 100644 --- a/posawesome/public/js/posapp/components/pos/ItemsSelector.vue +++ b/posawesome/public/js/posapp/components/pos/ItemsSelector.vue @@ -25,7 +25,7 @@ hide-details v-model="debounce_search" @keydown.esc="esc_event" - @keydown.enter="enter_event" + @keydown.enter="search_onchange" ref="debounce_search" > @@ -126,6 +126,7 @@ outlined hide-details v-model="item_group" + v-on:change="search_onchange" > @@ -185,7 +186,10 @@ export default { watch: { filtred_items(data_value) { - this.update_items_details(data_value); + if(!this.pos_profile.posa_limit_search){ + this.update_items_details(data_value); + } + }, customer_price_list() { this.get_items(); @@ -209,7 +213,19 @@ export default { } const vm = this; this.loading = true; - if (vm.pos_profile.posa_local_storage && localStorage.items_storage) { + + let search = this.get_search(this.first_search); + let gr = ""; + let sr = ""; + if(search){ + sr = search; + } + + if(vm.item_group != 'ALL'){ + gr = vm.item_group.toLowerCase(); + } + + if (vm.pos_profile.posa_local_storage && localStorage.items_storage && !vm.pos_profile.posa_limit_search) { vm.items = JSON.parse(localStorage.getItem('items_storage')); evntBus.$emit('set_all_items', vm.items); vm.loading = false; @@ -219,17 +235,22 @@ export default { args: { pos_profile: vm.pos_profile, price_list: vm.customer_price_list, + item_group:gr, + search_value:sr, }, callback: function (r) { if (r.message) { vm.items = r.message; evntBus.$emit('set_all_items', vm.items); vm.loading = false; - console.info('loadItmes'); - if (vm.pos_profile.posa_local_storage) { + console.info('Items Loaded'); + if (vm.pos_profile.posa_local_storage && !vm.pos_profile.posa_limit_search) { localStorage.setItem('items_storage', ''); localStorage.setItem('items_storage', JSON.stringify(r.message)); } + if(vm.pos_profile.posa_limit_search){ + vm.enter_event(); + } } }, }); @@ -296,6 +317,7 @@ export default { } }, enter_event() { + let match = false; if (!this.filtred_items.length || !this.first_search) { return; } @@ -305,18 +327,38 @@ export default { new_item.item_barcode.forEach((element) => { if (this.search == element.barcode) { new_item.uom = element.posa_uom; + match = true; } }); + if(!new_item.to_set_serial_no && new_item.has_serial_no && this.pos_profile.posa_search_serial_no){ + new_item.serial_no_data.forEach((element)=>{ + if(this.search && element.serial_no == this.search){ + new_item.to_set_serial_no = this.first_search; + match = true; + } + }); + } + if (this.flags.serial_no) { new_item.to_set_serial_no = this.flags.serial_no; } - this.add_item(new_item); - this.search = null; - this.first_search = null; - this.debounce_search = null; - this.flags.serial_no = null; - this.qty = 1; - this.$refs.debounce_search.focus(); + if(match){ + this.add_item(new_item); + this.search = null; + this.first_search = null; + this.debounce_search = null; + this.flags.serial_no = null; + this.qty = 1; + this.$refs.debounce_search.focus(); + } + }, + search_onchange(){ + const vm = this; + if(vm.pos_profile.posa_limit_search){ + vm.get_items(); + }else{ + vm.enter_event(); + } }, get_item_qty(first_search) { let scal_qty = Math.abs(this.qty); @@ -429,73 +471,79 @@ export default { computed: { filtred_items() { this.search = this.get_search(this.first_search); - let filtred_list = []; - let filtred_group_list = []; - if (this.item_group != 'ALL') { - filtred_group_list = this.items.filter((item) => - item.item_group.toLowerCase().includes(this.item_group.toLowerCase()) - ); - } else { - filtred_group_list = this.items; - } - if (!this.search || this.search.length < 3) { - if ( - this.pos_profile.posa_show_template_items && - this.pos_profile.posa_hide_variants_items - ) { - return (filtred_list = filtred_group_list - .filter((item) => !item.variant_of) - .slice(0, 50)); + if(!this.pos_profile.posa_limit_search){ + this.search = this.get_search(this.first_search); + let filtred_list = []; + let filtred_group_list = []; + if (this.item_group != 'ALL') { + filtred_group_list = this.items.filter((item) => + item.item_group.toLowerCase().includes(this.item_group.toLowerCase()) + ); } else { - return (filtred_list = filtred_group_list.slice(0, 50)); + filtred_group_list = this.items; } - } else if (this.search) { - filtred_list = filtred_group_list.filter((item) => { - let found = false; - for (let element of item.item_barcode) { - if (element.barcode == this.search) { - found = true; - break; - } + if (!this.search || this.search.length < 3) { + if ( + this.pos_profile.posa_show_template_items && + this.pos_profile.posa_hide_variants_items + ) { + return (filtred_list = filtred_group_list + .filter((item) => !item.variant_of) + .slice(0, 50)); + } else { + return (filtred_list = filtred_group_list.slice(0, 50)); } - return found; - }); - if (filtred_list.length == 0) { - filtred_list = filtred_group_list.filter((item) => - item.item_code.toLowerCase().includes(this.search.toLowerCase()) - ); + } else if (this.search) { + filtred_list = filtred_group_list.filter((item) => { + let found = false; + for (let element of item.item_barcode) { + if (element.barcode == this.search) { + found = true; + break; + } + } + return found; + }); if (filtred_list.length == 0) { filtred_list = filtred_group_list.filter((item) => - item.item_name.toLowerCase().includes(this.search.toLowerCase()) + item.item_code.toLowerCase().includes(this.search.toLowerCase()) ); - } - if ( - filtred_list.length == 0 && - this.pos_profile.posa_search_serial_no - ) { - filtred_list = filtred_group_list.filter((item) => { - let found = false; - for (let element of item.serial_no_data) { - if (element.serial_no == this.search) { - found = true; - this.flags.serial_no = null; - this.flags.serial_no = this.search; - break; + if (filtred_list.length == 0) { + filtred_list = filtred_group_list.filter((item) => + item.item_name.toLowerCase().includes(this.search.toLowerCase()) + ); + } + if ( + filtred_list.length == 0 && + this.pos_profile.posa_search_serial_no + ) { + filtred_list = filtred_group_list.filter((item) => { + let found = false; + for (let element of item.serial_no_data) { + if (element.serial_no == this.search) { + found = true; + this.flags.serial_no = null; + this.flags.serial_no = this.search; + break; + } } - } - return found; - }); + return found; + }); + } } } + if ( + this.pos_profile.posa_show_template_items && + this.pos_profile.posa_hide_variants_items + ) { + return filtred_list.filter((item) => !item.variant_of).slice(0, 50); + } else { + return filtred_list.slice(0, 50); + } + }else{ + return this.items } - if ( - this.pos_profile.posa_show_template_items && - this.pos_profile.posa_hide_variants_items - ) { - return filtred_list.filter((item) => !item.variant_of).slice(0, 50); - } else { - return filtred_list.slice(0, 50); - } + }, debounce_search: { get() { diff --git a/posawesome/translations/pt.csv b/posawesome/translations/pt.csv index 96d1db2a..4c9df35b 100755 --- a/posawesome/translations/pt.csv +++ b/posawesome/translations/pt.csv @@ -104,7 +104,7 @@ DocType: POS Closing Shift,Payment Reconciliation,Reconciliação de Pagamento DocType: POS Closing Shift,Period End Date,Data de Fim de Periodo DocType: POS Closing Shift,Period Start Date,Data de Inicio de Periodo DocType: POS Closing Shift,Posting Date,Data de Postagem -Custom Field - label: Batch-posa_btach_price,Price,Preço +Custom Field - label: Batch-posa_batch_price,Price,Preço DocType: POS Offer,Price Discount Scheme ,Esquema de Desconto de Preço Custom Field - label: Sales Invoice-posa_is_printed,Printed,Imprimido DocType: POS Offer,Product Discount Scheme,Esquema de Desconto de Produto