diff --git a/erpnext/__init__.py b/erpnext/__init__.py index 49405228e4..75e7361b38 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -5,7 +5,7 @@ import frappe from erpnext.hooks import regional_overrides from frappe.utils import getdate -__version__ = '10.1.40' +__version__ = '10.1.41' def get_default_company(user=None): '''Get default company for user''' diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.js b/erpnext/accounts/doctype/payment_entry/payment_entry.js index c353e5eab7..940a709beb 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.js +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.js @@ -819,28 +819,30 @@ frappe.ui.form.on('Payment Entry Reference', { reference_name: function(frm, cdt, cdn) { var row = locals[cdt][cdn]; - return frappe.call({ - method: "erpnext.accounts.doctype.payment_entry.payment_entry.get_reference_details", - args: { - reference_doctype: row.reference_doctype, - reference_name: row.reference_name, - party_account_currency: frm.doc.payment_type=="Receive" ? - frm.doc.paid_from_account_currency : frm.doc.paid_to_account_currency - }, - callback: function(r, rt) { - if(r.message) { - $.each(r.message, function(field, value) { - frappe.model.set_value(cdt, cdn, field, value); - }) + if (row.reference_name && row.reference_doctype) { + return frappe.call({ + method: "erpnext.accounts.doctype.payment_entry.payment_entry.get_reference_details", + args: { + reference_doctype: row.reference_doctype, + reference_name: row.reference_name, + party_account_currency: frm.doc.payment_type=="Receive" ? + frm.doc.paid_from_account_currency : frm.doc.paid_to_account_currency + }, + callback: function(r, rt) { + if(r.message) { + $.each(r.message, function(field, value) { + frappe.model.set_value(cdt, cdn, field, value); + }) - let allocated_amount = frm.doc.unallocated_amount > row.outstanding_amount ? - row.outstanding_amount : frm.doc.unallocated_amount; + let allocated_amount = frm.doc.unallocated_amount > row.outstanding_amount ? + row.outstanding_amount : frm.doc.unallocated_amount; - frappe.model.set_value(cdt, cdn, 'allocated_amount', allocated_amount); - frm.refresh_fields(); + frappe.model.set_value(cdt, cdn, 'allocated_amount', allocated_amount); + frm.refresh_fields(); + } } - } - }) + }) + } }, allocated_amount: function(frm) { diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json index b940a6a312..a73d607ff2 100755 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json @@ -1239,7 +1239,7 @@ "unique": 0 }, { - "allow_bulk_edit": 0, + "allow_bulk_edit": 1, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -3973,7 +3973,7 @@ "istable": 0, "max_attachments": 0, "menu_index": 0, - "modified": "2018-05-28 02:38:40.310899", + "modified": "2018-07-06 02:38:40.310899", "modified_by": "Administrator", "module": "Accounts", "name": "Purchase Invoice", diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json index a033bb0528..75792f85e0 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json @@ -1459,7 +1459,7 @@ "unique": 0 }, { - "allow_bulk_edit": 0, + "allow_bulk_edit": 1, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -4713,7 +4713,7 @@ "istable": 0, "max_attachments": 0, "menu_index": 0, - "modified": "2018-05-28 04:47:29.879475", + "modified": "2018-07-06 12:09:02.039783", "modified_by": "Administrator", "module": "Accounts", "name": "Sales Invoice", diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index b174d9b224..56767c2241 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -318,6 +318,7 @@ class SalesInvoice(SellingController): if not for_validate and not self.customer: self.customer = pos.customer + self.ignore_pricing_rule = pos.ignore_pricing_rule if pos.get('account_for_change_amount'): self.account_for_change_amount = pos.get('account_for_change_amount') diff --git a/erpnext/accounts/report/budget_variance_report/budget_variance_report.js b/erpnext/accounts/report/budget_variance_report/budget_variance_report.js index 1315b25d75..cf8d5490e6 100644 --- a/erpnext/accounts/report/budget_variance_report/budget_variance_report.js +++ b/erpnext/accounts/report/budget_variance_report/budget_variance_report.js @@ -39,6 +39,12 @@ frappe.query_reports["Budget Variance Report"] = { options: ["Cost Center", "Project"], default: "Cost Center", reqd: 1 - } + }, + { + fieldname: "cost_center", + label: __("Cost Center"), + fieldtype: "Link", + options: "Cost Center" + }, ] } diff --git a/erpnext/accounts/report/budget_variance_report/budget_variance_report.py b/erpnext/accounts/report/budget_variance_report/budget_variance_report.py index bc457aa6f2..c9f913aa61 100644 --- a/erpnext/accounts/report/budget_variance_report/budget_variance_report.py +++ b/erpnext/accounts/report/budget_variance_report/budget_variance_report.py @@ -10,9 +10,13 @@ from erpnext.controllers.trends import get_period_date_ranges, get_period_month_ def execute(filters=None): if not filters: filters = {} - + validate_filters(filters) columns = get_columns(filters) - cost_centers = get_cost_centers(filters) + if filters.get("cost_center"): + cost_centers = [filters.get("cost_center")] + else: + cost_centers = get_cost_centers(filters) + period_month_ranges = get_period_month_ranges(filters["period"], filters["fiscal_year"]) cam_map = get_cost_center_account_month_map(filters) @@ -39,6 +43,10 @@ def execute(filters=None): return columns, data +def validate_filters(filters): + if filters.get("budget_against")=="Project" and filters.get("cost_center"): + frappe.throw(_("Filter based on Cost Center is only applicable if Budget Against is selected as Cost Center")) + def get_columns(filters): columns = [_(filters.get("budget_against")) + ":Link/%s:120"%(filters.get("budget_against")), _("Account") + ":Link/Account:120"] @@ -66,12 +74,16 @@ def get_cost_centers(filters): #Get cost center & target details def get_cost_center_target_details(filters): + cond = "" + if filters.get("cost_center"): + cond += " and b.cost_center='%s'" % frappe.db.escape(filters.get("cost_center")) + return frappe.db.sql(""" select b.{budget_against} as budget_against, b.monthly_distribution, ba.account, ba.budget_amount from `tabBudget` b, `tabBudget Account` ba where b.name=ba.parent and b.docstatus = 1 and b.fiscal_year=%s - and b.budget_against = %s and b.company=%s - """.format(budget_against=filters.get("budget_against").replace(" ", "_").lower()), + and b.budget_against = %s and b.company=%s {cond} + """.format(budget_against=filters.get("budget_against").replace(" ", "_").lower(), cond=cond), (filters.fiscal_year, filters.budget_against, filters.company), as_dict=True) #Get target distribution details of accounts of cost center diff --git a/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py b/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py index ac9f4ce2ab..e6216b5f33 100644 --- a/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py +++ b/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py @@ -53,7 +53,7 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum delivery_note, d.income_account, d.cost_center, d.stock_qty, d.stock_uom ] - row += [d.base_net_rate/d.stock_qty, d.base_net_amount] \ + row += [(d.base_net_rate * d.qty)/d.stock_qty, d.base_net_amount] \ if d.stock_uom != d.uom else [d.base_net_rate, d.base_net_amount] total_tax = 0 @@ -133,7 +133,7 @@ def get_items(filters, additional_query_columns): `tabSales Invoice Item`.stock_uom, `tabSales Invoice Item`.base_net_rate, `tabSales Invoice Item`.base_net_amount, `tabSales Invoice`.customer_name, `tabSales Invoice`.customer_group, `tabSales Invoice Item`.so_detail, - `tabSales Invoice`.update_stock, `tabSales Invoice Item`.uom {0} + `tabSales Invoice`.update_stock, `tabSales Invoice Item`.uom, `tabSales Invoice Item`.qty {0} from `tabSales Invoice`, `tabSales Invoice Item` where `tabSales Invoice`.name = `tabSales Invoice Item`.parent and `tabSales Invoice`.docstatus = 1 %s %s diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.json b/erpnext/buying/doctype/purchase_order/purchase_order.json index 95aca6b02f..baf3b234d0 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.json +++ b/erpnext/buying/doctype/purchase_order/purchase_order.json @@ -1207,7 +1207,7 @@ "unique": 0 }, { - "allow_bulk_edit": 0, + "allow_bulk_edit": 1, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -3355,7 +3355,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2018-02-17 11:00:05.037716", + "modified": "2018-07-06 11:00:05.037716", "modified_by": "Administrator", "module": "Buying", "name": "Purchase Order", diff --git a/erpnext/buying/doctype/supplier_quotation/supplier_quotation.json b/erpnext/buying/doctype/supplier_quotation/supplier_quotation.json index ad47d52d73..bee6553515 100644 --- a/erpnext/buying/doctype/supplier_quotation/supplier_quotation.json +++ b/erpnext/buying/doctype/supplier_quotation/supplier_quotation.json @@ -781,7 +781,7 @@ "unique": 0 }, { - "allow_bulk_edit": 0, + "allow_bulk_edit": 1, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -2549,7 +2549,7 @@ "istable": 0, "max_attachments": 0, "menu_index": 0, - "modified": "2018-05-28 02:45:48.616334", + "modified": "2018-07-06 02:45:48.616334", "modified_by": "Administrator", "module": "Buying", "name": "Supplier Quotation", diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index 58073bca53..22ddf1f3e2 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -131,6 +131,8 @@ class AccountsController(TransactionBase): self.meta.get_label(date_field), self) def validate_due_date(self): + if self.get('is_pos'): return + from erpnext.accounts.party import validate_due_date if self.doctype == "Sales Invoice": if not self.due_date: diff --git a/erpnext/controllers/item_variant.py b/erpnext/controllers/item_variant.py index bf8c88cfb0..5e7ddbbd54 100644 --- a/erpnext/controllers/item_variant.py +++ b/erpnext/controllers/item_variant.py @@ -176,6 +176,14 @@ def create_variant(item, args): @frappe.whitelist() def enqueue_multiple_variant_creation(item, args): # There can be innumerable attribute combinations, enqueue + if isinstance(args, basestring): + variants = json.loads(args) + total_variants = 1 + for key in variants: + total_variants *= len(variants[key]) + if total_variants >= 600: + frappe.msgprint("Please do not create more than 500 items at a time", raise_exception=1) + return frappe.enqueue("erpnext.controllers.item_variant.create_multiple_variants", item=item, args=args, now=frappe.flags.in_test); diff --git a/erpnext/hr/doctype/appraisal/appraisal.js b/erpnext/hr/doctype/appraisal/appraisal.js index 64d6f40e0e..30317d96c0 100644 --- a/erpnext/hr/doctype/appraisal/appraisal.js +++ b/erpnext/hr/doctype/appraisal/appraisal.js @@ -24,6 +24,7 @@ cur_frm.cscript.refresh = function(doc,cdt,cdn){ } cur_frm.cscript.kra_template = function(doc, dt, dn) { + doc.goals = []; erpnext.utils.map_current_doc({ method: "erpnext.hr.doctype.appraisal.appraisal.fetch_appraisal_template", source_name: cur_frm.doc.kra_template, diff --git a/erpnext/hr/doctype/leave_application/leave_application.py b/erpnext/hr/doctype/leave_application/leave_application.py index 8d6db5c437..dd7d19b3fd 100755 --- a/erpnext/hr/doctype/leave_application/leave_application.py +++ b/erpnext/hr/doctype/leave_application/leave_application.py @@ -355,7 +355,7 @@ def get_approvers(doctype, txt, searchfield, start, page_len, filters): @frappe.whitelist() def get_number_of_leave_days(employee, leave_type, from_date, to_date, half_day = None, half_day_date = None): number_of_days = 0 - if half_day == 1: + if cint(half_day) == 1: if from_date == to_date: number_of_days = 0.5 else: diff --git a/erpnext/manufacturing/doctype/bom_update_tool/bom_update_tool.js b/erpnext/manufacturing/doctype/bom_update_tool/bom_update_tool.js index a4b48af5a5..e4b8a20288 100644 --- a/erpnext/manufacturing/doctype/bom_update_tool/bom_update_tool.js +++ b/erpnext/manufacturing/doctype/bom_update_tool/bom_update_tool.js @@ -22,6 +22,21 @@ frappe.ui.form.on('BOM Update Tool', { frm.disable_save(); }, + replace: function(frm) { + if (frm.doc.current_bom && frm.doc.new_bom) { + frappe.call({ + method: "erpnext.manufacturing.doctype.bom_update_tool.bom_update_tool.enqueue_replace_bom", + freeze: true, + args: { + args: { + "current_bom": frm.doc.current_bom, + "new_bom": frm.doc.new_bom + } + } + }); + } + }, + update_latest_price_in_all_boms: function() { frappe.call({ method: "erpnext.manufacturing.doctype.bom_update_tool.bom_update_tool.enqueue_update_cost", diff --git a/erpnext/manufacturing/doctype/bom_update_tool/bom_update_tool.json b/erpnext/manufacturing/doctype/bom_update_tool/bom_update_tool.json index ab63c0b540..b348bb78f3 100644 --- a/erpnext/manufacturing/doctype/bom_update_tool/bom_update_tool.json +++ b/erpnext/manufacturing/doctype/bom_update_tool/bom_update_tool.json @@ -123,7 +123,7 @@ "label": "Replace", "length": 0, "no_copy": 0, - "options": "replace_bom", + "options": "", "permlevel": 0, "print_hide": 0, "print_hide_if_no_value": 0, @@ -208,7 +208,7 @@ "issingle": 1, "istable": 0, "max_attachments": 0, - "modified": "2017-07-31 18:08:05.919276", + "modified": "2018-07-02 16:17:09.014102", "modified_by": "Administrator", "module": "Manufacturing", "name": "BOM Update Tool", diff --git a/erpnext/manufacturing/doctype/bom_update_tool/bom_update_tool.py b/erpnext/manufacturing/doctype/bom_update_tool/bom_update_tool.py index ec948eb5ed..04f9717c08 100644 --- a/erpnext/manufacturing/doctype/bom_update_tool/bom_update_tool.py +++ b/erpnext/manufacturing/doctype/bom_update_tool/bom_update_tool.py @@ -3,9 +3,10 @@ # For license information, please see license.txt from __future__ import unicode_literals -import frappe +import frappe, json from frappe.utils import cstr, flt from frappe import _ +from six import string_types from erpnext.manufacturing.doctype.bom.bom import get_boms_in_bottom_up_order from frappe.model.document import Document @@ -17,12 +18,14 @@ class BOMUpdateTool(Document): updated_bom = [] for bom in bom_list: bom_obj = frappe.get_doc("BOM", bom) + bom_obj.get_doc_before_save() updated_bom = bom_obj.update_cost_and_exploded_items(updated_bom) bom_obj.calculate_cost() bom_obj.update_parent_cost() bom_obj.db_update() - - frappe.msgprint(_("BOM replaced")) + if (getattr(bom_obj.meta, 'track_changes', False) + and bom_obj._doc_before_save and not bom_obj.flags.ignore_version): + bom_obj.save_version() def validate_bom(self): if cstr(self.current_bom) == cstr(self.new_bom): @@ -54,6 +57,14 @@ class BOMUpdateTool(Document): return bom_list +@frappe.whitelist() +def enqueue_replace_bom(args): + if isinstance(args, string_types): + args = json.loads(args) + + frappe.enqueue("erpnext.manufacturing.doctype.bom_update_tool.bom_update_tool.replace_bom", args=args) + frappe.msgprint(_("Queued for replacing the BOM. It may take a few minutes.")) + @frappe.whitelist() def enqueue_update_cost(): frappe.enqueue("erpnext.manufacturing.doctype.bom_update_tool.bom_update_tool.update_cost") @@ -63,6 +74,14 @@ def update_latest_price_in_all_boms(): if frappe.db.get_single_value("Manufacturing Settings", "update_bom_costs_automatically"): update_cost() +def replace_bom(args): + args = frappe._dict(args) + + doc = frappe.get_doc("BOM Update Tool") + doc.current_bom = args.current_bom + doc.new_bom = args.new_bom + doc.replace_bom() + def update_cost(): bom_list = get_boms_in_bottom_up_order() for bom in bom_list: diff --git a/erpnext/non_profit/doctype/membership/membership.json b/erpnext/non_profit/doctype/membership/membership.json index 42e084d54f..694a4fafea 100644 --- a/erpnext/non_profit/doctype/membership/membership.json +++ b/erpnext/non_profit/doctype/membership/membership.json @@ -15,6 +15,7 @@ "fields": [ { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -42,10 +43,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -73,10 +76,12 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -102,10 +107,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -133,15 +140,17 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, "columns": 0, - "fieldname": "membership_validaty_section", + "fieldname": "membership_validity_section", "fieldtype": "Section Break", "hidden": 0, "ignore_user_permissions": 0, @@ -150,7 +159,7 @@ "in_global_search": 0, "in_list_view": 0, "in_standard_filter": 0, - "label": "membership validaty section", + "label": "Validity", "length": 0, "no_copy": 0, "permlevel": 0, @@ -163,10 +172,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -193,10 +204,12 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -223,10 +236,12 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -252,10 +267,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -282,10 +299,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -312,10 +331,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -342,10 +363,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -373,10 +396,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -403,6 +428,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 } ], @@ -416,7 +442,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2017-12-05 07:02:56.859408", + "modified": "2018-06-26 19:23:17.911121", "modified_by": "Administrator", "module": "Non Profit", "name": "Membership", @@ -425,7 +451,6 @@ "permissions": [ { "amend": 0, - "apply_user_permissions": 0, "cancel": 0, "create": 1, "delete": 1, @@ -445,7 +470,6 @@ }, { "amend": 0, - "apply_user_permissions": 0, "cancel": 0, "create": 1, "delete": 1, @@ -472,5 +496,6 @@ "sort_field": "modified", "sort_order": "DESC", "track_changes": 1, - "track_seen": 0 -} \ No newline at end of file + "track_seen": 0, + "track_views": 0 +} diff --git a/erpnext/projects/doctype/project/project.py b/erpnext/projects/doctype/project/project.py index 44b0c00e65..1f4bd005c6 100644 --- a/erpnext/projects/doctype/project/project.py +++ b/erpnext/projects/doctype/project/project.py @@ -4,7 +4,7 @@ from __future__ import unicode_literals import frappe -from frappe.utils import flt, getdate, get_url +from frappe.utils import flt, getdate, get_url, now from frappe import _ from frappe.model.document import Document @@ -60,6 +60,7 @@ class Project(Document): self.validate_weights() self.sync_tasks() self.tasks = [] + self.load_tasks() self.send_welcome_email() def validate_project_name(self): @@ -83,36 +84,68 @@ class Project(Document): """sync tasks and remove table""" if self.flags.dont_sync_tasks: return task_names = [] + + existing_task_data = {} + for d in frappe.get_all('Project Task', + fields = ["title", "status", "start_date", "end_date", "description", "task_weight", "task_id"], + filters = {'parent': self.name}): + existing_task_data.setdefault(d.task_id, d) + for t in self.tasks: if t.task_id: task = frappe.get_doc("Task", t.task_id) else: task = frappe.new_doc("Task") task.project = self.name - task.update({ - "subject": t.title, - "status": t.status, - "exp_start_date": t.start_date, - "exp_end_date": t.end_date, - "description": t.description, - "task_weight": t.task_weight - }) - self.map_custom_fields(t, task) + if not t.task_id or self.is_row_updated(t, existing_task_data): + task.update({ + "subject": t.title, + "status": t.status, + "exp_start_date": t.start_date, + "exp_end_date": t.end_date, + "description": t.description, + "task_weight": t.task_weight + }) - task.flags.ignore_links = True - task.flags.from_project = True - task.flags.ignore_feed = True - task.save(ignore_permissions = True) - task_names.append(task.name) + self.map_custom_fields(t, task) + + task.flags.ignore_links = True + task.flags.from_project = True + task.flags.ignore_feed = True + + if t.task_id: + task.update({ + "modified_by": frappe.session.user, + "modified": now() + }) + + task.validate() + task.db_update() + else: + task.save(ignore_permissions = True) + task_names.append(task.name) + else: + task_names.append(task.name) # delete for t in frappe.get_all("Task", ["name"], {"project": self.name, "name": ("not in", task_names)}): frappe.delete_doc("Task", t.name) + def update_costing_and_percentage_complete(self): self.update_percent_complete() self.update_costing() + def is_row_updated(self, row, existing_task_data): + if self.get("__islocal") or not existing_task_data: return True + + d = existing_task_data.get(row.task_id) + + if (d and (row.title != d.title or row.status != d.status + or getdate(row.start_date) != getdate(d.start_date) or getdate(row.end_date) != getdate(d.end_date) + or row.description != d.description or row.task_weight != d.task_weight)): + return True + def map_custom_fields(self, source, target): project_task_custom_fields = frappe.get_all("Custom Field", {"dt": "Project Task"}, "fieldname") @@ -207,6 +240,9 @@ class Project(Document): self.total_billed_amount = total_billed_amount and total_billed_amount[0][0] or 0 + def after_rename(self, old_name, new_name, merge=False): + if old_name == self.copied_from: + frappe.db.set_value('Project', new_name, 'copied_from', new_name) def send_welcome_email(self): url = get_url("/project/?name={0}".format(self.name)) @@ -227,8 +263,7 @@ class Project(Document): user.welcome_email_sent=1 def on_update(self): - self.load_tasks() - self.sync_tasks() + self.update_costing_and_percentage_complete() self.update_dependencies_on_duplicated_project() def update_dependencies_on_duplicated_project(self): @@ -251,9 +286,7 @@ class Project(Document): continue name = _task.name - depends_on_tasks = _task.depends_on_tasks - depends_on_tasks = [x for x in depends_on_tasks.split(',') if x] dependency_map[task.title] = [ x['subject'] for x in frappe.get_list( 'Task Depends On', {"parent": name}, ['subject'])] @@ -264,7 +297,8 @@ class Project(Document): for dt in value: dt_name = frappe.db.get_value('Task', {"subject": dt, "project": self.name }) task_doc.append('depends_on', {"task": dt_name}) - task_doc.save() + + task_doc.update_db() def get_timeline_data(doctype, name): '''Return timeline for attendance''' diff --git a/erpnext/projects/doctype/project_task/project_task.json b/erpnext/projects/doctype/project_task/project_task.json index 79790e57b0..d215d63bc9 100644 --- a/erpnext/projects/doctype/project_task/project_task.json +++ b/erpnext/projects/doctype/project_task/project_task.json @@ -61,7 +61,7 @@ "label": "Status", "length": 0, "no_copy": 1, - "options": "Open\nWorking\nPending Review\nClosed\nCancelled", + "options": "Open\nWorking\nPending Review\nOverdue\nClosed\nCancelled", "permlevel": 0, "precision": "", "print_hide": 0, @@ -371,7 +371,7 @@ "remember_last_selected_value": 1, "report_hide": 0, "reqd": 0, - "search_index": 0, + "search_index": 1, "set_only_once": 0, "unique": 0 } @@ -386,7 +386,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2017-12-19 14:49:15.886339", + "modified": "2018-07-05 19:34:31.204454", "modified_by": "Administrator", "module": "Projects", "name": "Project Task", diff --git a/erpnext/projects/doctype/task/task.json b/erpnext/projects/doctype/task/task.json index 8e72d0339e..cf524da486 100644 --- a/erpnext/projects/doctype/task/task.json +++ b/erpnext/projects/doctype/task/task.json @@ -38,7 +38,7 @@ "remember_last_selected_value": 0, "report_hide": 0, "reqd": 1, - "search_index": 0, + "search_index": 1, "set_only_once": 0, "unique": 0 }, @@ -70,7 +70,7 @@ "remember_last_selected_value": 1, "report_hide": 0, "reqd": 0, - "search_index": 0, + "search_index": 1, "set_only_once": 0, "unique": 0 }, @@ -1214,7 +1214,7 @@ "istable": 0, "max_attachments": 5, "menu_index": 0, - "modified": "2017-11-10 18:37:19.660293", + "modified": "2018-06-26 11:46:06.678115", "modified_by": "Administrator", "module": "Projects", "name": "Task", diff --git a/erpnext/regional/united_arab_emirates/setup.py b/erpnext/regional/united_arab_emirates/setup.py index aa27d6159d..3c8328b107 100644 --- a/erpnext/regional/united_arab_emirates/setup.py +++ b/erpnext/regional/united_arab_emirates/setup.py @@ -17,7 +17,7 @@ def setup(company=None, patch=True): def make_custom_fields(): invoice_fields = [ dict(fieldname='vat_section', label='VAT Details', fieldtype='Section Break', - insert_after='select_print_heading', print_hide=1, collapsible=1), + insert_after='group_same_items', print_hide=1, collapsible=1), dict(fieldname='permit_no', label='Permit Number', fieldtype='Data', insert_after='vat_section', print_hide=1), dict(fieldname='reverse_charge_applicable', label='Reverse Charge Applicable', diff --git a/erpnext/selling/doctype/quotation/quotation.js b/erpnext/selling/doctype/quotation/quotation.js index 081d4dbe9a..695a410f15 100644 --- a/erpnext/selling/doctype/quotation/quotation.js +++ b/erpnext/selling/doctype/quotation/quotation.js @@ -186,7 +186,7 @@ cur_frm.cscript['Declare Order Lost'] = function(){ return cur_frm.call({ method: "declare_order_lost", doc: cur_frm.doc, - args: args.reason, + args: args, callback: function(r) { if(r.exc) { frappe.msgprint(__("There were errors.")); diff --git a/erpnext/selling/doctype/quotation/quotation.json b/erpnext/selling/doctype/quotation/quotation.json index 61973d6a84..f38156c95f 100644 --- a/erpnext/selling/doctype/quotation/quotation.json +++ b/erpnext/selling/doctype/quotation/quotation.json @@ -1076,7 +1076,7 @@ "unique": 0 }, { - "allow_bulk_edit": 0, + "allow_bulk_edit": 1, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -2911,7 +2911,7 @@ "istable": 0, "max_attachments": 1, "menu_index": 0, - "modified": "2018-05-28 03:23:15.354674", + "modified": "2018-07-06 03:23:15.354674", "modified_by": "Administrator", "module": "Selling", "name": "Quotation", diff --git a/erpnext/selling/doctype/quotation/quotation.py b/erpnext/selling/doctype/quotation/quotation.py index ad06bd2ddb..709c0694a6 100644 --- a/erpnext/selling/doctype/quotation/quotation.py +++ b/erpnext/selling/doctype/quotation/quotation.py @@ -70,10 +70,10 @@ class Quotation(SellingController): opp.status = None opp.set_status(update=True) - def declare_order_lost(self, arg): + def declare_order_lost(self, reason): if not self.has_sales_order(): frappe.db.set(self, 'status', 'Lost') - frappe.db.set(self, 'order_lost_reason', arg) + frappe.db.set(self, 'order_lost_reason', reason) self.update_opportunity() self.update_lead() else: diff --git a/erpnext/selling/doctype/sales_order/sales_order.json b/erpnext/selling/doctype/sales_order/sales_order.json index f302c1cd1c..b0437e30c6 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.json +++ b/erpnext/selling/doctype/sales_order/sales_order.json @@ -1131,7 +1131,7 @@ "unique": 0 }, { - "allow_bulk_edit": 0, + "allow_bulk_edit": 1, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -3529,7 +3529,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2018-01-12 15:56:12.483019", + "modified": "2018-07-06 15:56:12.483019", "modified_by": "Administrator", "module": "Selling", "name": "Sales Order", diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.json b/erpnext/stock/doctype/delivery_note/delivery_note.json index e3777833b4..325b234267 100644 --- a/erpnext/stock/doctype/delivery_note/delivery_note.json +++ b/erpnext/stock/doctype/delivery_note/delivery_note.json @@ -1253,7 +1253,7 @@ "unique": 0 }, { - "allow_bulk_edit": 0, + "allow_bulk_edit": 1, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -3731,7 +3731,7 @@ "istable": 0, "max_attachments": 0, "menu_index": 0, - "modified": "2018-05-28 03:03:35.035396", + "modified": "2018-07-06 03:03:35.035396", "modified_by": "Administrator", "module": "Stock", "name": "Delivery Note", diff --git a/erpnext/stock/doctype/material_request/material_request.json b/erpnext/stock/doctype/material_request/material_request.json index ba373453be..7ba139ce66 100644 --- a/erpnext/stock/doctype/material_request/material_request.json +++ b/erpnext/stock/doctype/material_request/material_request.json @@ -294,7 +294,7 @@ "unique": 0 }, { - "allow_bulk_edit": 0, + "allow_bulk_edit": 1, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -716,7 +716,7 @@ "istable": 0, "max_attachments": 0, "menu_index": 0, - "modified": "2017-10-05 18:24:17.148782", + "modified": "2018-07-06 18:24:17.148782", "modified_by": "Administrator", "module": "Stock", "name": "Material Request", diff --git a/erpnext/stock/doctype/material_request_item/material_request_item.py b/erpnext/stock/doctype/material_request_item/material_request_item.py index 16f007f6a2..6c6ecfea83 100644 --- a/erpnext/stock/doctype/material_request_item/material_request_item.py +++ b/erpnext/stock/doctype/material_request_item/material_request_item.py @@ -6,10 +6,12 @@ from __future__ import unicode_literals import frappe +from erpnext.controllers.print_settings import print_settings_for_item_table from frappe.model.document import Document class MaterialRequestItem(Document): - pass + def __setup__(self): + print_settings_for_item_table(self) def on_doctype_update(): frappe.db.add_index("Material Request Item", ["item_code", "warehouse"]) \ No newline at end of file diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json index 3f4337f353..15372c15d9 100755 --- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json +++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json @@ -1038,7 +1038,7 @@ "unique": 0 }, { - "allow_bulk_edit": 0, + "allow_bulk_edit": 1, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -3301,7 +3301,7 @@ "istable": 0, "max_attachments": 0, "menu_index": 0, - "modified": "2018-05-28 02:59:59.609643", + "modified": "2018-07-06 02:59:59.609643", "modified_by": "Administrator", "module": "Stock", "name": "Purchase Receipt", diff --git a/erpnext/templates/pages/order.html b/erpnext/templates/pages/order.html index 3a6d2254fb..79801890aa 100644 --- a/erpnext/templates/pages/order.html +++ b/erpnext/templates/pages/order.html @@ -20,7 +20,7 @@