Merge branch 'hotfix'
diff --git a/erpnext/__init__.py b/erpnext/__init__.py
index 6dbdab8..21abfaf 100644
--- a/erpnext/__init__.py
+++ b/erpnext/__init__.py
@@ -5,7 +5,7 @@
from erpnext.hooks import regional_overrides
from frappe.utils import getdate
-__version__ = '11.1.19'
+__version__ = '11.1.20'
def get_default_company(user=None):
'''Get default company for user'''
diff --git a/erpnext/projects/report/billing_summary.py b/erpnext/projects/report/billing_summary.py
new file mode 100644
index 0000000..214dcef
--- /dev/null
+++ b/erpnext/projects/report/billing_summary.py
@@ -0,0 +1,123 @@
+# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+
+from __future__ import unicode_literals
+import frappe
+from frappe import _
+from frappe.utils import time_diff_in_hours
+
+def get_columns():
+ return [
+ {
+ "label": _("Employee ID"),
+ "fieldtype": "Link",
+ "fieldname": "employee",
+ "options": "Employee",
+ "width": 300
+ },
+ {
+ "label": _("Employee Name"),
+ "fieldtype": "data",
+ "fieldname": "employee_name",
+ "hidden": 1,
+ "width": 200
+ },
+ {
+ "label": _("Timesheet"),
+ "fieldtype": "Link",
+ "fieldname": "timesheet",
+ "options": "Timesheet",
+ "width": 150
+ },
+ {
+ "label": _("Total Billable Hours"),
+ "fieldtype": "Int",
+ "fieldname": "total_billable_hours",
+ "width": 50
+ },
+ {
+ "label": _("Total Hours"),
+ "fieldtype": "Int",
+ "fieldname": "total_hours",
+ "width": 50
+ },
+ {
+ "label": _("Amount"),
+ "fieldtype": "Int",
+ "fieldname": "amount",
+ "width": 100
+ }
+ ]
+
+def get_data(filters):
+ data = []
+ record = get_records(filters)
+
+ for entries in record:
+ total_hours = 0
+ total_billable_hours = 0
+ total_amount = 0
+ entries_exists = False
+ timesheet_details = get_timesheet_details(filters, entries.name)
+ for activity in timesheet_details:
+ entries_exists = True
+ time_start = activity.from_time
+ time_end = frappe.utils.add_to_date(activity.from_time, hours=activity.hours)
+ from_date = frappe.utils.get_datetime(filters.from_date)
+ to_date = frappe.utils.get_datetime(filters.to_date)
+
+ if time_start <= from_date and time_end <= to_date:
+ total_hours, total_billable_hours, total_amount = get_billable_and_total_hours(activity,
+ time_end, from_date, total_hours, total_billable_hours, total_amount)
+ elif time_start >= from_date and time_end >= to_date:
+ total_hours, total_billable_hours, total_amount = get_billable_and_total_hours(activity,
+ to_date, time_start, total_hours, total_billable_hours, total_amount)
+ elif time_start >= from_date and time_end <= to_date:
+ total_hours, total_billable_hours, total_amount = get_billable_and_total_hours(activity,
+ time_end, time_start, total_hours, total_billable_hours, total_amount)
+
+ row = {
+ "employee": entries.employee,
+ "employee_name": entries.employee_name,
+ "timesheet": entries.name,
+ "total_billable_hours": total_billable_hours,
+ "total_hours": total_hours,
+ "amount": total_amount
+ }
+
+ if entries_exists:
+ data.append(row)
+ entries_exists = False
+
+ return data
+
+def get_records(filters):
+ record_filters = [
+ ["start_date", "<=", filters.to_date],
+ ["end_date", ">=", filters.from_date]
+ ]
+
+ if "employee" in filters:
+ record_filters.append(["employee", "=", filters.employee])
+
+ return frappe.get_all("Timesheet", filters=record_filters, fields=[" * "] )
+
+def get_billable_and_total_hours(activity, end, start, total_hours, total_billable_hours, total_amount):
+ total_hours += abs(time_diff_in_hours(end, start))
+ if activity.billable:
+ total_billable_hours += abs(time_diff_in_hours(end, start))
+ total_amount += total_billable_hours * activity.billing_rate
+ return total_hours, total_billable_hours, total_amount
+
+def get_timesheet_details(filters, parent):
+ timesheet_details_filter = {"parent": parent}
+
+ if "project" in filters:
+ timesheet_details_filter["project"] = filters.project
+
+ return frappe.get_all(
+ "Timesheet Detail",
+ filters = timesheet_details_filter,
+ fields=["*"]
+ )
diff --git a/erpnext/projects/report/employee_billing_summary/__init__.py b/erpnext/projects/report/employee_billing_summary/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/projects/report/employee_billing_summary/__init__.py
diff --git a/erpnext/projects/report/employee_billing_summary/employee_billing_summary.js b/erpnext/projects/report/employee_billing_summary/employee_billing_summary.js
new file mode 100644
index 0000000..65c2a69
--- /dev/null
+++ b/erpnext/projects/report/employee_billing_summary/employee_billing_summary.js
@@ -0,0 +1,29 @@
+// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+/* eslint-disable */
+
+frappe.query_reports["Employee Billing Summary"] = {
+ "filters": [
+ {
+ fieldname: "employee",
+ label: __("Employee"),
+ fieldtype: "Link",
+ options: "Employee",
+ reqd: 1
+ },
+ {
+ fieldname:"from_date",
+ label: __("From Date"),
+ fieldtype: "Date",
+ default: frappe.datetime.get_today(),
+ reqd: 1
+ },
+ {
+ fieldname:"to_date",
+ label: __("To Date"),
+ fieldtype: "Date",
+ default: frappe.datetime.add_days(frappe.datetime.get_today(), 30),
+ reqd: 1
+ },
+ ]
+}
diff --git a/erpnext/projects/report/employee_billing_summary/employee_billing_summary.json b/erpnext/projects/report/employee_billing_summary/employee_billing_summary.json
new file mode 100644
index 0000000..433ebac
--- /dev/null
+++ b/erpnext/projects/report/employee_billing_summary/employee_billing_summary.json
@@ -0,0 +1,36 @@
+{
+ "add_total_row": 0,
+ "creation": "2019-03-08 15:08:19.929728",
+ "disable_prepared_report": 0,
+ "disabled": 0,
+ "docstatus": 0,
+ "doctype": "Report",
+ "idx": 0,
+ "is_standard": "Yes",
+ "modified": "2019-03-08 15:08:19.929728",
+ "modified_by": "Administrator",
+ "module": "Projects",
+ "name": "Employee Billing Summary",
+ "owner": "Administrator",
+ "prepared_report": 0,
+ "ref_doctype": "Timesheet",
+ "report_name": "Employee Billing Summary",
+ "report_type": "Script Report",
+ "roles": [
+ {
+ "role": "Projects User"
+ },
+ {
+ "role": "HR User"
+ },
+ {
+ "role": "Manufacturing User"
+ },
+ {
+ "role": "Employee"
+ },
+ {
+ "role": "Accounts User"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/erpnext/projects/report/employee_billing_summary/employee_billing_summary.py b/erpnext/projects/report/employee_billing_summary/employee_billing_summary.py
new file mode 100644
index 0000000..cd5ad78
--- /dev/null
+++ b/erpnext/projects/report/employee_billing_summary/employee_billing_summary.py
@@ -0,0 +1,14 @@
+# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe import _
+from erpnext.projects.report.billing_summary import get_columns, get_data
+
+def execute(filters=None):
+ filters = frappe._dict(filters or {})
+ columns = get_columns()
+
+ data = get_data(filters)
+ return columns, data
\ No newline at end of file
diff --git a/erpnext/projects/report/project_billing_summary/__init__.py b/erpnext/projects/report/project_billing_summary/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/projects/report/project_billing_summary/__init__.py
diff --git a/erpnext/projects/report/project_billing_summary/project_billing_summary.js b/erpnext/projects/report/project_billing_summary/project_billing_summary.js
new file mode 100644
index 0000000..62362c3
--- /dev/null
+++ b/erpnext/projects/report/project_billing_summary/project_billing_summary.js
@@ -0,0 +1,29 @@
+// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+/* eslint-disable */
+
+frappe.query_reports["Project Billing Summary"] = {
+ "filters": [
+ {
+ fieldname: "project",
+ label: __("Project"),
+ fieldtype: "Link",
+ options: "Project",
+ reqd: 1
+ },
+ {
+ fieldname:"from_date",
+ label: __("From Date"),
+ fieldtype: "Date",
+ default: frappe.datetime.get_today(),
+ reqd: 1
+ },
+ {
+ fieldname:"to_date",
+ label: __("To Date"),
+ fieldtype: "Date",
+ default: frappe.datetime.add_days(frappe.datetime.get_today(), 30),
+ reqd: 1
+ },
+ ]
+}
diff --git a/erpnext/projects/report/project_billing_summary/project_billing_summary.json b/erpnext/projects/report/project_billing_summary/project_billing_summary.json
new file mode 100644
index 0000000..a3f91c8
--- /dev/null
+++ b/erpnext/projects/report/project_billing_summary/project_billing_summary.json
@@ -0,0 +1,36 @@
+{
+ "add_total_row": 0,
+ "creation": "2019-03-11 16:22:39.460524",
+ "disable_prepared_report": 0,
+ "disabled": 0,
+ "docstatus": 0,
+ "doctype": "Report",
+ "idx": 0,
+ "is_standard": "Yes",
+ "modified": "2019-03-11 16:22:39.460524",
+ "modified_by": "Administrator",
+ "module": "Projects",
+ "name": "Project Billing Summary",
+ "owner": "Administrator",
+ "prepared_report": 0,
+ "ref_doctype": "Timesheet",
+ "report_name": "Project Billing Summary",
+ "report_type": "Script Report",
+ "roles": [
+ {
+ "role": "Projects User"
+ },
+ {
+ "role": "HR User"
+ },
+ {
+ "role": "Manufacturing User"
+ },
+ {
+ "role": "Employee"
+ },
+ {
+ "role": "Accounts User"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/erpnext/projects/report/project_billing_summary/project_billing_summary.py b/erpnext/projects/report/project_billing_summary/project_billing_summary.py
new file mode 100644
index 0000000..cd5ad78
--- /dev/null
+++ b/erpnext/projects/report/project_billing_summary/project_billing_summary.py
@@ -0,0 +1,14 @@
+# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe import _
+from erpnext.projects.report.billing_summary import get_columns, get_data
+
+def execute(filters=None):
+ filters = frappe._dict(filters or {})
+ columns = get_columns()
+
+ data = get_data(filters)
+ return columns, data
\ No newline at end of file
diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py
index 8761f4e..e93e7d9 100644
--- a/erpnext/stock/doctype/item/item.py
+++ b/erpnext/stock/doctype/item/item.py
@@ -725,7 +725,7 @@
_('Cannot change Attributes after stock transaction. Make a new Item and transfer stock to the new Item'))
def validate_variant_based_on_change(self):
- if self.variant_of or (self.has_variants and frappe.get_all("Item", {"variant_of": self.name})):
+ if not self.is_new() and (self.variant_of or (self.has_variants and frappe.get_all("Item", {"variant_of": self.name}))):
if self.variant_based_on != frappe.db.get_value("Item", self.name, "variant_based_on"):
frappe.throw(_("Variant Based On cannot be changed"))