Merge branch 'hotfix'
diff --git a/erpnext/__init__.py b/erpnext/__init__.py
index 636bfe9..ce16a6e 100644
--- a/erpnext/__init__.py
+++ b/erpnext/__init__.py
@@ -4,7 +4,7 @@
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'''
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 ad6ea7d..0dc0ee6 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 @@
}
}
],
- 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 @@
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 44e247e..c399f3e 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 @@
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 @@
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 @@
"width": 90
})
- return columns
+ return columns
\ No newline at end of file
diff --git a/erpnext/manufacturing/doctype/production_order/production_order.py b/erpnext/manufacturing/doctype/production_order/production_order.py
index 1147570..f04fddf 100644
--- a/erpnext/manufacturing/doctype/production_order/production_order.py
+++ b/erpnext/manufacturing/doctype/production_order/production_order.py
@@ -51,9 +51,9 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
'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 @@
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 @@
@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
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index c6bd9ec..95adfd8 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -434,7 +434,7 @@
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_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 0000000..24e2040
--- /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 2798cfb..fb40e32 100644
--- a/erpnext/regional/india/setup.py
+++ b/erpnext/regional/india/setup.py
@@ -113,12 +113,15 @@
]
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 40bbae8..4e57a52 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 @@
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 @@
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 7f6f809..e79d722 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 @@
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 @@
dict(fieldtype='Data', label='E-Commerce GSTIN', width=130)
], additional_query_columns=[
'customer_gstin',
+ 'billing_address_gstin',
'company_gstin',
'place_of_supply',
'reverse_charge',
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 fd6b8c9..d74f1f0 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