From 94799a8b931e25cc98964776e1f69568c4a1d867 Mon Sep 17 00:00:00 2001 From: rohitwaghchaure Date: Thu, 28 Sep 2017 10:56:27 +0530 Subject: [PATCH 1/5] =?UTF-8?q?[fix]=20=E2=80=98NoneType=E2=80=99=20object?= =?UTF-8?q?=20is=20not=20iterable=20onload=20of=20POS=20(#10941)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- erpnext/selling/page/point_of_sale/point_of_sale.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/erpnext/selling/page/point_of_sale/point_of_sale.py b/erpnext/selling/page/point_of_sale/point_of_sale.py index fd6b8c9181..d74f1f06e3 100644 --- a/erpnext/selling/page/point_of_sale/point_of_sale.py +++ b/erpnext/selling/page/point_of_sale/point_of_sale.py @@ -3,12 +3,15 @@ from __future__ import unicode_literals import frappe, json +from frappe.utils.nestedset import get_root_of @frappe.whitelist() def get_items(start, page_length, price_list, item_group, search_value=""): serial_no = "" batch_no = "" item_code = search_value + if not frappe.db.exists('Item Group', item_group): + item_group = get_root_of('Item Group') if search_value: # search serial no From 16645803f9795b6f603f71faba55bcfea56d3f3a Mon Sep 17 00:00:00 2001 From: rohitwaghchaure Date: Thu, 28 Sep 2017 11:05:03 +0530 Subject: [PATCH 2/5] [fix] Added billing address gstin number in the sales invoice and delivery note as well in the sales gst reports (#10872) --- erpnext/patches.txt | 3 ++- .../update_billing_gstin_for_indian_account.py | 15 +++++++++++++++ erpnext/regional/india/setup.py | 5 ++++- .../gst_itemised_sales_register.py | 2 ++ .../gst_sales_register/gst_sales_register.py | 2 ++ 5 files changed, 25 insertions(+), 2 deletions(-) create mode 100644 erpnext/patches/v8_9/update_billing_gstin_for_indian_account.py diff --git a/erpnext/patches.txt b/erpnext/patches.txt index c6bd9ec50f..95adfd8f9c 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -434,7 +434,7 @@ erpnext.patches.v8_5.update_customer_group_in_POS_profile erpnext.patches.v8_6.update_timesheet_company_from_PO erpnext.patches.v8_6.set_write_permission_for_quotation_for_sales_manager erpnext.patches.v8_5.remove_project_type_property_setter -erpnext.patches.v8_7.add_more_gst_fields +erpnext.patches.v8_7.add_more_gst_fields #21-09-2017 erpnext.patches.v8_7.fix_purchase_receipt_status erpnext.patches.v8_6.rename_bom_update_tool erpnext.patches.v8_7.set_offline_in_pos_settings #11-09-17 @@ -445,3 +445,4 @@ erpnext.patches.v8_9.set_print_zero_amount_taxes erpnext.patches.v8_9.set_default_customer_group erpnext.patches.v8_9.remove_employee_from_salary_structure_parent erpnext.patches.v8_9.delete_gst_doctypes_for_outside_india_accounts +erpnext.patches.v8_9.update_billing_gstin_for_indian_account \ No newline at end of file diff --git a/erpnext/patches/v8_9/update_billing_gstin_for_indian_account.py b/erpnext/patches/v8_9/update_billing_gstin_for_indian_account.py new file mode 100644 index 0000000000..24e20409c1 --- /dev/null +++ b/erpnext/patches/v8_9/update_billing_gstin_for_indian_account.py @@ -0,0 +1,15 @@ +# Copyright (c) 2017, Frappe and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe + +def execute(): + company = frappe.get_all('Company', filters = {'country': 'India'}) + + if company: + for doctype in ['Sales Invoice', 'Delivery Note']: + frappe.db.sql(""" update `tab{0}` + set billing_address_gstin = (select gstin from `tabAddress` + where name = customer_address) + where customer_address is not null and customer_address != ''""".format(doctype)) \ No newline at end of file diff --git a/erpnext/regional/india/setup.py b/erpnext/regional/india/setup.py index 2798cfbd53..fb40e32e37 100644 --- a/erpnext/regional/india/setup.py +++ b/erpnext/regional/india/setup.py @@ -113,12 +113,15 @@ def make_custom_fields(): ] sales_invoice_gst_fields = [ + dict(fieldname='billing_address_gstin', label='Billing Address GSTIN', + fieldtype='Data', insert_after='customer_address', + options='customer_address.gstin', print_hide=1), dict(fieldname='customer_gstin', label='Customer GSTIN', fieldtype='Data', insert_after='shipping_address', options='shipping_address_name.gstin', print_hide=1), dict(fieldname='place_of_supply', label='Place of Supply', fieldtype='Data', insert_after='customer_gstin', print_hide=1, - options='shipping_address_name.gst_state_number', read_only=1), + options='shipping_address_name.gst_state_number', read_only=0), dict(fieldname='company_gstin', label='Company GSTIN', fieldtype='Data', insert_after='company_address', options='company_address.gstin', print_hide=1) diff --git a/erpnext/regional/report/gst_itemised_sales_register/gst_itemised_sales_register.py b/erpnext/regional/report/gst_itemised_sales_register/gst_itemised_sales_register.py index 40bbae8b55..4e57a52665 100644 --- a/erpnext/regional/report/gst_itemised_sales_register/gst_itemised_sales_register.py +++ b/erpnext/regional/report/gst_itemised_sales_register/gst_itemised_sales_register.py @@ -8,6 +8,7 @@ from erpnext.accounts.report.item_wise_sales_register.item_wise_sales_register i def execute(filters=None): return _execute(filters, additional_table_columns=[ dict(fieldtype='Data', label='Customer GSTIN', width=120), + dict(fieldtype='Data', label='Billing Address GSTIN', width=140), dict(fieldtype='Data', label='Company GSTIN', width=120), dict(fieldtype='Data', label='Place of Supply', width=120), dict(fieldtype='Data', label='Reverse Charge', width=120), @@ -17,6 +18,7 @@ def execute(filters=None): dict(fieldtype='Data', label='HSN Code', width=120) ], additional_query_columns=[ 'customer_gstin', + 'billing_address_gstin', 'company_gstin', 'place_of_supply', 'reverse_charge', diff --git a/erpnext/regional/report/gst_sales_register/gst_sales_register.py b/erpnext/regional/report/gst_sales_register/gst_sales_register.py index 7f6f809276..e79d722b9f 100644 --- a/erpnext/regional/report/gst_sales_register/gst_sales_register.py +++ b/erpnext/regional/report/gst_sales_register/gst_sales_register.py @@ -8,6 +8,7 @@ from erpnext.accounts.report.sales_register.sales_register import _execute def execute(filters=None): return _execute(filters, additional_table_columns=[ dict(fieldtype='Data', label='Customer GSTIN', width=120), + dict(fieldtype='Data', label='Billing Address GSTIN', width=140), dict(fieldtype='Data', label='Company GSTIN', width=120), dict(fieldtype='Data', label='Place of Supply', width=120), dict(fieldtype='Data', label='Reverse Charge', width=120), @@ -16,6 +17,7 @@ def execute(filters=None): dict(fieldtype='Data', label='E-Commerce GSTIN', width=130) ], additional_query_columns=[ 'customer_gstin', + 'billing_address_gstin', 'company_gstin', 'place_of_supply', 'reverse_charge', From a0ba5594f963a2226c5c71b439a6adc76fe0dbc0 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Thu, 28 Sep 2017 11:12:27 +0530 Subject: [PATCH 3/5] [fix] production_order.py via error report --- .../production_order/production_order.py | 46 +++++++++---------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/erpnext/manufacturing/doctype/production_order/production_order.py b/erpnext/manufacturing/doctype/production_order/production_order.py index 11475705db..f04fddfae3 100644 --- a/erpnext/manufacturing/doctype/production_order/production_order.py +++ b/erpnext/manufacturing/doctype/production_order/production_order.py @@ -51,9 +51,9 @@ class ProductionOrder(Document): def validate_sales_order(self): if self.sales_order: so = frappe.db.sql(""" - select so.name, so_item.delivery_date, so.project + select so.name, so_item.delivery_date, so.project from `tabSales Order` so, `tabSales Order Item` so_item - where so.name=%s and so.name=so_item.parent + where so.name=%s and so.name=so_item.parent and so.docstatus = 1 and so_item.item_code=%s """, (self.sales_order, self.production_item), as_dict=1) @@ -112,7 +112,7 @@ class ProductionOrder(Document): allowance_percentage = flt(frappe.db.get_single_value("Manufacturing Settings", "over_production_allowance_percentage")) - + if total_qty > so_qty + (allowance_percentage/100 * so_qty): frappe.throw(_("Cannot produce more Item {0} than Sales Order quantity {1}") .format(self.production_item, so_qty), OverProductionError) @@ -217,27 +217,27 @@ class ProductionOrder(Document): def set_production_order_operations(self): """Fetch operations from BOM and set in 'Production Order'""" self.set('operations', []) - + if not self.bom_no \ or cint(frappe.db.get_single_value("Manufacturing Settings", "disable_capacity_planning")): return - + if self.use_multi_level_bom: bom_list = frappe.get_doc("BOM", self.bom_no).traverse_tree() else: bom_list = [self.bom_no] - + operations = frappe.db.sql(""" - select + select operation, description, workstation, idx, - base_hour_rate as hour_rate, time_in_mins, + base_hour_rate as hour_rate, time_in_mins, "Pending" as status, parent as bom from `tabBOM Operation` where parent in (%s) order by idx """ % ", ".join(["%s"]*len(bom_list)), tuple(bom_list), as_dict=1) - + self.set('operations', operations) self.calculate_time() @@ -277,7 +277,7 @@ class ProductionOrder(Document): timesheet.set('time_logs', []) for i, d in enumerate(self.operations): - + if d.status != 'Completed': self.set_start_end_time_for_workstation(d, i) @@ -370,8 +370,8 @@ class ProductionOrder(Document): self.actual_start_date = None self.actual_end_date = None if self.get("operations"): - self.actual_start_date = min([d.actual_start_time for d in self.get("operations")]) - self.actual_end_date = max([d.actual_end_time for d in self.get("operations")]) + self.actual_start_date = min([d.actual_start_time for d in self.get("operations") if d.actual_start_time]) + self.actual_end_date = max([d.actual_end_time for d in self.get("operations") if d.actual_end_time]) def delete_timesheet(self): for timesheet in frappe.get_all("Timesheet", ["name"], {"production_order": self.name}): @@ -411,18 +411,18 @@ class ProductionOrder(Document): if d.source_warehouse: stock_bin = get_bin(d.item_code, d.source_warehouse) stock_bin.update_reserved_qty_for_production() - + def get_items_and_operations_from_bom(self): self.set_required_items() self.set_production_order_operations() - + return check_if_scrap_warehouse_mandatory(self.bom_no) - + def set_available_qty(self): for d in self.get("required_items"): if d.source_warehouse: d.available_qty_at_source_warehouse = get_latest_stock_qty(d.item_code, d.source_warehouse) - + if self.wip_warehouse: d.available_qty_at_wip_warehouse = get_latest_stock_qty(d.item_code, self.wip_warehouse) @@ -439,7 +439,7 @@ class ProductionOrder(Document): 'required_qty': item.qty, 'source_warehouse': item.source_warehouse or item.default_warehouse }) - + self.set_available_qty() def update_transaferred_qty_for_required_items(self): @@ -463,12 +463,12 @@ class ProductionOrder(Document): def get_item_details(item, project = None): res = frappe.db.sql(""" select stock_uom, description - from `tabItem` - where disabled=0 + from `tabItem` + where disabled=0 and (end_of_life is null or end_of_life='0000-00-00' or end_of_life > %s) and name=%s """, (nowdate(), item), as_dict=1) - + if not res: return {} @@ -611,14 +611,14 @@ def make_new_timesheet(source_name, target_doc=None): @frappe.whitelist() def stop_unstop(production_order, status): """ Called from client side on Stop/Unstop event""" - + if not frappe.has_permission("Production Order", "write"): frappe.throw(_("Not permitted"), frappe.PermissionError) - + pro_order = frappe.get_doc("Production Order", production_order) pro_order.update_status(status) pro_order.update_planned_qty() frappe.msgprint(_("Production Order has been {0}").format(status)) pro_order.notify_update() - + return pro_order.status \ No newline at end of file From 53e19075d1c235b9cc14a47c2bbf726b2dcc7617 Mon Sep 17 00:00:00 2001 From: Makarand Bauskar Date: Thu, 28 Sep 2017 12:30:04 +0530 Subject: [PATCH 4/5] [hotfix] fixes and refactored Quoted Item Comparison report (#10954) --- .../quoted_item_comparison.js | 95 ++++++++++--------- .../quoted_item_comparison.py | 81 ++++++++-------- 2 files changed, 91 insertions(+), 85 deletions(-) diff --git a/erpnext/buying/report/quoted_item_comparison/quoted_item_comparison.js b/erpnext/buying/report/quoted_item_comparison/quoted_item_comparison.js index ad6ea7d7f8..0dc0ee6b7c 100644 --- a/erpnext/buying/report/quoted_item_comparison/quoted_item_comparison.js +++ b/erpnext/buying/report/quoted_item_comparison/quoted_item_comparison.js @@ -2,29 +2,29 @@ // For license information, please see license.txt frappe.query_reports["Quoted Item Comparison"] = { - "filters": [ + filters: [ { - "fieldname": "supplier_quotation", - "label": __("Supplier Quotation"), - "fieldtype": "Link", - "options": "Supplier Quotation", - "default": "", - "get_query": function () { + fieldtype: "Link", + label: __("Supplier Quotation"), + options: "Supplier Quotation", + fieldname: "supplier_quotation", + default: "", + get_query: () => { return { filters: { "docstatus": ["<", 2] } } } }, { - "fieldname": "item", - "label": __("Item"), - "fieldtype": "Link", - "options": "Item", - "default": "", - "reqd": 1, - "get_query": function () { - var quote = frappe.query_report_filters_by_name.supplier_quotation.get_value(); + reqd: 1, + default: "", + options: "Item", + label: __("Item"), + fieldname: "item", + fieldtype: "Link", + get_query: () => { + let quote = frappe.query_report_filters_by_name.supplier_quotation.get_value(); if (quote != "") { return { - query: "erpnext.buying.doctype.quality_inspection.quality_inspection.item_query", + query: "erpnext.stock.doctype.quality_inspection.quality_inspection.item_query", filters: { "from": "Supplier Quotation Item", "parent": quote @@ -39,47 +39,50 @@ frappe.query_reports["Quoted Item Comparison"] = { } } ], - onload: function (report) { + onload: (report) => { // Create a button for setting the default supplier - report.page.add_inner_button(__("Select Default Supplier"), function () { - - var reporter = frappe.query_reports["Quoted Item Comparison"]; + report.page.add_inner_button(__("Select Default Supplier"), () => { + let reporter = frappe.query_reports["Quoted Item Comparison"]; //Always make a new one so that the latest values get updated reporter.make_default_supplier_dialog(report); - report.dialog.show(); - setTimeout(function () { report.dialog.input.focus(); }, 1000); - }, 'Tools'); }, - "make_default_supplier_dialog": function (report) { + make_default_supplier_dialog: (report) => { // Get the name of the item to change - var filters = report.get_values(); - var item_code = filters.item; + if(!report.data) return; + + let filters = report.get_values(); + let item_code = filters.item; // Get a list of the suppliers (with a blank as well) for the user to select - var select_options = ""; - for (let supplier of report.data) { - select_options += supplier.supplier_name + '\n' - } + let suppliers = $.map(report.data, (row, idx)=>{ return row.supplier_name }) // Create a dialog window for the user to pick their supplier - var d = new frappe.ui.Dialog({ + let dialog = new frappe.ui.Dialog({ title: __('Select Default Supplier'), fields: [ - { fieldname: 'supplier', fieldtype: 'Select', label: 'Supplier', reqd: 1, options: select_options }, - { fieldname: 'ok_button', fieldtype: 'Button', label: 'Set Default Supplier' }, + { + reqd: 1, + label: 'Supplier', + fieldtype: 'Link', + options: 'Supplier', + fieldname: 'supplier', + get_query: () => { + return { + filters: { + 'name': ['in', suppliers] + } + } + } + } ] }); - // On the user clicking the ok button - d.fields_dict.ok_button.input.onclick = function () { - var btn = d.fields_dict.ok_button.input; - var v = report.dialog.get_values(); - if (v) { - $(btn).set_working(); - + dialog.set_primary_action("Set Default Supplier", () => { + let values = dialog.get_values(); + if(values) { // Set the default_supplier field of the appropriate Item to the selected supplier frappe.call({ method: "frappe.client.set_value", @@ -87,17 +90,17 @@ frappe.query_reports["Quoted Item Comparison"] = { doctype: "Item", name: item_code, fieldname: "default_supplier", - value: v.supplier, + value: values.supplier, }, - callback: function (r) { - $(btn).done_working(); + freeze: true, + callback: (r) => { frappe.msgprint("Successfully Set Supplier"); - report.dialog.hide(); + dialog.hide(); } }); } - } - report.dialog = d; + }); + dialog.show(); } } diff --git a/erpnext/buying/report/quoted_item_comparison/quoted_item_comparison.py b/erpnext/buying/report/quoted_item_comparison/quoted_item_comparison.py index 44e247e881..c399f3eee2 100644 --- a/erpnext/buying/report/quoted_item_comparison/quoted_item_comparison.py +++ b/erpnext/buying/report/quoted_item_comparison/quoted_item_comparison.py @@ -8,53 +8,55 @@ import frappe def execute(filters=None): qty_list = get_quantity_list(filters.item) - data = get_quote_list(filters.item, qty_list) - columns = get_columns(qty_list) - return columns, data def get_quote_list(item, qty_list): out = [] - if item: - price_data = [] - suppliers = [] - company_currency = frappe.db.get_default("currency") - float_precision = cint(frappe.db.get_default("float_precision")) or 2 - # Get the list of suppliers - for root in frappe.db.sql("""select parent, qty, rate from `tabSupplier Quotation Item` where item_code=%s and docstatus < 2""", item, as_dict=1): - for splr in frappe.db.sql("""SELECT supplier from `tabSupplier Quotation` where name =%s and docstatus < 2""", root.parent, as_dict=1): - ip = frappe._dict({ + if not item: + return [] + + suppliers = [] + price_data = [] + company_currency = frappe.db.get_default("currency") + float_precision = cint(frappe.db.get_default("float_precision")) or 2 + # Get the list of suppliers + for root in frappe.db.sql("""select parent, qty, rate from `tabSupplier Quotation Item` + where item_code=%s and docstatus < 2""", item, as_dict=1): + for splr in frappe.db.sql("""select supplier from `tabSupplier Quotation` + where name =%s and docstatus < 2""", root.parent, as_dict=1): + ip = frappe._dict({ "supplier": splr.supplier, "qty": root.qty, "parent": root.parent, - "rate": root.rate}) - price_data.append(ip) - suppliers.append(splr.supplier) - - #Add a row for each supplier - for root in set(suppliers): - supplier_currency = frappe.db.get_value("Supplier", root, "default_currency") - if supplier_currency: - exchange_rate = get_exchange_rate(supplier_currency, company_currency) - else: - exchange_rate = 1 - - row = frappe._dict({ - "supplier_name": root + "rate": root.rate }) - for col in qty_list: - # Get the quantity for this row - for item_price in price_data: - if str(item_price.qty) == col.key and item_price.supplier == root: - row[col.key] = flt(item_price.rate * exchange_rate, float_precision) - row[col.key + "QUOTE"] = item_price.parent - break - else: - row[col.key] = "" - row[col.key + "QUOTE"] = "" - out.append(row) + price_data.append(ip) + suppliers.append(splr.supplier) + + #Add a row for each supplier + for root in set(suppliers): + supplier_currency = frappe.db.get_value("Supplier", root, "default_currency") + if supplier_currency: + exchange_rate = get_exchange_rate(supplier_currency, company_currency) + else: + exchange_rate = 1 + + row = frappe._dict({ + "supplier_name": root + }) + for col in qty_list: + # Get the quantity for this row + for item_price in price_data: + if str(item_price.qty) == col.key and item_price.supplier == root: + row[col.key] = flt(item_price.rate * exchange_rate, float_precision) + row[col.key + "QUOTE"] = item_price.parent + break + else: + row[col.key] = "" + row[col.key + "QUOTE"] = "" + out.append(row) return out @@ -62,7 +64,8 @@ def get_quantity_list(item): out = [] if item: - qty_list = frappe.db.sql("""select distinct qty from `tabSupplier Quotation Item` where ifnull(item_code,'')=%s and docstatus < 2""", item, as_dict=1) + qty_list = frappe.db.sql("""select distinct qty from `tabSupplier Quotation Item` + where ifnull(item_code,'')=%s and docstatus < 2""", item, as_dict=1) qty_list.sort(reverse=False) for qt in qty_list: col = frappe._dict({ @@ -98,4 +101,4 @@ def get_columns(qty_list): "width": 90 }) - return columns + return columns \ No newline at end of file From ca916a73de456e5770db0f92d57537ca2a490a5b Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Thu, 28 Sep 2017 13:00:48 +0600 Subject: [PATCH 5/5] bumped to version 9.0.3 --- erpnext/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/__init__.py b/erpnext/__init__.py index 636bfe981a..ce16a6e7db 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -4,7 +4,7 @@ import inspect import frappe from erpnext.hooks import regional_overrides -__version__ = '9.0.2' +__version__ = '9.0.3' def get_default_company(user=None): '''Get default company for user'''