diff --git a/erpnext/__init__.py b/erpnext/__init__.py index f91c97aa34..61f819df72 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -2,7 +2,7 @@ from __future__ import unicode_literals import frappe -__version__ = '7.1.28' +__version__ = '7.1.29' def get_default_company(user=None): '''Get default company for user''' diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index 5dce71f9c7..db6d594580 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -403,9 +403,9 @@ class SalesInvoice(SellingController): def validate_warehouse(self): super(SalesInvoice, self).validate_warehouse() - for d in self.get('items'): + for d in self.get_item_list(): if not d.warehouse and frappe.db.get_value("Item", d.item_code, "is_stock_item"): - frappe.throw(_("Warehouse required at Row No {0}").format(d.idx)) + frappe.throw(_("Warehouse required for stock Item {0}").format(d.item_code)) def validate_delivery_note(self): for d in self.get("items"): diff --git a/erpnext/accounts/page/pos/pos.js b/erpnext/accounts/page/pos/pos.js index b291cbd486..c52d4fa28a 100644 --- a/erpnext/accounts/page/pos/pos.js +++ b/erpnext/accounts/page/pos/pos.js @@ -549,26 +549,34 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ } }, - update_qty: function() { + bind_qty_event: function() { var me = this; $(this.wrapper).find(".pos-item-qty").on("change", function(){ var item_code = $(this).parents(".pos-bill-item").attr("data-item-code"); - me.update_qty_rate_against_item_code(item_code, "qty", $(this).val()); + var qty = $(this).val(); + me.update_qty(item_code, qty) }) $(this.wrapper).find("[data-action='increase-qty']").on("click", function(){ var item_code = $(this).parents(".pos-bill-item").attr("data-item-code"); var qty = flt($(this).parents(".pos-bill-item").find('.pos-item-qty').val()) + 1; - me.update_qty_rate_against_item_code(item_code, "qty", qty); + me.update_qty(item_code, qty) }) $(this.wrapper).find("[data-action='decrease-qty']").on("click", function(){ var item_code = $(this).parents(".pos-bill-item").attr("data-item-code"); var qty = flt($(this).parents(".pos-bill-item").find('.pos-item-qty').val()) - 1; - me.update_qty_rate_against_item_code(item_code, "qty", qty); + me.update_qty(item_code, qty) }) }, + + update_qty: function(item_code, qty) { + var me = this; + this.items = this.get_items(item_code); + this.validate_serial_no() + this.update_qty_rate_against_item_code(item_code, "qty", qty); + }, update_rate: function() { var me = this; @@ -723,7 +731,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ refresh: function(update_paid_amount) { var me = this; this.refresh_fields(update_paid_amount); - this.update_qty(); + this.bind_qty_event(); this.update_rate(); this.set_primary_action(); }, @@ -1019,6 +1027,13 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ serial_no = me.item_serial_no[key][0]; } + if(this.items[0].has_serial_no && serial_no == ""){ + this.refresh(); + frappe.throw(__(repl("Error: Serial no is mandatory for item %(item)s", { + 'item': this.items[0].item_code + }))) + } + if(item_code && serial_no){ $.each(this.frm.doc.items, function(index, data){ if(data.item_code == item_code){ @@ -1030,12 +1045,6 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ } }) } - - if(this.items[0].has_serial_no && serial_no == ""){ - frappe.throw(__(repl("Error: Serial no is mandatory for item %(item)s", { - 'item': this.items[0].item_code - }))) - } }, validate_serial_no_qty: function(args, item_code, field, value){ @@ -1047,11 +1056,13 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ frappe.throw(__("Serial no item cannot be a fraction")) } - if(args.serial_no && args.serial_no.split('\n').length != cint(value)){ + if(args.item_code == item_code && args.serial_no && args.serial_no.split('\n').length != cint(value)){ args.qty = 0.0; args.serial_no = '' this.refresh(); - frappe.throw(__("Total nos of serial no is not equal to quantity.")) + frappe.throw(__(repl("Total nos of serial no is not equal to quantity for item %(item)s.", { + 'item': item_code + }))) } }, diff --git a/erpnext/hr/doctype/hr_settings/hr_settings.json b/erpnext/hr/doctype/hr_settings/hr_settings.json index 74c42730f1..e9d209879e 100644 --- a/erpnext/hr/doctype/hr_settings/hr_settings.json +++ b/erpnext/hr/doctype/hr_settings/hr_settings.json @@ -14,6 +14,7 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "employee_settings", "fieldtype": "Section Break", "hidden": 0, @@ -28,6 +29,7 @@ "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 0, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, "search_index": 0, @@ -38,6 +40,7 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "default": "", "description": "Enter retirement age in years", "fieldname": "retirement_age", @@ -55,6 +58,7 @@ "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 0, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, "search_index": 0, @@ -65,6 +69,7 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "default": "Naming Series", "description": "Employee record is created using selected field. ", "fieldname": "emp_created_by", @@ -82,6 +87,7 @@ "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 0, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, "search_index": 0, @@ -92,6 +98,33 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, + "fieldname": "column_break_4", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, "description": "Don't send Employee Birthday Reminders", "fieldname": "stop_birthday_reminders", "fieldtype": "Check", @@ -107,6 +140,7 @@ "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 0, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, "search_index": 0, @@ -117,6 +151,34 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, + "fieldname": "maintain_bill_work_hours_same", + "fieldtype": "Check", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Maintain Billing Hours and Working Hours Same on Timesheet", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, "fieldname": "payroll_settings", "fieldtype": "Section Break", "hidden": 0, @@ -131,6 +193,7 @@ "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 0, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, "search_index": 0, @@ -141,6 +204,7 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "description": "If checked, Total no. of Working Days will include holidays, and this will reduce the value of Salary Per Day", "fieldname": "include_holidays_in_total_working_days", "fieldtype": "Check", @@ -156,6 +220,7 @@ "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 0, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, "search_index": 0, @@ -166,6 +231,7 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "default": "1", "description": "Emails salary slip to employee based on preferred email selected in Employee", "fieldname": "email_salary_slip_to_employee", @@ -183,6 +249,7 @@ "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 0, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, "search_index": 0, @@ -193,6 +260,7 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "max_working_hours_against_timesheet", "fieldtype": "Float", "hidden": 0, @@ -208,6 +276,7 @@ "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 0, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, "search_index": 0, @@ -226,7 +295,7 @@ "issingle": 1, "istable": 0, "max_attachments": 0, - "modified": "2016-09-21 11:28:50.687129", + "modified": "2016-12-21 18:52:03.633251", "modified_by": "Administrator", "module": "HR", "name": "HR Settings", @@ -242,6 +311,7 @@ "export": 0, "if_owner": 0, "import": 0, + "is_custom": 0, "permlevel": 0, "print": 1, "read": 1, diff --git a/erpnext/patches/v7_1/repost_stock_for_deleted_bins_for_merging_items.py b/erpnext/patches/v7_1/repost_stock_for_deleted_bins_for_merging_items.py index d1974d232c..321b0399a6 100644 --- a/erpnext/patches/v7_1/repost_stock_for_deleted_bins_for_merging_items.py +++ b/erpnext/patches/v7_1/repost_stock_for_deleted_bins_for_merging_items.py @@ -4,6 +4,7 @@ from erpnext.stock.stock_balance import repost_stock def execute(): frappe.reload_doc('manufacturing', 'doctype', 'production_order_item') + frappe.reload_doc('manufacturing', 'doctype', 'production_order') modified_items = frappe.db.sql_list(""" select name from `tabItem` diff --git a/erpnext/projects/doctype/timesheet/timesheet.js b/erpnext/projects/doctype/timesheet/timesheet.js index 93f8b68874..01fa160f30 100644 --- a/erpnext/projects/doctype/timesheet/timesheet.js +++ b/erpnext/projects/doctype/timesheet/timesheet.js @@ -136,7 +136,7 @@ calculate_end_time = function(frm, cdt, cdn){ frappe.model.set_value(cdt, cdn, "to_time", d.format(moment.defaultDatetimeFormat)); frm._setting_hours = false; - if(frm.doc.__islocal && !child.billing_hours && child.hours){ + if((frm.doc.__islocal || frm.doc.__onload.maintain_bill_work_hours_same) && child.hours){ frappe.model.set_value(cdt, cdn, "billing_hours", child.hours); } } diff --git a/erpnext/projects/doctype/timesheet/timesheet.py b/erpnext/projects/doctype/timesheet/timesheet.py index 48d3e00213..c3dbcd4180 100644 --- a/erpnext/projects/doctype/timesheet/timesheet.py +++ b/erpnext/projects/doctype/timesheet/timesheet.py @@ -20,6 +20,9 @@ class OverlapError(frappe.ValidationError): pass class OverProductionLoggedError(frappe.ValidationError): pass class Timesheet(Document): + def onload(self): + self.get("__onload").maintain_bill_work_hours_same = frappe.db.get_single_value('HR Settings', 'maintain_bill_work_hours_same') + def validate(self): self.set_employee_name() self.set_status()