diff --git a/erpnext/__init__.py b/erpnext/__init__.py index 533739595b..9845dd2c68 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -2,7 +2,7 @@ from __future__ import unicode_literals import frappe -__version__ = '7.1.7' +__version__ = '7.1.8' def get_default_company(user=None): '''Get default company for user''' diff --git a/erpnext/accounts/doctype/gl_entry/gl_entry.py b/erpnext/accounts/doctype/gl_entry/gl_entry.py index b052e4d141..fddabcb918 100644 --- a/erpnext/accounts/doctype/gl_entry/gl_entry.py +++ b/erpnext/accounts/doctype/gl_entry/gl_entry.py @@ -46,19 +46,22 @@ class GLEntry(Document): account_type = frappe.db.get_value("Account", self.account, "account_type") if not (self.party_type and self.party): if account_type == "Receivable": - frappe.throw(_("Customer is required against Receivable account {0}").format(self.account)) + frappe.throw(_("{0} {1}: Customer is required against Receivable account {2}") + .format(self.voucher_type, self.voucher_no, self.account)) elif account_type == "Payable": - frappe.throw(_("Supplier is required against Payable account {0}").format(self.account)) + frappe.throw(_("{0} {1}: Supplier is required against Payable account {2}") + .format(self.voucher_type, self.voucher_no, self.account)) # Zero value transaction is not allowed if not (flt(self.debit) or flt(self.credit)): - frappe.throw(_("Either debit or credit amount is required for {0}").format(self.account)) + frappe.throw(_("{0} {1}: Either debit or credit amount is required for {2}") + .format(self.voucher_type, self.voucher_no, self.account)) def pl_must_have_cost_center(self): if frappe.db.get_value("Account", self.account, "report_type") == "Profit and Loss": if not self.cost_center and self.voucher_type != 'Period Closing Voucher': - frappe.throw(_("Cost Center is required for 'Profit and Loss' account {0}. Please set up a default Cost Center for the Company.") - .format(self.account)) + frappe.throw(_("{0} {1}: Cost Center is required for 'Profit and Loss' account {2}. Please set up a default Cost Center for the Company.") + .format(self.voucher_type, self.voucher_no, self.account)) else: if self.cost_center: self.cost_center = None @@ -68,7 +71,8 @@ class GLEntry(Document): def check_pl_account(self): if self.is_opening=='Yes' and \ frappe.db.get_value("Account", self.account, "report_type")=="Profit and Loss": - frappe.throw(_("'Profit and Loss' type account {0} not allowed in Opening Entry").format(self.account)) + frappe.throw(_("{0} {1}: 'Profit and Loss' type account {2} not allowed in Opening Entry") + .format(self.voucher_type, self.voucher_no, self.account)) def validate_account_details(self, adv_adj): """Account must be ledger, active and not freezed""" @@ -77,13 +81,16 @@ class GLEntry(Document): from tabAccount where name=%s""", self.account, as_dict=1)[0] if ret.is_group==1: - frappe.throw(_("Account {0} cannot be a Group").format(self.account)) + frappe.throw(_("{0} {1}: Account {2} cannot be a Group") + .format(self.voucher_type, self.voucher_no, self.account)) if ret.docstatus==2: - frappe.throw(_("Account {0} is inactive").format(self.account)) + frappe.throw(_("{0} {1}: Account {2} is inactive") + .format(self.voucher_type, self.voucher_no, self.account)) if ret.company != self.company: - frappe.throw(_("Account {0} does not belong to Company {1}").format(self.account, self.company)) + frappe.throw(_("{0} {1}: Account {2} does not belong to Company {3}") + .format(self.voucher_type, self.voucher_no, self.account, self.company)) def validate_cost_center(self): if not hasattr(self, "cost_center_company"): @@ -97,7 +104,8 @@ class GLEntry(Document): return self.cost_center_company[self.cost_center] if self.cost_center and _get_cost_center_company() != self.company: - frappe.throw(_("Cost Center {0} does not belong to Company {1}").format(self.cost_center, self.company)) + frappe.throw(_("{0} {1}: Cost Center {2} does not belong to Company {3}") + .format(self.voucher_type, self.voucher_no, self.cost_center, self.company)) def validate_party(self): validate_party_frozen_disabled(self.party_type, self.party) @@ -110,8 +118,9 @@ class GLEntry(Document): self.account_currency = company_currency if account_currency != self.account_currency: - frappe.throw(_("Accounting Entry for {0} can only be made in currency: {1}") - .format(self.account, (account_currency or company_currency)), InvalidAccountCurrency) + frappe.throw(_("{0} {1}: Accounting Entry for {2} can only be made in currency: {3}") + .format(self.voucher_type, self.voucher_no, self.account, + (account_currency or company_currency)), InvalidAccountCurrency) if self.party_type and self.party: validate_party_gle_currency(self.party_type, self.party, self.company, self.account_currency) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js index 47f1a5c1c3..9b4306e68d 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js @@ -483,20 +483,22 @@ frappe.ui.form.on('Sales Invoice', { frappe.ui.form.on('Sales Invoice Timesheet', { time_sheet: function(frm, cdt, cdn){ var d = locals[cdt][cdn]; - frappe.call({ - method: "erpnext.projects.doctype.timesheet.timesheet.get_timesheet_data", - args: { - 'name': d.time_sheet, - 'project': frm.doc.project || null - }, - callback: function(r, rt) { - if(r.message){ - data = r.message; - frappe.model.set_value(cdt, cdn, "billing_hours", data.billing_hours); - frappe.model.set_value(cdt, cdn, "billing_amount", data.billing_amount); - frappe.model.set_value(cdt, cdn, "timesheet_detail", data.timesheet_detail); + if(d.time_sheet) { + frappe.call({ + method: "erpnext.projects.doctype.timesheet.timesheet.get_timesheet_data", + args: { + 'name': d.time_sheet, + 'project': frm.doc.project || null + }, + callback: function(r, rt) { + if(r.message){ + data = r.message; + frappe.model.set_value(cdt, cdn, "billing_hours", data.billing_hours); + frappe.model.set_value(cdt, cdn, "billing_amount", data.billing_amount); + frappe.model.set_value(cdt, cdn, "timesheet_detail", data.timesheet_detail); + } } - } - }) + }) + } } }) diff --git a/erpnext/accounts/page/pos/pos.js b/erpnext/accounts/page/pos/pos.js index 4c13fe3720..32e9b3ab60 100644 --- a/erpnext/accounts/page/pos/pos.js +++ b/erpnext/accounts/page/pos/pos.js @@ -988,6 +988,10 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ item.margin_rate_or_amount = pricing_rule[0].margin_rate_or_amount; item.discount_percentage = pricing_rule[0].discount_percentage || 0.0; me.apply_pricing_rule_on_item(item) + } else if(item.discount_percentage > 0 || item.margin_rate_or_amount > 0) { + item.margin_rate_or_amount = 0.0; + item.discount_percentage = 0.0; + me.apply_pricing_rule_on_item(item) } }) }, diff --git a/erpnext/hr/doctype/salary_slip/salary_slip.json b/erpnext/hr/doctype/salary_slip/salary_slip.json index 1a5ccdcda4..fb922a1037 100644 --- a/erpnext/hr/doctype/salary_slip/salary_slip.json +++ b/erpnext/hr/doctype/salary_slip/salary_slip.json @@ -133,7 +133,7 @@ "collapsible": 0, "columns": 0, "fieldname": "department", - "fieldtype": "Link", + "fieldtype": "Read Only", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, @@ -145,11 +145,11 @@ "no_copy": 0, "oldfieldname": "department", "oldfieldtype": "Link", - "options": "Department", + "options": "employee.department", "permlevel": 0, "print_hide": 0, "print_hide_if_no_value": 0, - "read_only": 1, + "read_only": 0, "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, @@ -162,8 +162,9 @@ "bold": 0, "collapsible": 0, "columns": 0, + "depends_on": "eval:doc.designation", "fieldname": "designation", - "fieldtype": "Link", + "fieldtype": "Read Only", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, @@ -175,11 +176,11 @@ "no_copy": 0, "oldfieldname": "designation", "oldfieldtype": "Link", - "options": "Designation", + "options": "employee.designation", "permlevel": 0, "print_hide": 0, "print_hide_if_no_value": 0, - "read_only": 1, + "read_only": 0, "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, @@ -193,7 +194,7 @@ "collapsible": 0, "columns": 0, "fieldname": "branch", - "fieldtype": "Link", + "fieldtype": "Read Only", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, @@ -205,11 +206,11 @@ "no_copy": 0, "oldfieldname": "branch", "oldfieldtype": "Link", - "options": "Branch", + "options": "employee.branch", "permlevel": 0, "print_hide": 0, "print_hide_if_no_value": 0, - "read_only": 1, + "read_only": 0, "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 5c355fdf87..04e5bfce6a 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -340,7 +340,9 @@ erpnext.patches.v7_0.update_status_of_zero_amount_sales_order erpnext.patches.v7_1.add_field_for_task_dependent erpnext.patches.v7_0.repost_bin_qty_and_item_projected_qty erpnext.patches.v7_1.set_prefered_contact_email -execute:frappe.db.sql("update `tabSingles` set value = 1 where field = 'unlink_payment_on_cancellation_of_invoice' and doctype = 'Accounts Settings'") +execute:frappe.reload_doc('accounts', 'doctype', 'accounts_settings') +execute:frappe.db.set_value("Accounts Settings", "Accounts Settings", "unlink_payment_on_cancellation_of_invoice", 0) execute:frappe.db.sql("update `tabStock Entry` set total_amount = null where purpose in('Repack', 'Manufacture')") erpnext.patches.v7_1.save_stock_settings -erpnext.patches.v7_0.repost_gle_for_pi_with_update_stock #2016-11-01 \ No newline at end of file +erpnext.patches.v7_0.repost_gle_for_pi_with_update_stock #2016-11-01 +erpnext.patches.v7_1.add_account_user_role_for_timesheet diff --git a/erpnext/patches/v5_1/rename_roles.py b/erpnext/patches/v5_1/rename_roles.py index 452c800944..26208aa1e5 100644 --- a/erpnext/patches/v5_1/rename_roles.py +++ b/erpnext/patches/v5_1/rename_roles.py @@ -5,5 +5,5 @@ def execute(): frappe.rename_doc("Role", "Material User", "Stock User") if not frappe.db.exists("Role", "Stock Manager"): frappe.rename_doc("Role", "Material Manager", "Stock Manager") - if not frappe.db.exists("Role", "Stock Manager"): + if not frappe.db.exists("Role", "Item Manager"): frappe.rename_doc("Role", "Material Master Manager", "Item Manager") diff --git a/erpnext/patches/v7_0/convert_timelog_to_timesheet.py b/erpnext/patches/v7_0/convert_timelog_to_timesheet.py index 2ca72b4b48..9894c2a6d3 100644 --- a/erpnext/patches/v7_0/convert_timelog_to_timesheet.py +++ b/erpnext/patches/v7_0/convert_timelog_to_timesheet.py @@ -3,11 +3,12 @@ from erpnext.manufacturing.doctype.production_order.production_order \ import make_timesheet, add_timesheet_detail def execute(): + frappe.reload_doc('projects', 'doctype', 'task') frappe.reload_doc('projects', 'doctype', 'timesheet') if not frappe.db.table_exists("Time Log"): return - for data in frappe.db.sql("select * from `tabTime Log` where docstatus < 2", as_dict=1): + for data in frappe.db.sql("select * from `tabTime Log`", as_dict=1): if data.task: company = frappe.db.get_value("Task", data.task, "company") elif data.production_order: @@ -18,7 +19,10 @@ def execute(): time_sheet = make_timesheet(data.production_order) args = get_timelog_data(data) add_timesheet_detail(time_sheet, args) - time_sheet.docstatus = data.docstatus + if data.docstatus == 2: + time_sheet.docstatus = 0 + else: + time_sheet.docstatus = data.docstatus time_sheet.employee = data.employee time_sheet.note = data.note time_sheet.company = company @@ -38,6 +42,10 @@ def execute(): d.db_set("docstatus", 1) time_sheet.update_production_order(time_sheet.name) time_sheet.update_task_and_project() + if data.docstatus == 2: + time_sheet.db_set("docstatus", 2) + for d in time_sheet.get("time_logs"): + d.db_set("docstatus", 2) def get_timelog_data(data): return { diff --git a/erpnext/patches/v7_1/add_account_user_role_for_timesheet.py b/erpnext/patches/v7_1/add_account_user_role_for_timesheet.py new file mode 100644 index 0000000000..7372b0cc5f --- /dev/null +++ b/erpnext/patches/v7_1/add_account_user_role_for_timesheet.py @@ -0,0 +1,31 @@ +# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe + +def execute(): + if not frappe.db.get_value('DocPerm', {'parent': 'Timesheet', 'role': 'Accounts User', 'permlevel': 1}): + doc = frappe.get_doc('DocType', 'Timesheet') + doc.append('permissions', { + 'role': "Accounts User", + 'permlevel': 0, + 'read': 1, + 'write': 1, + 'create': 1, + 'delete': 1, + 'submit': 1, + 'cancel': 1, + 'amend': 1, + 'report': 1, + 'email': 1 + }) + + doc.append('permissions', { + 'role': "Accounts User", + 'permlevel': 1, + 'read': 1, + 'write': 1 + }) + + doc.save(ignore_permissions=True) \ No newline at end of file diff --git a/erpnext/projects/doctype/timesheet/timesheet.json b/erpnext/projects/doctype/timesheet/timesheet.json index 3f7ee48838..751b7931e1 100644 --- a/erpnext/projects/doctype/timesheet/timesheet.json +++ b/erpnext/projects/doctype/timesheet/timesheet.json @@ -946,48 +946,6 @@ "submit": 1, "write": 1 }, - { - "amend": 1, - "apply_user_permissions": 0, - "cancel": 1, - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "is_custom": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Accounts User", - "set_user_permissions": 0, - "share": 1, - "submit": 1, - "write": 1 - }, - { - "amend": 0, - "apply_user_permissions": 0, - "cancel": 0, - "create": 0, - "delete": 0, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "is_custom": 0, - "permlevel": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "Accounts User", - "set_user_permissions": 0, - "share": 1, - "submit": 0, - "write": 1 - }, { "amend": 0, "apply_user_permissions": 0, @@ -1008,6 +966,48 @@ "share": 0, "submit": 0, "write": 1 + }, + { + "amend": 1, + "apply_user_permissions": 0, + "cancel": 1, + "create": 1, + "delete": 1, + "email": 1, + "export": 0, + "if_owner": 0, + "import": 0, + "is_custom": 0, + "permlevel": 0, + "print": 0, + "read": 1, + "report": 1, + "role": "Accounts User", + "set_user_permissions": 0, + "share": 0, + "submit": 1, + "write": 1 + }, + { + "amend": 0, + "apply_user_permissions": 0, + "cancel": 0, + "create": 0, + "delete": 0, + "email": 0, + "export": 0, + "if_owner": 0, + "import": 0, + "is_custom": 0, + "permlevel": 1, + "print": 0, + "read": 1, + "report": 0, + "role": "Accounts User", + "set_user_permissions": 0, + "share": 0, + "submit": 0, + "write": 1 } ], "quick_entry": 0, diff --git a/erpnext/projects/doctype/timesheet/timesheet.py b/erpnext/projects/doctype/timesheet/timesheet.py index 9e32b528be..02e5f18f84 100644 --- a/erpnext/projects/doctype/timesheet/timesheet.py +++ b/erpnext/projects/doctype/timesheet/timesheet.py @@ -322,18 +322,7 @@ def make_sales_invoice(source_name, target=None): @frappe.whitelist() def make_salary_slip(source_name, target_doc=None): target = frappe.new_doc("Salary Slip") - set_missing_values(source_name, target) - - target.append("timesheets", get_mapped_doc("Timesheet", source_name, { - "Timesheet": { - "doctype": "Salary Slip Timesheet", - "field_map": { - "total_hours": "working_hours", - "name": "time_sheet" - }, - } - })) - + set_missing_values(source_name, target) target.run_method("get_emp_and_leave_details") return target diff --git a/erpnext/selling/doctype/sales_order/sales_order.json b/erpnext/selling/doctype/sales_order/sales_order.json index 588ed9cd20..593331103f 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.json +++ b/erpnext/selling/doctype/sales_order/sales_order.json @@ -386,7 +386,7 @@ "in_standard_filter": 0, "label": "Customer's Purchase Order", "length": 0, - "no_copy": 0, + "no_copy": 1, "oldfieldname": "po_no", "oldfieldtype": "Data", "permlevel": 0, @@ -418,7 +418,7 @@ "in_standard_filter": 0, "label": "Customer's Purchase Order Date", "length": 0, - "no_copy": 0, + "no_copy": 1, "oldfieldname": "po_date", "oldfieldtype": "Date", "permlevel": 0,