From fd53c64d5d6aa77e6dbd88c8c65732b2effd9486 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Fri, 29 Mar 2019 20:50:06 +0530
Subject: [PATCH 001/484] feat: create carried forward leave expiry option
---
erpnext/hr/doctype/leave_type/leave_type.json | 85 +++++++++++++++++--
erpnext/hr/doctype/leave_type/leave_type.py | 9 +-
2 files changed, 86 insertions(+), 8 deletions(-)
diff --git a/erpnext/hr/doctype/leave_type/leave_type.json b/erpnext/hr/doctype/leave_type/leave_type.json
index 6a7a80a784..06f18c8a5e 100644
--- a/erpnext/hr/doctype/leave_type/leave_type.json
+++ b/erpnext/hr/doctype/leave_type/leave_type.json
@@ -1,5 +1,6 @@
{
"allow_copy": 0,
+ "allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 1,
"allow_rename": 1,
@@ -14,10 +15,12 @@
"fields": [
{
"allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "leave_type_name",
"fieldtype": "Data",
"hidden": 0,
@@ -42,15 +45,17 @@
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
- "unique": 0
+ "unique": 1
},
{
"allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "",
+ "fetch_if_empty": 0,
"fieldname": "max_leaves_allowed",
"fieldtype": "Int",
"hidden": 0,
@@ -78,10 +83,12 @@
},
{
"allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "applicable_after",
"fieldtype": "Int",
"hidden": 0,
@@ -109,10 +116,12 @@
},
{
"allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "max_continuous_days_allowed",
"fieldtype": "Int",
"hidden": 0,
@@ -141,10 +150,12 @@
},
{
"allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "column_break_3",
"fieldtype": "Column Break",
"hidden": 0,
@@ -171,10 +182,12 @@
},
{
"allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "is_carry_forward",
"fieldtype": "Check",
"hidden": 0,
@@ -203,10 +216,46 @@
},
{
"allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "depends_on": "eval: doc.is_carry_forward == 1",
+ "fetch_if_empty": 0,
+ "fieldname": "carry_forward_leave_expiry",
+ "fieldtype": "Int",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Carry Forward Leave Expiry",
+ "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,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "is_lwp",
"fieldtype": "Check",
"hidden": 0,
@@ -233,10 +282,12 @@
},
{
"allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "is_optional_leave",
"fieldtype": "Check",
"hidden": 0,
@@ -264,10 +315,12 @@
},
{
"allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "allow_negative",
"fieldtype": "Check",
"hidden": 0,
@@ -294,10 +347,12 @@
},
{
"allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "include_holiday",
"fieldtype": "Check",
"hidden": 0,
@@ -324,10 +379,12 @@
},
{
"allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "is_compensatory",
"fieldtype": "Check",
"hidden": 0,
@@ -355,10 +412,12 @@
},
{
"allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "encashment",
"fieldtype": "Section Break",
"hidden": 0,
@@ -386,10 +445,12 @@
},
{
"allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "allow_encashment",
"fieldtype": "Check",
"hidden": 0,
@@ -417,11 +478,13 @@
},
{
"allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "allow_encashment",
+ "fetch_if_empty": 0,
"fieldname": "encashment_threshold_days",
"fieldtype": "Int",
"hidden": 0,
@@ -449,11 +512,13 @@
},
{
"allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "allow_encashment",
+ "fetch_if_empty": 0,
"fieldname": "earning_component",
"fieldtype": "Link",
"hidden": 0,
@@ -482,10 +547,12 @@
},
{
"allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "earned_leave",
"fieldtype": "Section Break",
"hidden": 0,
@@ -513,10 +580,12 @@
},
{
"allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "is_earned_leave",
"fieldtype": "Check",
"hidden": 0,
@@ -544,11 +613,13 @@
},
{
"allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "is_earned_leave",
+ "fetch_if_empty": 0,
"fieldname": "earned_leave_frequency",
"fieldtype": "Select",
"hidden": 0,
@@ -577,12 +648,14 @@
},
{
"allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "0.5",
"depends_on": "is_earned_leave",
+ "fetch_if_empty": 0,
"fieldname": "rounding",
"fieldtype": "Select",
"hidden": 0,
@@ -611,17 +684,15 @@
}
],
"has_web_view": 0,
- "hide_heading": 0,
"hide_toolbar": 0,
"icon": "fa fa-flag",
"idx": 1,
- "image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2018-06-03 18:32:51.803472",
+ "modified": "2019-03-29 16:06:03.456035",
"modified_by": "Administrator",
"module": "HR",
"name": "Leave Type",
@@ -687,8 +758,8 @@
],
"quick_entry": 0,
"read_only": 0,
- "read_only_onload": 0,
"show_name_in_global_search": 0,
"track_changes": 0,
- "track_seen": 0
-}
+ "track_seen": 0,
+ "track_views": 0
+}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/leave_type/leave_type.py b/erpnext/hr/doctype/leave_type/leave_type.py
index e0127e5e97..d7891a4f62 100644
--- a/erpnext/hr/doctype/leave_type/leave_type.py
+++ b/erpnext/hr/doctype/leave_type/leave_type.py
@@ -3,8 +3,15 @@
from __future__ import unicode_literals
import frappe
+from frappe import _
from frappe.model.document import Document
class LeaveType(Document):
- pass
\ No newline at end of file
+ def validate(self):
+ if self.is_carry_forward:
+ self.validate_carry_forward()
+
+ def validate_carry_forward(self):
+ if (self.carry_forward_leave_expiry <1 or self.carry_forward_leave_expiry > 365):
+ frappe.throw(_('Invalid entry!! Carried forward days need to expire within a year'))
From c182a5687eae94994b0df8f8692d70195a594670 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Fri, 5 Apr 2019 11:17:40 +0530
Subject: [PATCH 002/484] feat: add validation for carry forward leave expiry
---
erpnext/hr/doctype/leave_type/leave_type.json | 107 ++++++++++++------
erpnext/hr/doctype/leave_type/leave_type.py | 4 +-
2 files changed, 75 insertions(+), 36 deletions(-)
diff --git a/erpnext/hr/doctype/leave_type/leave_type.json b/erpnext/hr/doctype/leave_type/leave_type.json
index 06f18c8a5e..ee9b04fc00 100644
--- a/erpnext/hr/doctype/leave_type/leave_type.json
+++ b/erpnext/hr/doctype/leave_type/leave_type.json
@@ -221,40 +221,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
- "depends_on": "eval: doc.is_carry_forward == 1",
- "fetch_if_empty": 0,
- "fieldname": "carry_forward_leave_expiry",
- "fieldtype": "Int",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Carry Forward Leave Expiry",
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
+ "depends_on": "",
"fetch_if_empty": 0,
"fieldname": "is_lwp",
"fieldtype": "Check",
@@ -410,6 +377,76 @@
"translatable": 0,
"unique": 0
},
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 1,
+ "columns": 0,
+ "depends_on": "eval: doc.is_carry_forward == 1",
+ "fetch_if_empty": 0,
+ "fieldname": "carry_forward_section",
+ "fieldtype": "Section Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Carry Forward",
+ "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,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "default": "1",
+ "depends_on": "",
+ "description": "calculated in days",
+ "fetch_if_empty": 0,
+ "fieldname": "carry_forward__leave_expiry",
+ "fieldtype": "Int",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Carry Forward Leave Expiry",
+ "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,
+ "translatable": 0,
+ "unique": 0
+ },
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
@@ -692,7 +729,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2019-03-29 16:06:03.456035",
+ "modified": "2019-04-04 14:27:47.742997",
"modified_by": "Administrator",
"module": "HR",
"name": "Leave Type",
diff --git a/erpnext/hr/doctype/leave_type/leave_type.py b/erpnext/hr/doctype/leave_type/leave_type.py
index d7891a4f62..9cd574a598 100644
--- a/erpnext/hr/doctype/leave_type/leave_type.py
+++ b/erpnext/hr/doctype/leave_type/leave_type.py
@@ -2,6 +2,7 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+import calendar
import frappe
from frappe import _
@@ -13,5 +14,6 @@ class LeaveType(Document):
self.validate_carry_forward()
def validate_carry_forward(self):
- if (self.carry_forward_leave_expiry <1 or self.carry_forward_leave_expiry > 365):
+ max_days = 366 if calendar.isleap() else 365
+ if not (1 < self.carry_forward_leave_expiry < max_days):
frappe.throw(_('Invalid entry!! Carried forward days need to expire within a year'))
From 1208ca6a36069cdd7b5f394839960826e3cdadba Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Fri, 5 Apr 2019 11:18:28 +0530
Subject: [PATCH 003/484] feat: add old leaves to track carry forward leave
allocation
---
.../leave_allocation/leave_allocation.json | 94 ++++++++++++++++++-
1 file changed, 90 insertions(+), 4 deletions(-)
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.json b/erpnext/hr/doctype/leave_allocation/leave_allocation.json
index 6d61fe3d5c..431adfb16b 100644
--- a/erpnext/hr/doctype/leave_allocation/leave_allocation.json
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.json
@@ -22,6 +22,7 @@
"collapsible": 0,
"columns": 0,
"default": "",
+ "fetch_if_empty": 0,
"fieldname": "naming_series",
"fieldtype": "Select",
"hidden": 0,
@@ -55,6 +56,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "employee",
"fieldtype": "Link",
"hidden": 0,
@@ -90,6 +92,7 @@
"collapsible": 0,
"columns": 0,
"fetch_from": "employee.employee_name",
+ "fetch_if_empty": 0,
"fieldname": "employee_name",
"fieldtype": "Data",
"hidden": 0,
@@ -122,6 +125,7 @@
"collapsible": 0,
"columns": 0,
"fetch_from": "employee.department",
+ "fetch_if_empty": 0,
"fieldname": "department",
"fieldtype": "Link",
"hidden": 0,
@@ -155,6 +159,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "column_break1",
"fieldtype": "Column Break",
"hidden": 0,
@@ -186,6 +191,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "leave_type",
"fieldtype": "Link",
"hidden": 0,
@@ -220,6 +226,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "from_date",
"fieldtype": "Date",
"hidden": 0,
@@ -252,6 +259,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "to_date",
"fieldtype": "Date",
"hidden": 0,
@@ -284,6 +292,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "section_break_6",
"fieldtype": "Section Break",
"hidden": 0,
@@ -316,6 +325,8 @@
"bold": 1,
"collapsible": 0,
"columns": 0,
+ "depends_on": "eval: doc.is_carry_forward != 1",
+ "fetch_if_empty": 0,
"fieldname": "new_leaves_allocated",
"fieldtype": "Float",
"hidden": 0,
@@ -347,7 +358,76 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "depends_on": "eval: doc.is_carry_forward == 1",
+ "fetch_if_empty": 0,
+ "fieldname": "old_leaves_allocated",
+ "fieldtype": "Int",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Old Leaves Allocated",
+ "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,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "is_carry_forward",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "is carry forward",
+ "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,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "depends_on": "",
"description": "",
+ "fetch_if_empty": 0,
"fieldname": "carry_forward",
"fieldtype": "Check",
"hidden": 0,
@@ -380,6 +460,7 @@
"collapsible": 0,
"columns": 0,
"depends_on": "carry_forward",
+ "fetch_if_empty": 0,
"fieldname": "carry_forwarded_leaves",
"fieldtype": "Float",
"hidden": 0,
@@ -411,6 +492,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "total_leaves_allocated",
"fieldtype": "Float",
"hidden": 0,
@@ -443,6 +525,7 @@
"collapsible": 0,
"columns": 0,
"depends_on": "eval:doc.total_leaves_encashed>0",
+ "fetch_if_empty": 0,
"fieldname": "total_leaves_encashed",
"fieldtype": "Float",
"hidden": 0,
@@ -475,6 +558,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "column_break_10",
"fieldtype": "Column Break",
"hidden": 0,
@@ -506,6 +590,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "compensatory_request",
"fieldtype": "Link",
"hidden": 0,
@@ -539,6 +624,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "leave_period",
"fieldtype": "Link",
"hidden": 0,
@@ -572,6 +658,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "amended_from",
"fieldtype": "Link",
"hidden": 0,
@@ -606,6 +693,7 @@
"bold": 0,
"collapsible": 1,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "notes",
"fieldtype": "Section Break",
"hidden": 0,
@@ -638,6 +726,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "description",
"fieldtype": "Small Text",
"hidden": 0,
@@ -667,17 +756,15 @@
}
],
"has_web_view": 0,
- "hide_heading": 0,
"hide_toolbar": 0,
"icon": "fa fa-ok",
"idx": 1,
- "image_view": 0,
"in_create": 0,
"is_submittable": 1,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2019-01-30 11:28:09.360525",
+ "modified": "2019-04-04 15:09:33.421008",
"modified_by": "Administrator",
"module": "HR",
"name": "Leave Allocation",
@@ -724,7 +811,6 @@
],
"quick_entry": 0,
"read_only": 0,
- "read_only_onload": 0,
"search_fields": "employee,employee_name,leave_type,total_leaves_allocated",
"show_name_in_global_search": 1,
"sort_field": "modified",
From 7c6b6eae5b55651d6401c57b6f8d2a1a4cd4a1b4 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Fri, 5 Apr 2019 11:58:35 +0530
Subject: [PATCH 004/484] feat: set leave allocation on carry forward check
---
.../leave_allocation/leave_allocation.py | 42 ++++++++++++++-----
1 file changed, 31 insertions(+), 11 deletions(-)
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.py b/erpnext/hr/doctype/leave_allocation/leave_allocation.py
index dc270dba41..e755da5f54 100755
--- a/erpnext/hr/doctype/leave_allocation/leave_allocation.py
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.py
@@ -62,11 +62,18 @@ class LeaveAllocation(Document):
if flt(self.new_leaves_allocated) % 0.5:
frappe.throw(_("Leaves must be allocated in multiples of 0.5"), ValueMultiplierError)
- def validate_allocation_overlap(self):
+ def validate_allocation_overlap(self, carry_forward=0):
leave_allocation = frappe.db.sql("""
- select name from `tabLeave Allocation`
- where employee=%s and leave_type=%s and docstatus=1
- and to_date >= %s and from_date <= %s""",
+ SELECT
+ name
+ FROM `tabLeave Allocation`
+ WHERE
+ employee=%s
+ AND leave_type=%s
+ AND docstatus=1
+ AND is_carry_forward={0}
+ AND to_date >= %s
+ AND from_date <= %s""".format(carry_forward),
(self.employee, self.leave_type, self.from_date, self.to_date))
if leave_allocation:
@@ -111,6 +118,11 @@ class LeaveAllocation(Document):
else:
frappe.throw(_("Total allocated leaves {0} cannot be less than already approved leaves {1} for the period").format(self.total_leaves_allocated, leaves_taken), LessAllocationError)
+ def set_carry_forward_leaves(self):
+ self.validate_allocation_overlap(carry_forward=1)
+ self.old_leaves_allocated = get_carry_forwarded_leaves(self.employee, self.leave_type,
+ self.from_date, self.is_carry_forward)
+
def get_leave_allocation_for_period(employee, leave_type, from_date, to_date):
leave_allocated = 0
leave_allocations = frappe.db.sql("""
@@ -135,17 +147,25 @@ def get_leave_allocation_for_period(employee, leave_type, from_date, to_date):
return leave_allocated
@frappe.whitelist()
-def get_carry_forwarded_leaves(employee, leave_type, date, carry_forward=None):
+def get_carry_forwarded_leaves(employee, leave_type, date, is_carry_forward=None):
carry_forwarded_leaves = 0
- if carry_forward:
+ if is_carry_forward:
validate_carry_forward(leave_type)
previous_allocation = frappe.db.sql("""
- select name, from_date, to_date, total_leaves_allocated
- from `tabLeave Allocation`
- where employee=%s and leave_type=%s and docstatus=1 and to_date < %s
- order by to_date desc limit 1
+ SELECT
+ name,
+ from_date,
+ to_date,
+ total_leaves_allocated
+ FROM `tabLeave Allocation`
+ WHERE
+ employee=%s
+ AND leave_type=%s
+ AND docstatus=1
+ AND to_date < %s
+ ORDER BY to_date desc limit 1
""", (employee, leave_type, date), as_dict=1)
if previous_allocation:
leaves_taken = get_approved_leaves_for_period(employee, leave_type,
@@ -157,4 +177,4 @@ def get_carry_forwarded_leaves(employee, leave_type, date, carry_forward=None):
def validate_carry_forward(leave_type):
if not frappe.db.get_value("Leave Type", leave_type, "is_carry_forward"):
- frappe.throw(_("Leave Type {0} cannot be carry-forwarded").format(leave_type))
+ frappe.throw(_("Leave Type {0} cannot be carry-forwarded").format(leave_type))
\ No newline at end of file
From bd3b3ea12c45c2d5cda37fa984fcbbd607dde56e Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Thu, 11 Apr 2019 00:20:32 +0530
Subject: [PATCH 005/484] test: create leave type
---
.../hr/doctype/leave_type/test_leave_type.py | 22 +++++++++++++++++--
1 file changed, 20 insertions(+), 2 deletions(-)
diff --git a/erpnext/hr/doctype/leave_type/test_leave_type.py b/erpnext/hr/doctype/leave_type/test_leave_type.py
index b844e49e7c..671865b5a0 100644
--- a/erpnext/hr/doctype/leave_type/test_leave_type.py
+++ b/erpnext/hr/doctype/leave_type/test_leave_type.py
@@ -2,6 +2,24 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-
import frappe
-test_records = frappe.get_test_records('Leave Type')
\ No newline at end of file
+from frappe import _
+
+test_records = frappe.get_test_records('Leave Type')
+
+def create_leave_type(**args):
+ if frappe.db.exists("Leave Type", args.leave_type_name):
+ return frappe.get_doc("Leave Type", args.leave_type_name)
+ leave_type = frappe.get_doc({
+ "doctype": "Leave Type",
+ "leave_type_name": args.leave_type_name or "_Test Leave Type",
+ "include_holiday": args.include_holidays or 1,
+ "allow_encashment": args.allow_encashment or 0,
+ "is_earned_leave": args.is_earned_leave or 0,
+ "is_lwp": args.is_lwp or 0,
+ "is_carry_forward": args.is_carry_forward or 0,
+ "carry_forward_leave_expiry": args.is_carry_forward or 0,
+ "encashment_threshold_days": args.encashment_threshold_days or 5,
+ "earning_component": "Leave Encashment"
+ })
+ return leave_type
\ No newline at end of file
From c28d2e4b2aeae44daa08ca247f4fa5142fdcf4f8 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Thu, 11 Apr 2019 00:21:11 +0530
Subject: [PATCH 006/484] test: create leave allocation check
---
.../leave_allocation/test_leave_allocation.py | 83 +++++++++++++++----
1 file changed, 65 insertions(+), 18 deletions(-)
diff --git a/erpnext/hr/doctype/leave_allocation/test_leave_allocation.py b/erpnext/hr/doctype/leave_allocation/test_leave_allocation.py
index 3b22eb2e44..3bc8dc458d 100644
--- a/erpnext/hr/doctype/leave_allocation/test_leave_allocation.py
+++ b/erpnext/hr/doctype/leave_allocation/test_leave_allocation.py
@@ -1,12 +1,13 @@
from __future__ import unicode_literals
import frappe
import unittest
-from frappe.utils import getdate
+from frappe.utils import nowdate, add_months, getdate
+from erpnext.hr.doctype.leave_type.test_leave_type import create_leave_type
class TestLeaveAllocation(unittest.TestCase):
def test_overlapping_allocation(self):
frappe.db.sql("delete from `tabLeave Allocation`")
-
+
employee = frappe.get_doc("Employee", frappe.db.sql_list("select name from tabEmployee limit 1")[0])
leaves = [
{
@@ -18,7 +19,7 @@ class TestLeaveAllocation(unittest.TestCase):
"from_date": getdate("2015-10-01"),
"to_date": getdate("2015-10-31"),
"new_leaves_allocated": 5,
- "docstatus": 1
+ "docstatus": 1
},
{
"doctype": "Leave Allocation",
@@ -28,17 +29,17 @@ class TestLeaveAllocation(unittest.TestCase):
"leave_type": "_Test Leave Type",
"from_date": getdate("2015-09-01"),
"to_date": getdate("2015-11-30"),
- "new_leaves_allocated": 5
+ "new_leaves_allocated": 5
}
]
frappe.get_doc(leaves[0]).save()
self.assertRaises(frappe.ValidationError, frappe.get_doc(leaves[1]).save)
-
- def test_invalid_period(self):
+
+ def test_invalid_period(self):
employee = frappe.get_doc("Employee", frappe.db.sql_list("select name from tabEmployee limit 1")[0])
-
- d = frappe.get_doc({
+
+ doc = frappe.get_doc({
"doctype": "Leave Allocation",
"__islocal": 1,
"employee": employee.name,
@@ -46,15 +47,15 @@ class TestLeaveAllocation(unittest.TestCase):
"leave_type": "_Test Leave Type",
"from_date": getdate("2015-09-30"),
"to_date": getdate("2015-09-1"),
- "new_leaves_allocated": 5
+ "new_leaves_allocated": 5
})
-
+
#invalid period
- self.assertRaises(frappe.ValidationError, d.save)
-
+ self.assertRaises(frappe.ValidationError, doc.save)
+
def test_allocated_leave_days_over_period(self):
employee = frappe.get_doc("Employee", frappe.db.sql_list("select name from tabEmployee limit 1")[0])
- d = frappe.get_doc({
+ doc = frappe.get_doc({
"doctype": "Leave Allocation",
"__islocal": 1,
"employee": employee.name,
@@ -62,10 +63,56 @@ class TestLeaveAllocation(unittest.TestCase):
"leave_type": "_Test Leave Type",
"from_date": getdate("2015-09-1"),
"to_date": getdate("2015-09-30"),
- "new_leaves_allocated": 35
+ "new_leaves_allocated": 35
})
-
- #allocated leave more than period
- self.assertRaises(frappe.ValidationError, d.save)
-
+ #allocated leave more than period
+ self.assertRaises(frappe.ValidationError, doc.save)
+
+ def test_carry_forward_allocation(self):
+ frappe.db.sql("delete from `tabLeave Allocation`")
+
+ employee = frappe.get_doc("Employee", frappe.db.sql_list("select name from tabEmployee limit 1")[0])
+ doc = frappe.get_doc({
+ "doctype": "Leave Allocation",
+ "__islocal": 1,
+ "employee": employee.name,
+ "employee_name": employee.employee_name,
+ "leave_type": "_Test Leave Type Carry Forward",
+ "from_date": nowdate(),
+ "to_date": add_months(nowdate(),-12),
+ "new_leaves_allocated": 10
+ })
+ doc.save()
+ doc = frappe.get_doc({
+ "doctype": "Leave Allocation",
+ "__islocal": 1,
+ "employee": employee.name,
+ "employee_name": employee.employee_name,
+ "leave_type": "_Test Leave Type Carry Forward",
+ "from_date": nowdate(),
+ "to_date": add_months(now_date(),12),
+ "carry_forward": 1
+ })
+ doc.save()
+ self.assertEquals(doc.total_leaves_allocated, 10)
+
+def create_leave_allocation(**args):
+ args = frappe._dict(args)
+ if not frappe.db.exists("Leave Type", "_Test Leave Type"):
+ leave_type = create_leave_type(args.leave_type)
+ leave_type.insert()
+
+ employee = frappe.get_doc("Employee", frappe.db.sql_list("select name from tabEmployee limit 1")[0])
+ leave_allocation = frappe.get_doc({
+ "doctype": "Leave Allocation",
+ "__islocal": 1,
+ "employee": employee.name,
+ "employee_name": employee.employee_name,
+ "leave_type": args.leave_type or "_Test Leave Type",
+ "from_date": args.from_date or nowdate(),
+ "to_date": args.to_date or add_months(nowdate(), 12),
+ "new_leaves_allocated": args.new_leaves_allocated or 20
+ })
+ return leave_allocation
+
test_dependencies = ["Employee", "Leave Type"]
\ No newline at end of file
From e46d3a87ea7fc9850f4619ef02d6850ba3abe876 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Thu, 11 Apr 2019 00:22:11 +0530
Subject: [PATCH 007/484] feat: set carry forwarded leave allocation
---
.../leave_allocation/leave_allocation.json | 107 +---------------
.../leave_allocation/leave_allocation.py | 114 +++++++++++-------
2 files changed, 75 insertions(+), 146 deletions(-)
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.json b/erpnext/hr/doctype/leave_allocation/leave_allocation.json
index 431adfb16b..aa203384e8 100644
--- a/erpnext/hr/doctype/leave_allocation/leave_allocation.json
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.json
@@ -325,7 +325,7 @@
"bold": 1,
"collapsible": 0,
"columns": 0,
- "depends_on": "eval: doc.is_carry_forward != 1",
+ "depends_on": "eval: doc.carry_forward != 1",
"fetch_if_empty": 0,
"fieldname": "new_leaves_allocated",
"fieldtype": "Float",
@@ -351,73 +351,6 @@
"translatable": 0,
"unique": 0
},
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval: doc.is_carry_forward == 1",
- "fetch_if_empty": 0,
- "fieldname": "old_leaves_allocated",
- "fieldtype": "Int",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Old Leaves Allocated",
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "is_carry_forward",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "is carry forward",
- "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,
- "translatable": 0,
- "unique": 0
- },
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
@@ -437,7 +370,7 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
- "label": "Add unused leaves from previous allocations",
+ "label": "Allocate unused leaves from previous allocations",
"length": 0,
"no_copy": 0,
"permlevel": 0,
@@ -452,39 +385,6 @@
"translatable": 0,
"unique": 0
},
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "carry_forward",
- "fetch_if_empty": 0,
- "fieldname": "carry_forwarded_leaves",
- "fieldtype": "Float",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Unused leaves",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
@@ -492,6 +392,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "depends_on": "",
"fetch_if_empty": 0,
"fieldname": "total_leaves_allocated",
"fieldtype": "Float",
@@ -764,7 +665,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2019-04-04 15:09:33.421008",
+ "modified": "2019-04-05 15:31:04.627015",
"modified_by": "Administrator",
"module": "HR",
"name": "Leave Allocation",
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.py b/erpnext/hr/doctype/leave_allocation/leave_allocation.py
index e755da5f54..7ce3143901 100755
--- a/erpnext/hr/doctype/leave_allocation/leave_allocation.py
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.py
@@ -18,14 +18,19 @@ class ValueMultiplierError(frappe.ValidationError): pass
class LeaveAllocation(Document):
def validate(self):
self.validate_period()
- self.validate_new_leaves_allocated_value()
+ self.validate_lwp()
self.validate_allocation_overlap()
self.validate_back_dated_allocation()
+ if not self.carry_forward:
+ self.validate_new_leaves_allocated_value()
+ self.validate_leave_allocation_days()
self.set_total_leaves_allocated()
self.validate_total_leaves_allocated()
- self.validate_lwp()
set_employee_name(self)
- self.validate_leave_allocation_days()
+
+ def on_update(self):
+ if self.carry_forward:
+ self.set_carry_forward_leaves()
def validate_leave_allocation_days(self):
company = frappe.db.get_value("Employee", self.employee, "company")
@@ -44,7 +49,6 @@ class LeaveAllocation(Document):
self.validate_new_leaves_allocated_value()
self.set_total_leaves_allocated()
- frappe.db.set(self,'carry_forwarded_leaves', flt(self.carry_forwarded_leaves))
frappe.db.set(self,'total_leaves_allocated',flt(self.total_leaves_allocated))
self.validate_against_leave_applications()
@@ -62,7 +66,7 @@ class LeaveAllocation(Document):
if flt(self.new_leaves_allocated) % 0.5:
frappe.throw(_("Leaves must be allocated in multiples of 0.5"), ValueMultiplierError)
- def validate_allocation_overlap(self, carry_forward=0):
+ def validate_allocation_overlap(self):
leave_allocation = frappe.db.sql("""
SELECT
name
@@ -71,10 +75,10 @@ class LeaveAllocation(Document):
employee=%s
AND leave_type=%s
AND docstatus=1
- AND is_carry_forward={0}
+ AND carry_forward={0}
AND to_date >= %s
- AND from_date <= %s""".format(carry_forward),
- (self.employee, self.leave_type, self.from_date, self.to_date))
+ AND from_date <= %s""" #nosec
+ .format(self.carry_forward), (self.employee, self.leave_type, self.from_date, self.to_date))
if leave_allocation:
frappe.msgprint(_("{0} already allocated for Employee {1} for period {2} to {3}")
@@ -94,12 +98,11 @@ class LeaveAllocation(Document):
BackDatedAllocationError)
def set_total_leaves_allocated(self):
- self.carry_forwarded_leaves = get_carry_forwarded_leaves(self.employee,
- self.leave_type, self.from_date, self.carry_forward)
- self.total_leaves_allocated = flt(self.carry_forwarded_leaves) + flt(self.new_leaves_allocated)
+ self.total_leaves_allocated = flt(self.new_leaves_allocated)
- if not self.total_leaves_allocated and not frappe.db.get_value("Leave Type", self.leave_type, "is_earned_leave") and not frappe.db.get_value("Leave Type", self.leave_type, "is_compensatory"):
+ if not self.total_leaves_allocated and not frappe.db.get_value("Leave Type", self.leave_type, "is_earned_leave")\
+ and not frappe.db.get_value("Leave Type", self.leave_type, "is_compensatory"):
frappe.throw(_("Total leaves allocated is mandatory for Leave Type {0}".format(self.leave_type)))
def validate_total_leaves_allocated(self):
@@ -119,20 +122,44 @@ class LeaveAllocation(Document):
frappe.throw(_("Total allocated leaves {0} cannot be less than already approved leaves {1} for the period").format(self.total_leaves_allocated, leaves_taken), LessAllocationError)
def set_carry_forward_leaves(self):
- self.validate_allocation_overlap(carry_forward=1)
- self.old_leaves_allocated = get_carry_forwarded_leaves(self.employee, self.leave_type,
- self.from_date, self.is_carry_forward)
+
+ leaves_allocated
+ # check number of days to expire, ignore expiry for default value
+ expiry_days = frappe.db.get_value("Leave Type",
+ filters={"leave_type": leave_type, "is_carry_forward": 1},
+ fieldname="carry_forward_leave_expiry")
+
+ max_leaves_allowed = frappe.db.get_value("Leave Type", self.leave_type, "max_leaves_allowed")
+ leave_period = get_leave_period(self.from_date, self.to_date, company)
+ if leave_period:
+ leave_allocated = get_leave_allocation_for_period(self.employee, self.leave_type, leave_period[0].from_date, leave_period[0].to_date)
+
+ carry_forwarded_leaves = get_carry_forwarded_leaves(self.employee, self.leave_type,
+ self.from_date, expiry_days)
+ leaves_allocated += carry_forwarded_leaves
+
+ if leaves_allocated > max_leaves_allowed:
+ self.total_leaves_allocated = max_leaves_allowed - leaves_allocated
+ else:
+ self.total_leaves_allocated = carry_forwarded_leaves
def get_leave_allocation_for_period(employee, leave_type, from_date, to_date):
leave_allocated = 0
leave_allocations = frappe.db.sql("""
- select employee, leave_type, from_date, to_date, total_leaves_allocated
- from `tabLeave Allocation`
- where employee=%(employee)s and leave_type=%(leave_type)s
- and docstatus=1
- and (from_date between %(from_date)s and %(to_date)s
- or to_date between %(from_date)s and %(to_date)s
- or (from_date < %(from_date)s and to_date > %(to_date)s))
+ SELECT
+ employee,
+ leave_type,
+ from_date,
+ to_date,
+ total_leaves_allocated
+ FROM `tabLeave Allocation`
+ WHERE
+ employee=%(employee)s
+ AND leave_type=%(leave_type)s
+ AND docstatus=1
+ AND (from_date BETWEEN %(from_date)s AND %(to_date)s
+ OR to_date BETWEEN %(from_date)s AND %(to_date)s
+ OR (from_date < %(from_date)s AND to_date > %(to_date)s))
""", {
"from_date": from_date,
"to_date": to_date,
@@ -147,31 +174,32 @@ def get_leave_allocation_for_period(employee, leave_type, from_date, to_date):
return leave_allocated
@frappe.whitelist()
-def get_carry_forwarded_leaves(employee, leave_type, date, is_carry_forward=None):
+def get_carry_forwarded_leaves(employee, leave_type, date, expiry_days):
carry_forwarded_leaves = 0
- if is_carry_forward:
- validate_carry_forward(leave_type)
+ validate_carry_forward(leave_type)
+ filters = {
+ "employee": employee,
+ "leave_type": leave_type,
+ "docstatus": 1,
+ "to_date": ("<", date)
+ }
+ limit = 1
+ if expiry_days:
+ filters.update(carry_forward=0)
+ limit = 2
- previous_allocation = frappe.db.sql("""
- SELECT
- name,
- from_date,
- to_date,
- total_leaves_allocated
- FROM `tabLeave Allocation`
- WHERE
- employee=%s
- AND leave_type=%s
- AND docstatus=1
- AND to_date < %s
- ORDER BY to_date desc limit 1
- """, (employee, leave_type, date), as_dict=1)
- if previous_allocation:
- leaves_taken = get_approved_leaves_for_period(employee, leave_type,
- previous_allocation[0].from_date, previous_allocation[0].to_date)
+ previous_allocation = frappe.get_all("Leave Allocation",
+ filters=filters,
+ fields=["name","from_date","to_date","total_leaves_allocated"],
+ order_by="to_date desc",
+ limit=limit)
- carry_forwarded_leaves = flt(previous_allocation[0].total_leaves_allocated) - flt(leaves_taken)
+ if previous_allocation:
+ leaves_taken = get_approved_leaves_for_period(employee, leave_type,
+ previous_allocation[0].from_date, previous_allocation[0].to_date)
+
+ carry_forwarded_leaves = flt(previous_allocation[0].total_leaves_allocated) - flt(leaves_taken)
return carry_forwarded_leaves
From d6c5b6320ffc0327dabad107688bc71ffccbcbf5 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Tue, 23 Apr 2019 17:47:25 +0530
Subject: [PATCH 008/484] feat: add a field for conditionally displaying carry
forwarded leave
---
.../leave_allocation/leave_allocation.json | 36 ++++++++++++++++++-
1 file changed, 35 insertions(+), 1 deletion(-)
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.json b/erpnext/hr/doctype/leave_allocation/leave_allocation.json
index aa203384e8..0903398d1f 100644
--- a/erpnext/hr/doctype/leave_allocation/leave_allocation.json
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.json
@@ -351,6 +351,40 @@
"translatable": 0,
"unique": 0
},
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "depends_on": "eval: doc.carry_forward == 1",
+ "fetch_if_empty": 0,
+ "fieldname": "carry_forwarded_leaves",
+ "fieldtype": "Int",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Unused Leaves",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
@@ -665,7 +699,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2019-04-05 15:31:04.627015",
+ "modified": "2019-04-22 18:33:15.858006",
"modified_by": "Administrator",
"module": "HR",
"name": "Leave Allocation",
From 0c0bfb1ef02d5ab68c97f4ec17c05c783abfe47c Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Tue, 23 Apr 2019 18:25:51 +0530
Subject: [PATCH 009/484] feat: calculate carry forward leaves allocation
---
.../leave_allocation/leave_allocation.py | 72 +++++++++----------
1 file changed, 33 insertions(+), 39 deletions(-)
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.py b/erpnext/hr/doctype/leave_allocation/leave_allocation.py
index 7ce3143901..7f8f806f3b 100755
--- a/erpnext/hr/doctype/leave_allocation/leave_allocation.py
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.py
@@ -21,35 +21,25 @@ class LeaveAllocation(Document):
self.validate_lwp()
self.validate_allocation_overlap()
self.validate_back_dated_allocation()
- if not self.carry_forward:
- self.validate_new_leaves_allocated_value()
- self.validate_leave_allocation_days()
- self.set_total_leaves_allocated()
self.validate_total_leaves_allocated()
set_employee_name(self)
-
- def on_update(self):
- if self.carry_forward:
- self.set_carry_forward_leaves()
+ self.validate_leaves_allocated_value()
+ self.validate_leave_allocation_days()
+ self.set_total_leaves_allocated()
def validate_leave_allocation_days(self):
- company = frappe.db.get_value("Employee", self.employee, "company")
- leave_period = get_leave_period(self.from_date, self.to_date, company)
- max_leaves_allowed = frappe.db.get_value("Leave Type", self.leave_type, "max_leaves_allowed")
- if max_leaves_allowed > 0:
- leave_allocated = 0
- if leave_period:
- leave_allocated = get_leave_allocation_for_period(self.employee, self.leave_type, leave_period[0].from_date, leave_period[0].to_date)
- leave_allocated += self.new_leaves_allocated
- if leave_allocated > max_leaves_allowed:
- frappe.throw(_("Total allocated leaves are more days than maximum allocation of {0} leave type for employee {1} in the period")\
- .format(self.leave_type, self.employee))
+ new_leaves = self.new_leaves_allocate if not self.carry_forward else self.carry_forwarded_leaves
+ max_leaves, leaves_allocated = self.get_max_leaves_with_leaves_allocated_for_leave_type(flt(new_leaves))
+
+ if leave_allocated > max_leaves:
+ frappe.throw(_("Total allocated leaves are more days than maximum allocation of {0} leave type for employee {1} in the period")\
+ .format(self.leave_type, self.employee))
def on_update_after_submit(self):
self.validate_new_leaves_allocated_value()
self.set_total_leaves_allocated()
- frappe.db.set(self,'total_leaves_allocated',flt(self.total_leaves_allocated))
+ frappe.db.set(self,'total_leaves_allocated', flt(self.total_leaves_allocated))
self.validate_against_leave_applications()
@@ -61,7 +51,7 @@ class LeaveAllocation(Document):
if frappe.db.get_value("Leave Type", self.leave_type, "is_lwp"):
frappe.throw(_("Leave Type {0} cannot be allocated since it is leave without pay").format(self.leave_type))
- def validate_new_leaves_allocated_value(self):
+ def validate_leaves_allocated_value(self):
"""validate that leave allocation is in multiples of 0.5"""
if flt(self.new_leaves_allocated) % 0.5:
frappe.throw(_("Leaves must be allocated in multiples of 0.5"), ValueMultiplierError)
@@ -98,8 +88,11 @@ class LeaveAllocation(Document):
BackDatedAllocationError)
def set_total_leaves_allocated(self):
-
- self.total_leaves_allocated = flt(self.new_leaves_allocated)
+ if self.carry_forward:
+ self.set_carry_forwarded_leaves()
+ self.total_leaves_allocated = flt(self.carry_forwarded_leaves)
+ else:
+ self.total_leaves_allocated = flt(self.new_leaves_allocated)
if not self.total_leaves_allocated and not frappe.db.get_value("Leave Type", self.leave_type, "is_earned_leave")\
and not frappe.db.get_value("Leave Type", self.leave_type, "is_compensatory"):
@@ -121,27 +114,28 @@ class LeaveAllocation(Document):
else:
frappe.throw(_("Total allocated leaves {0} cannot be less than already approved leaves {1} for the period").format(self.total_leaves_allocated, leaves_taken), LessAllocationError)
- def set_carry_forward_leaves(self):
-
- leaves_allocated
- # check number of days to expire, ignore expiry for default value
+ def set_carry_forwarded_leaves(self):
+ # check number of days to expire, ignore expiry for default value 0
expiry_days = frappe.db.get_value("Leave Type",
filters={"leave_type": leave_type, "is_carry_forward": 1},
fieldname="carry_forward_leave_expiry")
- max_leaves_allowed = frappe.db.get_value("Leave Type", self.leave_type, "max_leaves_allowed")
+ self.carry_forwarded_leaves = get_carry_forwarded_leaves(self.employee, self.leave_type, self.from_date, expiry_days)
+ max_leaves, leaves_allocated = self.get_max_leaves_with_leaves_allocated_for_leave_type(self.carry_forwarded_leaves)
+ if leaves_allocated > max_leaves:
+ self.carry_forwarded_leaves = max_leaves - (leaves_allocated - self.carry_forwarded_leaves)
+
+ def get_max_leaves_with_leaves_allocated_for_leave_type(self, new_leaves):
+ ''' compare new leaves allocated with max leaves '''
+ company = frappe.db.get_value("Employee", self.employee, "company")
leave_period = get_leave_period(self.from_date, self.to_date, company)
- if leave_period:
- leave_allocated = get_leave_allocation_for_period(self.employee, self.leave_type, leave_period[0].from_date, leave_period[0].to_date)
-
- carry_forwarded_leaves = get_carry_forwarded_leaves(self.employee, self.leave_type,
- self.from_date, expiry_days)
- leaves_allocated += carry_forwarded_leaves
-
- if leaves_allocated > max_leaves_allowed:
- self.total_leaves_allocated = max_leaves_allowed - leaves_allocated
- else:
- self.total_leaves_allocated = carry_forwarded_leaves
+ max_leaves_allowed = frappe.db.get_value("Leave Type", self.leave_type, "max_leaves_allowed")
+ if max_leaves_allowed > 0:
+ leave_allocated = 0
+ if leave_period:
+ leave_allocated = get_leave_allocation_for_period(self.employee, self.leave_type, leave_period[0].from_date, leave_period[0].to_date)
+ leave_allocated += new_leaves
+ return max_leaves_allowed, leaves_allocated
def get_leave_allocation_for_period(employee, leave_type, from_date, to_date):
leave_allocated = 0
From 4badca54af4b06d127836e60af0dd5f7d9091f1d Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Tue, 23 Apr 2019 18:26:24 +0530
Subject: [PATCH 010/484] feat: validate leave expiry days
---
erpnext/hr/doctype/leave_type/leave_type.json | 6 +++---
erpnext/hr/doctype/leave_type/leave_type.py | 5 +++--
2 files changed, 6 insertions(+), 5 deletions(-)
diff --git a/erpnext/hr/doctype/leave_type/leave_type.json b/erpnext/hr/doctype/leave_type/leave_type.json
index ee9b04fc00..0b8e38ea73 100644
--- a/erpnext/hr/doctype/leave_type/leave_type.json
+++ b/erpnext/hr/doctype/leave_type/leave_type.json
@@ -422,7 +422,7 @@
"depends_on": "",
"description": "calculated in days",
"fetch_if_empty": 0,
- "fieldname": "carry_forward__leave_expiry",
+ "fieldname": "carry_forward_leave_expiry",
"fieldtype": "Int",
"hidden": 0,
"ignore_user_permissions": 0,
@@ -431,7 +431,7 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
- "label": "Carry Forward Leave Expiry",
+ "label": "Carry Forward Leave Expiry",
"length": 0,
"no_copy": 0,
"permlevel": 0,
@@ -729,7 +729,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2019-04-04 14:27:47.742997",
+ "modified": "2019-04-11 15:38:39.334283",
"modified_by": "Administrator",
"module": "HR",
"name": "Leave Type",
diff --git a/erpnext/hr/doctype/leave_type/leave_type.py b/erpnext/hr/doctype/leave_type/leave_type.py
index 9cd574a598..da21f7827b 100644
--- a/erpnext/hr/doctype/leave_type/leave_type.py
+++ b/erpnext/hr/doctype/leave_type/leave_type.py
@@ -4,6 +4,7 @@
from __future__ import unicode_literals
import calendar
import frappe
+from datetime import datetime
from frappe import _
from frappe.model.document import Document
@@ -14,6 +15,6 @@ class LeaveType(Document):
self.validate_carry_forward()
def validate_carry_forward(self):
- max_days = 366 if calendar.isleap() else 365
- if not (1 < self.carry_forward_leave_expiry < max_days):
+ max_days = 366 if calendar.isleap(datetime.now().year) else 365
+ if not (0 <= self.carry_forward_leave_expiry <= max_days):
frappe.throw(_('Invalid entry!! Carried forward days need to expire within a year'))
From 99c9cfaaedd069c4053a190a37a681ca2f79eea9 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Tue, 23 Apr 2019 18:28:28 +0530
Subject: [PATCH 011/484] feat: generate leave allocation for carry forwarded
leaves
---
.../hr/doctype/leave_period/leave_period.py | 38 ++++++++++++++-----
1 file changed, 28 insertions(+), 10 deletions(-)
diff --git a/erpnext/hr/doctype/leave_period/leave_period.py b/erpnext/hr/doctype/leave_period/leave_period.py
index 15fa8d6f8c..1e2884d202 100644
--- a/erpnext/hr/doctype/leave_period/leave_period.py
+++ b/erpnext/hr/doctype/leave_period/leave_period.py
@@ -5,9 +5,10 @@
from __future__ import unicode_literals
import frappe
from frappe import _
-from frappe.utils import getdate, cstr
+from frappe.utils import getdate, cstr, add_days
from frappe.model.document import Document
from erpnext.hr.utils import validate_overlap, get_employee_leave_policy
+from erpnext.hr.doctype.leave_allocation.leave_allocation import get_carry_forwarded_leaves
from frappe.utils.background_jobs import enqueue
from six import iteritems
@@ -39,8 +40,8 @@ class LeavePeriod(Document):
employee=None, carry_forward_leaves=0):
employees = self.get_employees({
"grade": grade,
- "department": department,
- "designation": designation,
+ "department": department,
+ "designation": designation,
"name": employee
})
@@ -57,7 +58,7 @@ def grant_leave_alloc_for_employees(employees, leave_period, carry_forward_leave
leave_allocations = []
existing_allocations_for = get_existing_allocations(employees, leave_period.name)
leave_type_details = get_leave_type_details()
- count=0
+ count = 0
for employee in employees:
if employee in existing_allocations_for:
continue
@@ -77,8 +78,14 @@ def grant_leave_alloc_for_employees(employees, leave_period, carry_forward_leave
def get_existing_allocations(employees, leave_period):
leave_allocations = frappe.db.sql_list("""
- select distinct employee from `tabLeave Allocation`
- where leave_period=%s and employee in (%s) and docstatus=1
+ SELECT DISTINCT
+ employee
+ FROM `tabLeave Allocation`
+ WHERE
+ leave_period=%s
+ AND employee in (%s)
+ AND carry_forward=0
+ AND docstatus=1
""" % ('%s', ', '.join(['%s']*len(employees))), [leave_period] + employees)
if leave_allocations:
frappe.msgprint(_("Skipping Leave Allocation for the following employees, as Leave Allocation records already exists against them. {0}")
@@ -87,7 +94,8 @@ def get_existing_allocations(employees, leave_period):
def get_leave_type_details():
leave_type_details = frappe._dict()
- leave_types = frappe.get_all("Leave Type", fields=["name", "is_lwp", "is_earned_leave", "is_compensatory", "is_carry_forward"])
+ leave_types = frappe.get_all("Leave Type",
+ fields=["name", "is_lwp", "is_earned_leave", "is_compensatory", "is_carry_forward", "carry_forward_leave_expiry"])
for d in leave_types:
leave_type_details.setdefault(d.name, d)
return leave_type_details
@@ -106,9 +114,19 @@ def create_leave_allocation(employee, leave_type, new_leaves_allocated, leave_ty
allocation.leave_period = leave_period.name
if carry_forward_leaves:
if leave_type_details.get(leave_type).is_carry_forward:
- allocation.carry_forward = carry_forward_leaves
- allocation.save(ignore_permissions = True)
+ create_carry_forward_leaves_allocation(employee, leave_type, leave_type_details, leave_period, carry_forward_leaves)
+ allocation.save(ignore_permissions=True)
allocation.submit()
return allocation.name
-
+def create_carry_forward_leaves_allocation(employee, leave_type, leave_type_details, leave_period, carry_forward_leaves):
+ allocation = frappe.new_doc("Leave Allocation")
+ allocation.employee = employee
+ allocation.leave_type = leave_type
+ allocation.from_date = leave_period.from_date
+ allocation.to_date = add_days(leave_period.from_date, leave_type_details.carry_forward_leave_expiry) if not leave_type_details.carry_forward_leave_expiry else leave_period.to_date
+ allocation.leave_period = leave_period.name
+ allocation.carry_forward = carry_forward_leaves
+ allocation.carry_forwarded_leaves = get_carry_forwarded_leaves(employee, leave_type, leave_period.from_date, leave_type_details.carry_forward_leave_expiry)
+ allocation.save(ignore_permissions=True)
+ allocation.submit()
\ No newline at end of file
From 70cf4a67967ceb1525cc1f98340ae81c4180f1d8 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Wed, 24 Apr 2019 13:17:16 +0530
Subject: [PATCH 012/484] feat: validate leave allocation period to be within
expiry limits
---
.../leave_allocation/leave_allocation.py | 32 ++++++++++++++-----
.../hr/doctype/leave_period/leave_period.py | 2 +-
2 files changed, 25 insertions(+), 9 deletions(-)
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.py b/erpnext/hr/doctype/leave_allocation/leave_allocation.py
index 7f8f806f3b..0c00afff66 100755
--- a/erpnext/hr/doctype/leave_allocation/leave_allocation.py
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.py
@@ -44,9 +44,17 @@ class LeaveAllocation(Document):
self.validate_against_leave_applications()
def validate_period(self):
- if date_diff(self.to_date, self.from_date) <= 0:
+ allocation_period = date_diff(self.to_date, self.from_date)
+
+ if allocation_period <= 0:
frappe.throw(_("To date cannot be before from date"))
+ # check if the allocation period is more than the expiry allows for carry forwarded allocation
+ if self.carry_forward:
+ expiry_days = get_days_to_expiry_for_leave_type(self.leave_type)
+ if allocation_period > expiry_days:
+ frappe.throw(_("Leave allocation period cannot be more than the expiry days allocated"))
+
def validate_lwp(self):
if frappe.db.get_value("Leave Type", self.leave_type, "is_lwp"):
frappe.throw(_("Leave Type {0} cannot be allocated since it is leave without pay").format(self.leave_type))
@@ -115,13 +123,10 @@ class LeaveAllocation(Document):
frappe.throw(_("Total allocated leaves {0} cannot be less than already approved leaves {1} for the period").format(self.total_leaves_allocated, leaves_taken), LessAllocationError)
def set_carry_forwarded_leaves(self):
- # check number of days to expire, ignore expiry for default value 0
- expiry_days = frappe.db.get_value("Leave Type",
- filters={"leave_type": leave_type, "is_carry_forward": 1},
- fieldname="carry_forward_leave_expiry")
+ self.carry_forwarded_leaves = get_carry_forwarded_leaves(self.employee, self.leave_type, self.from_date)
- self.carry_forwarded_leaves = get_carry_forwarded_leaves(self.employee, self.leave_type, self.from_date, expiry_days)
max_leaves, leaves_allocated = self.get_max_leaves_with_leaves_allocated_for_leave_type(self.carry_forwarded_leaves)
+
if leaves_allocated > max_leaves:
self.carry_forwarded_leaves = max_leaves - (leaves_allocated - self.carry_forwarded_leaves)
@@ -168,9 +173,10 @@ def get_leave_allocation_for_period(employee, leave_type, from_date, to_date):
return leave_allocated
@frappe.whitelist()
-def get_carry_forwarded_leaves(employee, leave_type, date, expiry_days):
+def get_carry_forwarded_leaves(employee, leave_type, date):
+ ''' Calculates carry forwarded days based on previous unused leave allocations '''
carry_forwarded_leaves = 0
-
+ expiry_days = get_days_to_expiry_for_leave_type(leave_type)
validate_carry_forward(leave_type)
filters = {
"employee": employee,
@@ -179,6 +185,8 @@ def get_carry_forwarded_leaves(employee, leave_type, date, expiry_days):
"to_date": ("<", date)
}
limit = 1
+
+ # check number of days to expire, ignore expiry for default value 0
if expiry_days:
filters.update(carry_forward=0)
limit = 2
@@ -197,6 +205,14 @@ def get_carry_forwarded_leaves(employee, leave_type, date, expiry_days):
return carry_forwarded_leaves
+def get_days_to_expiry_for_leave_type(leave_type):
+ ''' returns days to expiry for a provided leave type '''
+ expiry_days = frappe.db.get_value("Leave Type",
+ filters={"leave_type": leave_type, "is_carry_forward": 1},
+ fieldname="carry_forward_leave_expiry")
+
+
+
def validate_carry_forward(leave_type):
if not frappe.db.get_value("Leave Type", leave_type, "is_carry_forward"):
frappe.throw(_("Leave Type {0} cannot be carry-forwarded").format(leave_type))
\ No newline at end of file
diff --git a/erpnext/hr/doctype/leave_period/leave_period.py b/erpnext/hr/doctype/leave_period/leave_period.py
index 1e2884d202..0c83a1e548 100644
--- a/erpnext/hr/doctype/leave_period/leave_period.py
+++ b/erpnext/hr/doctype/leave_period/leave_period.py
@@ -127,6 +127,6 @@ def create_carry_forward_leaves_allocation(employee, leave_type, leave_type_deta
allocation.to_date = add_days(leave_period.from_date, leave_type_details.carry_forward_leave_expiry) if not leave_type_details.carry_forward_leave_expiry else leave_period.to_date
allocation.leave_period = leave_period.name
allocation.carry_forward = carry_forward_leaves
- allocation.carry_forwarded_leaves = get_carry_forwarded_leaves(employee, leave_type, leave_period.from_date, leave_type_details.carry_forward_leave_expiry)
+ allocation.carry_forwarded_leaves = get_carry_forwarded_leaves(employee, leave_type, leave_period.from_date)
allocation.save(ignore_permissions=True)
allocation.submit()
\ No newline at end of file
From d01863707c891a83305f05cc6da0457a163a28e0 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Thu, 25 Apr 2019 19:40:37 +0530
Subject: [PATCH 013/484] test: pass leave type as params
---
.../leave_allocation/test_leave_allocation.py | 52 ++++++++-----------
.../hr/doctype/leave_type/test_leave_type.py | 3 +-
2 files changed, 23 insertions(+), 32 deletions(-)
diff --git a/erpnext/hr/doctype/leave_allocation/test_leave_allocation.py b/erpnext/hr/doctype/leave_allocation/test_leave_allocation.py
index 3bc8dc458d..325f3a7299 100644
--- a/erpnext/hr/doctype/leave_allocation/test_leave_allocation.py
+++ b/erpnext/hr/doctype/leave_allocation/test_leave_allocation.py
@@ -1,7 +1,7 @@
from __future__ import unicode_literals
import frappe
import unittest
-from frappe.utils import nowdate, add_months, getdate
+from frappe.utils import nowdate, add_months, getdate, add_days
from erpnext.hr.doctype.leave_type.test_leave_type import create_leave_type
class TestLeaveAllocation(unittest.TestCase):
@@ -71,36 +71,27 @@ class TestLeaveAllocation(unittest.TestCase):
def test_carry_forward_allocation(self):
frappe.db.sql("delete from `tabLeave Allocation`")
- employee = frappe.get_doc("Employee", frappe.db.sql_list("select name from tabEmployee limit 1")[0])
- doc = frappe.get_doc({
- "doctype": "Leave Allocation",
- "__islocal": 1,
- "employee": employee.name,
- "employee_name": employee.employee_name,
- "leave_type": "_Test Leave Type Carry Forward",
- "from_date": nowdate(),
- "to_date": add_months(nowdate(),-12),
- "new_leaves_allocated": 10
- })
- doc.save()
- doc = frappe.get_doc({
- "doctype": "Leave Allocation",
- "__islocal": 1,
- "employee": employee.name,
- "employee_name": employee.employee_name,
- "leave_type": "_Test Leave Type Carry Forward",
- "from_date": nowdate(),
- "to_date": add_months(now_date(),12),
- "carry_forward": 1
- })
- doc.save()
- self.assertEquals(doc.total_leaves_allocated, 10)
+ leave_type = create_leave_type(
+ leave_type_name="_Test Carry Forward",
+ is_carry_forward=1,
+ carry_forward_leave_expiry=366)
+ leave_type.submit()
+
+ leave_allocation = create_leave_allocation(
+ from_date=add_months(nowdate(), -12),
+ to_date=add_days(nowdate(), -1),
+ leave_type=leave_type
+ )
+ leave_allocation.new_leaves_allocated = 10
+ leave_allocation.submit()
+
+ carry_forward_alloc = create_leave_allocation(leave_type=leave_type)
+ carry_forward_alloc.carry_forward = 1
+ carry_forward_alloc.save()
+ self.assertEquals(carry_forward_alloc.total_leaves_allocated, 10)
def create_leave_allocation(**args):
args = frappe._dict(args)
- if not frappe.db.exists("Leave Type", "_Test Leave Type"):
- leave_type = create_leave_type(args.leave_type)
- leave_type.insert()
employee = frappe.get_doc("Employee", frappe.db.sql_list("select name from tabEmployee limit 1")[0])
leave_allocation = frappe.get_doc({
@@ -108,10 +99,9 @@ def create_leave_allocation(**args):
"__islocal": 1,
"employee": employee.name,
"employee_name": employee.employee_name,
- "leave_type": args.leave_type or "_Test Leave Type",
+ "leave_type": args.leave_type.leave_type_name or "_Test Leave Type",
"from_date": args.from_date or nowdate(),
- "to_date": args.to_date or add_months(nowdate(), 12),
- "new_leaves_allocated": args.new_leaves_allocated or 20
+ "to_date": args.to_date or add_months(nowdate(), 12)
})
return leave_allocation
diff --git a/erpnext/hr/doctype/leave_type/test_leave_type.py b/erpnext/hr/doctype/leave_type/test_leave_type.py
index 671865b5a0..1006550de4 100644
--- a/erpnext/hr/doctype/leave_type/test_leave_type.py
+++ b/erpnext/hr/doctype/leave_type/test_leave_type.py
@@ -8,6 +8,7 @@ from frappe import _
test_records = frappe.get_test_records('Leave Type')
def create_leave_type(**args):
+ args = frappe._dict(args)
if frappe.db.exists("Leave Type", args.leave_type_name):
return frappe.get_doc("Leave Type", args.leave_type_name)
leave_type = frappe.get_doc({
@@ -18,7 +19,7 @@ def create_leave_type(**args):
"is_earned_leave": args.is_earned_leave or 0,
"is_lwp": args.is_lwp or 0,
"is_carry_forward": args.is_carry_forward or 0,
- "carry_forward_leave_expiry": args.is_carry_forward or 0,
+ "carry_forward_leave_expiry": args.carry_forward_leave_expiry or 0,
"encashment_threshold_days": args.encashment_threshold_days or 5,
"earning_component": "Leave Encashment"
})
From 0abf5d340cbbfcc9d05cb51243ce9a47dca2d1e0 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Thu, 25 Apr 2019 19:52:45 +0530
Subject: [PATCH 014/484] fix: carry forwarded allocation period validation
---
.../leave_allocation/leave_allocation.py | 31 +++++++++----------
.../hr/doctype/leave_period/leave_period.py | 5 ++-
erpnext/hr/doctype/leave_type/leave_type.py | 4 +--
3 files changed, 21 insertions(+), 19 deletions(-)
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.py b/erpnext/hr/doctype/leave_allocation/leave_allocation.py
index 0c00afff66..f7db7dee86 100755
--- a/erpnext/hr/doctype/leave_allocation/leave_allocation.py
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.py
@@ -19,19 +19,19 @@ class LeaveAllocation(Document):
def validate(self):
self.validate_period()
self.validate_lwp()
+ set_employee_name(self)
+ self.set_total_leaves_allocated()
self.validate_allocation_overlap()
self.validate_back_dated_allocation()
self.validate_total_leaves_allocated()
- set_employee_name(self)
self.validate_leaves_allocated_value()
self.validate_leave_allocation_days()
- self.set_total_leaves_allocated()
def validate_leave_allocation_days(self):
- new_leaves = self.new_leaves_allocate if not self.carry_forward else self.carry_forwarded_leaves
+ new_leaves = self.new_leaves_allocated if not self.carry_forward else self.carry_forwarded_leaves
max_leaves, leaves_allocated = self.get_max_leaves_with_leaves_allocated_for_leave_type(flt(new_leaves))
- if leave_allocated > max_leaves:
+ if leaves_allocated > max_leaves:
frappe.throw(_("Total allocated leaves are more days than maximum allocation of {0} leave type for employee {1} in the period")\
.format(self.leave_type, self.employee))
@@ -52,8 +52,9 @@ class LeaveAllocation(Document):
# check if the allocation period is more than the expiry allows for carry forwarded allocation
if self.carry_forward:
expiry_days = get_days_to_expiry_for_leave_type(self.leave_type)
- if allocation_period > expiry_days:
- frappe.throw(_("Leave allocation period cannot be more than the expiry days allocated"))
+
+ if allocation_period > flt(expiry_days) and expiry_days:
+ frappe.throw(_("Leave allocation period cannot exceed carry forward expiry limit"))
def validate_lwp(self):
if frappe.db.get_value("Leave Type", self.leave_type, "is_lwp"):
@@ -109,7 +110,7 @@ class LeaveAllocation(Document):
def validate_total_leaves_allocated(self):
# Adding a day to include To Date in the difference
date_difference = date_diff(self.to_date, self.from_date) + 1
- if date_difference < self.total_leaves_allocated:
+ if date_difference < flt(self.total_leaves_allocated):
frappe.throw(_("Total allocated leaves are more than days in the period"), OverAllocationError)
def validate_against_leave_applications(self):
@@ -133,13 +134,13 @@ class LeaveAllocation(Document):
def get_max_leaves_with_leaves_allocated_for_leave_type(self, new_leaves):
''' compare new leaves allocated with max leaves '''
company = frappe.db.get_value("Employee", self.employee, "company")
+ leaves_allocated = 0
leave_period = get_leave_period(self.from_date, self.to_date, company)
max_leaves_allowed = frappe.db.get_value("Leave Type", self.leave_type, "max_leaves_allowed")
if max_leaves_allowed > 0:
- leave_allocated = 0
if leave_period:
- leave_allocated = get_leave_allocation_for_period(self.employee, self.leave_type, leave_period[0].from_date, leave_period[0].to_date)
- leave_allocated += new_leaves
+ leaves_allocated = get_leave_allocation_for_period(self.employee, self.leave_type, leave_period[0].from_date, leave_period[0].to_date)
+ leaves_allocated += new_leaves
return max_leaves_allowed, leaves_allocated
def get_leave_allocation_for_period(employee, leave_type, from_date, to_date):
@@ -184,12 +185,12 @@ def get_carry_forwarded_leaves(employee, leave_type, date):
"docstatus": 1,
"to_date": ("<", date)
}
- limit = 1
+ limit = 2
# check number of days to expire, ignore expiry for default value 0
if expiry_days:
filters.update(carry_forward=0)
- limit = 2
+ limit = 1
previous_allocation = frappe.get_all("Leave Allocation",
filters=filters,
@@ -207,12 +208,10 @@ def get_carry_forwarded_leaves(employee, leave_type, date):
def get_days_to_expiry_for_leave_type(leave_type):
''' returns days to expiry for a provided leave type '''
- expiry_days = frappe.db.get_value("Leave Type",
- filters={"leave_type": leave_type, "is_carry_forward": 1},
+ return frappe.db.get_value("Leave Type",
+ filters={"leave_type_name": leave_type, "is_carry_forward": 1},
fieldname="carry_forward_leave_expiry")
-
-
def validate_carry_forward(leave_type):
if not frappe.db.get_value("Leave Type", leave_type, "is_carry_forward"):
frappe.throw(_("Leave Type {0} cannot be carry-forwarded").format(leave_type))
\ No newline at end of file
diff --git a/erpnext/hr/doctype/leave_period/leave_period.py b/erpnext/hr/doctype/leave_period/leave_period.py
index 0c83a1e548..a6198a8918 100644
--- a/erpnext/hr/doctype/leave_period/leave_period.py
+++ b/erpnext/hr/doctype/leave_period/leave_period.py
@@ -120,6 +120,9 @@ def create_leave_allocation(employee, leave_type, new_leaves_allocated, leave_ty
return allocation.name
def create_carry_forward_leaves_allocation(employee, leave_type, leave_type_details, leave_period, carry_forward_leaves):
+ carry_forwarded_leaves = get_carry_forwarded_leaves(employee, leave_type, leave_period.from_date)
+ if not carry_forwarded_leaves:
+ return
allocation = frappe.new_doc("Leave Allocation")
allocation.employee = employee
allocation.leave_type = leave_type
@@ -127,6 +130,6 @@ def create_carry_forward_leaves_allocation(employee, leave_type, leave_type_deta
allocation.to_date = add_days(leave_period.from_date, leave_type_details.carry_forward_leave_expiry) if not leave_type_details.carry_forward_leave_expiry else leave_period.to_date
allocation.leave_period = leave_period.name
allocation.carry_forward = carry_forward_leaves
- allocation.carry_forwarded_leaves = get_carry_forwarded_leaves(employee, leave_type, leave_period.from_date)
+ allocation.carry_forwarded_leaves = carry_forwarded_leaves
allocation.save(ignore_permissions=True)
allocation.submit()
\ No newline at end of file
diff --git a/erpnext/hr/doctype/leave_type/leave_type.py b/erpnext/hr/doctype/leave_type/leave_type.py
index da21f7827b..dcae5fe085 100644
--- a/erpnext/hr/doctype/leave_type/leave_type.py
+++ b/erpnext/hr/doctype/leave_type/leave_type.py
@@ -15,6 +15,6 @@ class LeaveType(Document):
self.validate_carry_forward()
def validate_carry_forward(self):
- max_days = 366 if calendar.isleap(datetime.now().year) else 365
+ max_days = 367 if calendar.isleap(datetime.now().year) else 366
if not (0 <= self.carry_forward_leave_expiry <= max_days):
- frappe.throw(_('Invalid entry!! Carried forward days need to expire within a year'))
+ frappe.throw(_('Invalid entry!! Carried forward days need to expire within a year'))
\ No newline at end of file
From 5e2b067107b5ab18d7cc1e863b5cd8d908ee23f7 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Thu, 25 Apr 2019 19:54:40 +0530
Subject: [PATCH 015/484] feat: display carry forwarded allocation days and
total leaves allocated
---
.../leave_allocation/leave_allocation.js | 17 +++++++----------
1 file changed, 7 insertions(+), 10 deletions(-)
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.js b/erpnext/hr/doctype/leave_allocation/leave_allocation.js
index 4b4bfafd16..0014c07a3c 100755
--- a/erpnext/hr/doctype/leave_allocation/leave_allocation.js
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.js
@@ -34,34 +34,31 @@ frappe.ui.form.on("Leave Allocation", {
},
carry_forwarded_leaves: function(frm) {
- frm.set_value("total_leaves_allocated",
- flt(frm.doc.carry_forwarded_leaves) + flt(frm.doc.new_leaves_allocated));
+ frm.set_value("total_leaves_allocated", flt(frm.doc.carry_forwarded_leaves));
},
new_leaves_allocated: function(frm) {
- frm.set_value("total_leaves_allocated",
- flt(frm.doc.carry_forwarded_leaves) + flt(frm.doc.new_leaves_allocated));
+ frm.set_value("total_leaves_allocated", flt(frm.doc.new_leaves_allocated));
},
calculate_total_leaves_allocated: function(frm) {
- if (cint(frm.doc.carry_forward) == 1 && frm.doc.leave_type && frm.doc.employee) {
+ if (cint(frm.doc.carry_forward) === 1 && frm.doc.leave_type && frm.doc.employee) {
return frappe.call({
method: "erpnext.hr.doctype.leave_allocation.leave_allocation.get_carry_forwarded_leaves",
args: {
"employee": frm.doc.employee,
- "date": frm.doc.from_date,
"leave_type": frm.doc.leave_type,
- "carry_forward": frm.doc.carry_forward
+ "date": frm.doc.from_date,
},
callback: function(r) {
if (!r.exc && r.message) {
+ frm.set_value("new_leaves_allocated", 0);
frm.set_value('carry_forwarded_leaves', r.message);
- frm.set_value("total_leaves_allocated",
- flt(r.message) + flt(frm.doc.new_leaves_allocated));
+ frm.set_value("total_leaves_allocated", flt(r.message));
}
}
})
- } else if (cint(frm.doc.carry_forward) == 0) {
+ } else if (cint(frm.doc.carry_forward) === 0) {
frm.set_value("carry_forwarded_leaves", 0);
frm.set_value("total_leaves_allocated", flt(frm.doc.new_leaves_allocated));
}
From 1de990b2ac71f95468285cdce119f83295906210 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Thu, 9 May 2019 16:51:02 +0530
Subject: [PATCH 016/484] feat: create leave ledger entry
---
.../hr/doctype/leave_ledger_entry/__init__.py | 0
.../leave_ledger_entry/leave_ledger_entry.js | 8 ++
.../leave_ledger_entry.json | 99 +++++++++++++++++++
.../leave_ledger_entry/leave_ledger_entry.py | 39 ++++++++
.../test_leave_ledger_entry.py | 10 ++
5 files changed, 156 insertions(+)
create mode 100644 erpnext/hr/doctype/leave_ledger_entry/__init__.py
create mode 100644 erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.js
create mode 100644 erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.json
create mode 100644 erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
create mode 100644 erpnext/hr/doctype/leave_ledger_entry/test_leave_ledger_entry.py
diff --git a/erpnext/hr/doctype/leave_ledger_entry/__init__.py b/erpnext/hr/doctype/leave_ledger_entry/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.js b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.js
new file mode 100644
index 0000000000..c68d518f67
--- /dev/null
+++ b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.js
@@ -0,0 +1,8 @@
+// Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Leave Ledger Entry', {
+ // refresh: function(frm) {
+
+ // }
+});
diff --git a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.json b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.json
new file mode 100644
index 0000000000..8ef302452d
--- /dev/null
+++ b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.json
@@ -0,0 +1,99 @@
+{
+ "creation": "2019-05-09 15:47:39.760406",
+ "doctype": "DocType",
+ "engine": "InnoDB",
+ "field_order": [
+ "employee",
+ "employee_name",
+ "leave_type",
+ "transaction_type",
+ "transaction_name",
+ "leaves",
+ "from_date",
+ "to_date",
+ "is_carry_forward",
+ "amended_from"
+ ],
+ "fields": [
+ {
+ "fieldname": "employee",
+ "fieldtype": "Link",
+ "label": "Employee",
+ "options": "Employee"
+ },
+ {
+ "fieldname": "employee_name",
+ "fieldtype": "Data",
+ "label": "Employee Name"
+ },
+ {
+ "fieldname": "leave_type",
+ "fieldtype": "Link",
+ "label": "Leave Type",
+ "options": "Leave Type"
+ },
+ {
+ "fieldname": "amended_from",
+ "fieldtype": "Link",
+ "label": "Amended From",
+ "no_copy": 1,
+ "options": "Leave Ledger Entry",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "fieldname": "transaction_type",
+ "fieldtype": "Link",
+ "label": "Transaction Type",
+ "options": "DocType"
+ },
+ {
+ "fieldname": "transaction_name",
+ "fieldtype": "Dynamic Link",
+ "label": "Transaction Name",
+ "options": "transaction_type"
+ },
+ {
+ "fieldname": "leaves",
+ "fieldtype": "Int",
+ "label": "Leaves"
+ },
+ {
+ "fieldname": "from_date",
+ "fieldtype": "Date",
+ "label": "From Date"
+ },
+ {
+ "fieldname": "to_date",
+ "fieldtype": "Date",
+ "label": "To Date"
+ },
+ {
+ "fieldname": "is_carry_forward",
+ "fieldtype": "Check",
+ "label": "Is Carry Forward"
+ }
+ ],
+ "is_submittable": 1,
+ "modified": "2019-05-09 15:54:52.834794",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Leave Ledger Entry",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "System Manager",
+ "share": 1,
+ "write": 1
+ }
+ ],
+ "sort_field": "modified",
+ "sort_order": "ASC"
+}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
new file mode 100644
index 0000000000..dd8de56717
--- /dev/null
+++ b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
@@ -0,0 +1,39 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+# import frappe
+from frappe.model.document import Document
+from frappe.utils import add_days
+
+class LeaveLedgerEntry(Document):
+ pass
+
+def create_leave_ledger_entry(ref_doc, submit=True):
+ ledger = dict(
+ doctype='Leave Ledger Entry',
+ employee=ref_doc.employee,
+ employee_name=ref_doc.employee_name,
+ leave_type=ref_doc.leave_type,
+ from_date=ref_doc.from_date,
+ transaction_document_type=ref_doc.doctype,
+ transaction_document_name=ref_doc.name
+ )
+
+ if ref_doc.carry_forwarded_leaves:
+ expiry_days = frappe.db.get_value("Leave Type", ref_doc.leave_type, "carry_forward_leave_expiry")
+
+ ledger.update(dict(
+ leaves=ref_doc.carry_forwarded_leaves * 1 if submit else -1,
+ to_date=add_days(ref_doc.from_date, expiry_days) if expiry_days else ref_doc.to_date,
+ is_carry_forward=1
+ ))
+ frappe.get_doc(ledger).insert()
+
+ ledger.update(dict(
+ leaves=ref_doc.new_leaves_allocated * 1 if submit else -1,
+ to_date=ref_doc.to_date,
+ is_carry_forward=0
+ ))
+ frappe.get_doc(ledger).insert()
\ No newline at end of file
diff --git a/erpnext/hr/doctype/leave_ledger_entry/test_leave_ledger_entry.py b/erpnext/hr/doctype/leave_ledger_entry/test_leave_ledger_entry.py
new file mode 100644
index 0000000000..6f7725c254
--- /dev/null
+++ b/erpnext/hr/doctype/leave_ledger_entry/test_leave_ledger_entry.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+# import frappe
+import unittest
+
+class TestLeaveLedgerEntry(unittest.TestCase):
+ pass
From 2b421c39b5c0dbf7ea8e5a9a567bd124b527af15 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Thu, 9 May 2019 19:36:01 +0530
Subject: [PATCH 017/484] feat: add transaction details in ledger
---
.../leave_allocation/leave_allocation.json | 1491 ++++++++---------
.../leave_ledger_entry.json | 2 +-
.../leave_ledger_entry/leave_ledger_entry.py | 11 +-
3 files changed, 741 insertions(+), 763 deletions(-)
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.json b/erpnext/hr/doctype/leave_allocation/leave_allocation.json
index 0903398d1f..12c74de9d0 100644
--- a/erpnext/hr/doctype/leave_allocation/leave_allocation.json
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.json
@@ -1,757 +1,736 @@
{
- "allow_copy": 0,
- "allow_events_in_timeline": 0,
- "allow_guest_to_view": 0,
- "allow_import": 1,
- "allow_rename": 0,
- "autoname": "naming_series:",
- "beta": 0,
- "creation": "2013-02-20 19:10:38",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "Setup",
- "editable_grid": 0,
- "engine": "InnoDB",
- "fields": [
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "",
- "fetch_if_empty": 0,
- "fieldname": "naming_series",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Series",
- "length": 0,
- "no_copy": 1,
- "options": "HR-LAL-.YYYY.-",
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 1,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "employee",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 1,
- "in_list_view": 1,
- "in_standard_filter": 1,
- "label": "Employee",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "employee",
- "oldfieldtype": "Link",
- "options": "Employee",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 1,
- "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,
- "fetch_from": "employee.employee_name",
- "fetch_if_empty": 0,
- "fieldname": "employee_name",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 1,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Employee Name",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 1,
- "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,
- "fetch_from": "employee.department",
- "fetch_if_empty": 0,
- "fieldname": "department",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Department",
- "length": 0,
- "no_copy": 0,
- "options": "Department",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "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,
- "fetch_if_empty": 0,
- "fieldname": "column_break1",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0,
- "width": "50%"
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "leave_type",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 1,
- "label": "Leave Type",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "leave_type",
- "oldfieldtype": "Link",
- "options": "Leave Type",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 1,
- "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,
- "fetch_if_empty": 0,
- "fieldname": "from_date",
- "fieldtype": "Date",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "From Date",
- "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": 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,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "to_date",
- "fieldtype": "Date",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "To Date",
- "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": 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,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "section_break_6",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Allocation",
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 1,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval: doc.carry_forward != 1",
- "fetch_if_empty": 0,
- "fieldname": "new_leaves_allocated",
- "fieldtype": "Float",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "New Leaves Allocated",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval: doc.carry_forward == 1",
- "fetch_if_empty": 0,
- "fieldname": "carry_forwarded_leaves",
- "fieldtype": "Int",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Unused Leaves",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "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,
- "depends_on": "",
- "description": "",
- "fetch_if_empty": 0,
- "fieldname": "carry_forward",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Allocate unused leaves from previous allocations",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
- "fetch_if_empty": 0,
- "fieldname": "total_leaves_allocated",
- "fieldtype": "Float",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Total Leaves Allocated",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "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,
- "columns": 0,
- "depends_on": "eval:doc.total_leaves_encashed>0",
- "fetch_if_empty": 0,
- "fieldname": "total_leaves_encashed",
- "fieldtype": "Float",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Total Leaves Encashed",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "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,
- "fetch_if_empty": 0,
- "fieldname": "column_break_10",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "compensatory_request",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Compensatory Leave Request",
- "length": 0,
- "no_copy": 0,
- "options": "Compensatory Leave Request",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "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,
- "fetch_if_empty": 0,
- "fieldname": "leave_period",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 1,
- "label": "Leave Period",
- "length": 0,
- "no_copy": 0,
- "options": "Leave Period",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "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,
- "fetch_if_empty": 0,
- "fieldname": "amended_from",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 1,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Amended From",
- "length": 0,
- "no_copy": 1,
- "oldfieldname": "amended_from",
- "oldfieldtype": "Data",
- "options": "Leave Allocation",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "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": 1,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "notes",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Notes",
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "description",
- "fieldtype": "Small Text",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Description",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "reason",
- "oldfieldtype": "Small Text",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0,
- "width": "300px"
- }
- ],
- "has_web_view": 0,
- "hide_toolbar": 0,
- "icon": "fa fa-ok",
- "idx": 1,
- "in_create": 0,
- "is_submittable": 1,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2019-04-22 18:33:15.858006",
- "modified_by": "Administrator",
- "module": "HR",
- "name": "Leave Allocation",
- "owner": "Administrator",
- "permissions": [
- {
- "amend": 1,
- "cancel": 1,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "HR User",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 1,
- "write": 1
- },
- {
- "amend": 1,
- "cancel": 1,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 1,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "HR Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 1,
- "write": 1
- }
- ],
- "quick_entry": 0,
- "read_only": 0,
- "search_fields": "employee,employee_name,leave_type,total_leaves_allocated",
- "show_name_in_global_search": 1,
- "sort_field": "modified",
- "sort_order": "DESC",
- "timeline_field": "employee",
- "track_changes": 0,
- "track_seen": 0,
- "track_views": 0
-}
\ No newline at end of file
+ "allow_copy": 0,
+ "allow_events_in_timeline": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 1,
+ "allow_rename": 0,
+ "autoname": "naming_series:",
+ "beta": 0,
+ "creation": "2013-02-20 19:10:38",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "Setup",
+ "editable_grid": 0,
+ "engine": "InnoDB",
+ "fields": [
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "default": "",
+ "fieldname": "naming_series",
+ "fieldtype": "Select",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Series",
+ "length": 0,
+ "no_copy": 1,
+ "options": "HR-LAL-.YYYY.-",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 1,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 1,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "employee",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 1,
+ "in_list_view": 1,
+ "in_standard_filter": 1,
+ "label": "Employee",
+ "length": 0,
+ "no_copy": 0,
+ "oldfieldname": "employee",
+ "oldfieldtype": "Link",
+ "options": "Employee",
+ "permlevel": 0,
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 1,
+ "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,
+ "fetch_from": "employee.employee_name",
+ "fieldname": "employee_name",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 1,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Employee Name",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 1,
+ "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,
+ "fetch_from": "employee.department",
+ "fieldname": "department",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Department",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Department",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "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": "column_break1",
+ "fieldtype": "Column Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "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,
+ "translatable": 0,
+ "unique": 0,
+ "width": "50%"
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "leave_type",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 1,
+ "label": "Leave Type",
+ "length": 0,
+ "no_copy": 0,
+ "oldfieldname": "leave_type",
+ "oldfieldtype": "Link",
+ "options": "Leave Type",
+ "permlevel": 0,
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 1,
+ "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": "from_date",
+ "fieldtype": "Date",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "From Date",
+ "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": 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,
+ "columns": 0,
+ "fieldname": "to_date",
+ "fieldtype": "Date",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "To Date",
+ "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": 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,
+ "columns": 0,
+ "fieldname": "section_break_6",
+ "fieldtype": "Section Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Allocation",
+ "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,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 1,
+ "bold": 1,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "new_leaves_allocated",
+ "fieldtype": "Float",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "New Leaves Allocated",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "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,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "description": "",
+ "fieldname": "carry_forward",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Add unused leaves from previous allocations",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "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,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "depends_on": "carry_forward",
+ "fieldname": "carry_forwarded_leaves",
+ "fieldtype": "Float",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Unused leaves",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "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": 1,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "total_leaves_allocated",
+ "fieldtype": "Float",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Total Leaves Allocated",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "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,
+ "columns": 0,
+ "depends_on": "eval:doc.total_leaves_encashed>0",
+ "fieldname": "total_leaves_encashed",
+ "fieldtype": "Float",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Total Leaves Encashed",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "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": "column_break_10",
+ "fieldtype": "Column Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 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,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "compensatory_request",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Compensatory Leave Request",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Compensatory Leave Request",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "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": "leave_period",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 1,
+ "label": "Leave Period",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Leave Period",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "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": "amended_from",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 1,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Amended From",
+ "length": 0,
+ "no_copy": 1,
+ "oldfieldname": "amended_from",
+ "oldfieldtype": "Data",
+ "options": "Leave Allocation",
+ "permlevel": 0,
+ "print_hide": 1,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "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": 1,
+ "columns": 0,
+ "fieldname": "notes",
+ "fieldtype": "Section Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Notes",
+ "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,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "description",
+ "fieldtype": "Small Text",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Description",
+ "length": 0,
+ "no_copy": 0,
+ "oldfieldname": "reason",
+ "oldfieldtype": "Small Text",
+ "permlevel": 0,
+ "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,
+ "translatable": 0,
+ "unique": 0,
+ "width": "300px"
+ }
+ ],
+ "has_web_view": 0,
+ "hide_heading": 0,
+ "hide_toolbar": 0,
+ "icon": "fa fa-ok",
+ "idx": 1,
+ "image_view": 0,
+ "in_create": 0,
+ "is_submittable": 1,
+ "issingle": 0,
+ "istable": 0,
+ "max_attachments": 0,
+ "modified": "2019-01-30 11:28:09.360525",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Leave Allocation",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "amend": 1,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 0,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "HR User",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 1,
+ "write": 1
+ },
+ {
+ "amend": 1,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "if_owner": 0,
+ "import": 1,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "HR Manager",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 1,
+ "write": 1
+ }
+ ],
+ "quick_entry": 0,
+ "read_only": 0,
+ "read_only_onload": 0,
+ "search_fields": "employee,employee_name,leave_type,total_leaves_allocated",
+ "show_name_in_global_search": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "timeline_field": "employee",
+ "track_changes": 0,
+ "track_seen": 0,
+ "track_views": 0
+ }
\ No newline at end of file
diff --git a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.json b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.json
index 8ef302452d..c7e6b709bd 100644
--- a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.json
+++ b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.json
@@ -75,7 +75,7 @@
}
],
"is_submittable": 1,
- "modified": "2019-05-09 15:54:52.834794",
+ "modified": "2019-05-09 18:36:07.383714",
"modified_by": "Administrator",
"module": "HR",
"name": "Leave Ledger Entry",
diff --git a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
index dd8de56717..35dce97936 100644
--- a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
+++ b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
@@ -3,7 +3,7 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-# import frappe
+import frappe
from frappe.model.document import Document
from frappe.utils import add_days
@@ -17,10 +17,9 @@ def create_leave_ledger_entry(ref_doc, submit=True):
employee_name=ref_doc.employee_name,
leave_type=ref_doc.leave_type,
from_date=ref_doc.from_date,
- transaction_document_type=ref_doc.doctype,
- transaction_document_name=ref_doc.name
+ transaction_type=ref_doc.doctype,
+ transaction_name=ref_doc.name
)
-
if ref_doc.carry_forwarded_leaves:
expiry_days = frappe.db.get_value("Leave Type", ref_doc.leave_type, "carry_forward_leave_expiry")
@@ -29,11 +28,11 @@ def create_leave_ledger_entry(ref_doc, submit=True):
to_date=add_days(ref_doc.from_date, expiry_days) if expiry_days else ref_doc.to_date,
is_carry_forward=1
))
- frappe.get_doc(ledger).insert()
+ frappe.get_doc(ledger).submit()
ledger.update(dict(
leaves=ref_doc.new_leaves_allocated * 1 if submit else -1,
to_date=ref_doc.to_date,
is_carry_forward=0
))
- frappe.get_doc(ledger).insert()
\ No newline at end of file
+ frappe.get_doc(ledger).submit()
\ No newline at end of file
From 679371e397a840267d1e29b7d19bdcccf5598f5a Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Thu, 9 May 2019 19:43:35 +0530
Subject: [PATCH 018/484] feat: get carry forwarded leaves via ledger entries
---
.../leave_allocation/leave_allocation.js | 19 +-
.../leave_allocation/leave_allocation.json | 965 +++++-------------
.../leave_allocation/leave_allocation.py | 159 +--
.../hr/doctype/leave_period/leave_period.py | 21 +-
4 files changed, 293 insertions(+), 871 deletions(-)
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.js b/erpnext/hr/doctype/leave_allocation/leave_allocation.js
index 0014c07a3c..228b5528de 100755
--- a/erpnext/hr/doctype/leave_allocation/leave_allocation.js
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.js
@@ -34,33 +34,36 @@ frappe.ui.form.on("Leave Allocation", {
},
carry_forwarded_leaves: function(frm) {
- frm.set_value("total_leaves_allocated", flt(frm.doc.carry_forwarded_leaves));
+ frm.set_value("total_leaves_allocated",
+ flt(frm.doc.carry_forwarded_leaves) + flt(frm.doc.new_leaves_allocated));
},
new_leaves_allocated: function(frm) {
- frm.set_value("total_leaves_allocated", flt(frm.doc.new_leaves_allocated));
+ frm.set_value("total_leaves_allocated",
+ flt(frm.doc.carry_forwarded_leaves) + flt(frm.doc.new_leaves_allocated));
},
calculate_total_leaves_allocated: function(frm) {
- if (cint(frm.doc.carry_forward) === 1 && frm.doc.leave_type && frm.doc.employee) {
+ if (cint(frm.doc.carry_forward) == 1 && frm.doc.leave_type && frm.doc.employee) {
return frappe.call({
method: "erpnext.hr.doctype.leave_allocation.leave_allocation.get_carry_forwarded_leaves",
args: {
"employee": frm.doc.employee,
- "leave_type": frm.doc.leave_type,
"date": frm.doc.from_date,
+ "leave_type": frm.doc.leave_type,
+ "carry_forward": frm.doc.carry_forward
},
callback: function(r) {
if (!r.exc && r.message) {
- frm.set_value("new_leaves_allocated", 0);
frm.set_value('carry_forwarded_leaves', r.message);
- frm.set_value("total_leaves_allocated", flt(r.message));
+ frm.set_value("total_leaves_allocated",
+ flt(r.message) + flt(frm.doc.new_leaves_allocated));
}
}
})
- } else if (cint(frm.doc.carry_forward) === 0) {
+ } else if (cint(frm.doc.carry_forward) == 0) {
frm.set_value("carry_forwarded_leaves", 0);
frm.set_value("total_leaves_allocated", flt(frm.doc.new_leaves_allocated));
}
}
-})
+})
\ No newline at end of file
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.json b/erpnext/hr/doctype/leave_allocation/leave_allocation.json
index 12c74de9d0..bb851c6850 100644
--- a/erpnext/hr/doctype/leave_allocation/leave_allocation.json
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.json
@@ -1,736 +1,231 @@
{
- "allow_copy": 0,
- "allow_events_in_timeline": 0,
- "allow_guest_to_view": 0,
- "allow_import": 1,
- "allow_rename": 0,
- "autoname": "naming_series:",
- "beta": 0,
- "creation": "2013-02-20 19:10:38",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "Setup",
- "editable_grid": 0,
- "engine": "InnoDB",
- "fields": [
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "",
- "fieldname": "naming_series",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Series",
- "length": 0,
- "no_copy": 1,
- "options": "HR-LAL-.YYYY.-",
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 1,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "employee",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 1,
- "in_list_view": 1,
- "in_standard_filter": 1,
- "label": "Employee",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "employee",
- "oldfieldtype": "Link",
- "options": "Employee",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 1,
- "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,
- "fetch_from": "employee.employee_name",
- "fieldname": "employee_name",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 1,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Employee Name",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 1,
- "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,
- "fetch_from": "employee.department",
- "fieldname": "department",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Department",
- "length": 0,
- "no_copy": 0,
- "options": "Department",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "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": "column_break1",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0,
- "width": "50%"
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "leave_type",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 1,
- "label": "Leave Type",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "leave_type",
- "oldfieldtype": "Link",
- "options": "Leave Type",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 1,
- "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": "from_date",
- "fieldtype": "Date",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "From Date",
- "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": 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,
- "columns": 0,
- "fieldname": "to_date",
- "fieldtype": "Date",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "To Date",
- "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": 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,
- "columns": 0,
- "fieldname": "section_break_6",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Allocation",
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 1,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "new_leaves_allocated",
- "fieldtype": "Float",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "New Leaves Allocated",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "",
- "fieldname": "carry_forward",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Add unused leaves from previous allocations",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "carry_forward",
- "fieldname": "carry_forwarded_leaves",
- "fieldtype": "Float",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Unused leaves",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "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": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "total_leaves_allocated",
- "fieldtype": "Float",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Total Leaves Allocated",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "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,
- "columns": 0,
- "depends_on": "eval:doc.total_leaves_encashed>0",
- "fieldname": "total_leaves_encashed",
- "fieldtype": "Float",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Total Leaves Encashed",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "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": "column_break_10",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "compensatory_request",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Compensatory Leave Request",
- "length": 0,
- "no_copy": 0,
- "options": "Compensatory Leave Request",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "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": "leave_period",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 1,
- "label": "Leave Period",
- "length": 0,
- "no_copy": 0,
- "options": "Leave Period",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "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": "amended_from",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 1,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Amended From",
- "length": 0,
- "no_copy": 1,
- "oldfieldname": "amended_from",
- "oldfieldtype": "Data",
- "options": "Leave Allocation",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "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": 1,
- "columns": 0,
- "fieldname": "notes",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Notes",
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "description",
- "fieldtype": "Small Text",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Description",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "reason",
- "oldfieldtype": "Small Text",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0,
- "width": "300px"
- }
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "icon": "fa fa-ok",
- "idx": 1,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 1,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2019-01-30 11:28:09.360525",
- "modified_by": "Administrator",
- "module": "HR",
- "name": "Leave Allocation",
- "owner": "Administrator",
- "permissions": [
- {
- "amend": 1,
- "cancel": 1,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "HR User",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 1,
- "write": 1
- },
- {
- "amend": 1,
- "cancel": 1,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 1,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "HR Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 1,
- "write": 1
- }
- ],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "search_fields": "employee,employee_name,leave_type,total_leaves_allocated",
- "show_name_in_global_search": 1,
- "sort_field": "modified",
- "sort_order": "DESC",
- "timeline_field": "employee",
- "track_changes": 0,
- "track_seen": 0,
- "track_views": 0
- }
\ No newline at end of file
+ "allow_import": 1,
+ "autoname": "naming_series:",
+ "creation": "2013-02-20 19:10:38",
+ "doctype": "DocType",
+ "document_type": "Setup",
+ "engine": "InnoDB",
+ "field_order": [
+ "naming_series",
+ "employee",
+ "employee_name",
+ "department",
+ "column_break1",
+ "leave_type",
+ "from_date",
+ "to_date",
+ "section_break_6",
+ "new_leaves_allocated",
+ "carry_forward",
+ "carry_forwarded_leaves",
+ "total_leaves_allocated",
+ "total_leaves_encashed",
+ "column_break_10",
+ "compensatory_request",
+ "leave_period",
+ "amended_from",
+ "notes",
+ "description"
+ ],
+ "fields": [
+ {
+ "fieldname": "naming_series",
+ "fieldtype": "Select",
+ "label": "Series",
+ "no_copy": 1,
+ "options": "HR-LAL-.YYYY.-",
+ "print_hide": 1,
+ "reqd": 1,
+ "set_only_once": 1
+ },
+ {
+ "fieldname": "employee",
+ "fieldtype": "Link",
+ "in_global_search": 1,
+ "in_list_view": 1,
+ "in_standard_filter": 1,
+ "label": "Employee",
+ "oldfieldname": "employee",
+ "oldfieldtype": "Link",
+ "options": "Employee",
+ "reqd": 1,
+ "search_index": 1
+ },
+ {
+ "fetch_from": "employee.employee_name",
+ "fieldname": "employee_name",
+ "fieldtype": "Data",
+ "in_global_search": 1,
+ "in_list_view": 1,
+ "label": "Employee Name",
+ "read_only": 1,
+ "search_index": 1
+ },
+ {
+ "fetch_from": "employee.department",
+ "fieldname": "department",
+ "fieldtype": "Link",
+ "label": "Department",
+ "options": "Department",
+ "read_only": 1
+ },
+ {
+ "fieldname": "column_break1",
+ "fieldtype": "Column Break",
+ "width": "50%"
+ },
+ {
+ "fieldname": "leave_type",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "in_standard_filter": 1,
+ "label": "Leave Type",
+ "oldfieldname": "leave_type",
+ "oldfieldtype": "Link",
+ "options": "Leave Type",
+ "reqd": 1,
+ "search_index": 1
+ },
+ {
+ "fieldname": "from_date",
+ "fieldtype": "Date",
+ "label": "From Date",
+ "reqd": 1
+ },
+ {
+ "fieldname": "to_date",
+ "fieldtype": "Date",
+ "label": "To Date",
+ "reqd": 1
+ },
+ {
+ "fieldname": "section_break_6",
+ "fieldtype": "Section Break",
+ "label": "Allocation"
+ },
+ {
+ "allow_on_submit": 1,
+ "bold": 1,
+ "fieldname": "new_leaves_allocated",
+ "fieldtype": "Float",
+ "label": "New Leaves Allocated"
+ },
+ {
+ "fieldname": "carry_forward",
+ "fieldtype": "Check",
+ "label": "Add unused leaves from previous allocations"
+ },
+ {
+ "depends_on": "carry_forward",
+ "fieldname": "carry_forwarded_leaves",
+ "fieldtype": "Float",
+ "label": "Unused leaves",
+ "read_only": 1
+ },
+ {
+ "allow_on_submit": 1,
+ "fieldname": "total_leaves_allocated",
+ "fieldtype": "Float",
+ "label": "Total Leaves Allocated",
+ "read_only": 1,
+ "reqd": 1
+ },
+ {
+ "depends_on": "eval:doc.total_leaves_encashed>0",
+ "fieldname": "total_leaves_encashed",
+ "fieldtype": "Float",
+ "label": "Total Leaves Encashed",
+ "read_only": 1
+ },
+ {
+ "fieldname": "column_break_10",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "compensatory_request",
+ "fieldtype": "Link",
+ "label": "Compensatory Leave Request",
+ "options": "Compensatory Leave Request",
+ "read_only": 1
+ },
+ {
+ "fieldname": "leave_period",
+ "fieldtype": "Link",
+ "in_standard_filter": 1,
+ "label": "Leave Period",
+ "options": "Leave Period",
+ "read_only": 1
+ },
+ {
+ "fieldname": "amended_from",
+ "fieldtype": "Link",
+ "ignore_user_permissions": 1,
+ "label": "Amended From",
+ "no_copy": 1,
+ "oldfieldname": "amended_from",
+ "oldfieldtype": "Data",
+ "options": "Leave Allocation",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "collapsible": 1,
+ "fieldname": "notes",
+ "fieldtype": "Section Break",
+ "label": "Notes"
+ },
+ {
+ "fieldname": "description",
+ "fieldtype": "Small Text",
+ "label": "Description",
+ "oldfieldname": "reason",
+ "oldfieldtype": "Small Text",
+ "width": "300px"
+ }
+ ],
+ "icon": "fa fa-ok",
+ "idx": 1,
+ "is_submittable": 1,
+ "modified": "2019-05-09 19:06:33.659196",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Leave Allocation",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "amend": 1,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "HR User",
+ "share": 1,
+ "submit": 1,
+ "write": 1
+ },
+ {
+ "amend": 1,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "import": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "HR Manager",
+ "share": 1,
+ "submit": 1,
+ "write": 1
+ }
+ ],
+ "search_fields": "employee,employee_name,leave_type,total_leaves_allocated",
+ "show_name_in_global_search": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "timeline_field": "employee"
+}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.py b/erpnext/hr/doctype/leave_allocation/leave_allocation.py
index f7db7dee86..aa1cc9ecad 100755
--- a/erpnext/hr/doctype/leave_allocation/leave_allocation.py
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.py
@@ -8,6 +8,7 @@ from frappe import _
from frappe.model.document import Document
from erpnext.hr.utils import set_employee_name, get_leave_period
from erpnext.hr.doctype.leave_application.leave_application import get_approved_leaves_for_period
+from erpnext.hr.doctype.leave_ledger_entry.leave_ledger_entry import create_leave_ledger_entry
class OverlapError(frappe.ValidationError): pass
class BackDatedAllocationError(frappe.ValidationError): pass
@@ -18,66 +19,62 @@ class ValueMultiplierError(frappe.ValidationError): pass
class LeaveAllocation(Document):
def validate(self):
self.validate_period()
- self.validate_lwp()
- set_employee_name(self)
- self.set_total_leaves_allocated()
+ self.validate_new_leaves_allocated_value()
self.validate_allocation_overlap()
self.validate_back_dated_allocation()
+ self.set_total_leaves_allocated()
self.validate_total_leaves_allocated()
- self.validate_leaves_allocated_value()
+ self.validate_lwp()
+ set_employee_name(self)
self.validate_leave_allocation_days()
def validate_leave_allocation_days(self):
- new_leaves = self.new_leaves_allocated if not self.carry_forward else self.carry_forwarded_leaves
- max_leaves, leaves_allocated = self.get_max_leaves_with_leaves_allocated_for_leave_type(flt(new_leaves))
+ company = frappe.db.get_value("Employee", self.employee, "company")
+ leave_period = get_leave_period(self.from_date, self.to_date, company)
+ max_leaves_allowed = frappe.db.get_value("Leave Type", self.leave_type, "max_leaves_allowed")
+ if max_leaves_allowed > 0:
+ leave_allocated = 0
+ if leave_period:
+ leave_allocated = get_leave_allocation_for_period(self.employee, self.leave_type, leave_period[0].from_date, leave_period[0].to_date)
+ leave_allocated += self.new_leaves_allocated
+ if leave_allocated > max_leaves_allowed:
+ frappe.throw(_("Total allocated leaves are more days than maximum allocation of {0} leave type for employee {1} in the period")\
+ .format(self.leave_type, self.employee))
- if leaves_allocated > max_leaves:
- frappe.throw(_("Total allocated leaves are more days than maximum allocation of {0} leave type for employee {1} in the period")\
- .format(self.leave_type, self.employee))
+ def on_submit(self):
+ create_leave_ledger_entry(self)
+
+ def on_cancel(self):
+ create_leave_ledger_entry(self)
def on_update_after_submit(self):
self.validate_new_leaves_allocated_value()
self.set_total_leaves_allocated()
- frappe.db.set(self,'total_leaves_allocated', flt(self.total_leaves_allocated))
+ frappe.db.set(self,'carry_forwarded_leaves', flt(self.carry_forwarded_leaves))
+ frappe.db.set(self,'total_leaves_allocated',flt(self.total_leaves_allocated))
self.validate_against_leave_applications()
def validate_period(self):
- allocation_period = date_diff(self.to_date, self.from_date)
-
- if allocation_period <= 0:
+ if date_diff(self.to_date, self.from_date) <= 0:
frappe.throw(_("To date cannot be before from date"))
- # check if the allocation period is more than the expiry allows for carry forwarded allocation
- if self.carry_forward:
- expiry_days = get_days_to_expiry_for_leave_type(self.leave_type)
-
- if allocation_period > flt(expiry_days) and expiry_days:
- frappe.throw(_("Leave allocation period cannot exceed carry forward expiry limit"))
-
def validate_lwp(self):
if frappe.db.get_value("Leave Type", self.leave_type, "is_lwp"):
frappe.throw(_("Leave Type {0} cannot be allocated since it is leave without pay").format(self.leave_type))
- def validate_leaves_allocated_value(self):
+ def validate_new_leaves_allocated_value(self):
"""validate that leave allocation is in multiples of 0.5"""
if flt(self.new_leaves_allocated) % 0.5:
frappe.throw(_("Leaves must be allocated in multiples of 0.5"), ValueMultiplierError)
def validate_allocation_overlap(self):
leave_allocation = frappe.db.sql("""
- SELECT
- name
- FROM `tabLeave Allocation`
- WHERE
- employee=%s
- AND leave_type=%s
- AND docstatus=1
- AND carry_forward={0}
- AND to_date >= %s
- AND from_date <= %s""" #nosec
- .format(self.carry_forward), (self.employee, self.leave_type, self.from_date, self.to_date))
+ select name from `tabLeave Allocation`
+ where employee=%s and leave_type=%s and docstatus=1
+ and to_date >= %s and from_date <= %s""",
+ (self.employee, self.leave_type, self.from_date, self.to_date))
if leave_allocation:
frappe.msgprint(_("{0} already allocated for Employee {1} for period {2} to {3}")
@@ -97,20 +94,18 @@ class LeaveAllocation(Document):
BackDatedAllocationError)
def set_total_leaves_allocated(self):
- if self.carry_forward:
- self.set_carry_forwarded_leaves()
- self.total_leaves_allocated = flt(self.carry_forwarded_leaves)
- else:
- self.total_leaves_allocated = flt(self.new_leaves_allocated)
+ self.carry_forwarded_leaves = get_carry_forwarded_leaves(self.employee,
+ self.leave_type, self.from_date, self.carry_forward)
- if not self.total_leaves_allocated and not frappe.db.get_value("Leave Type", self.leave_type, "is_earned_leave")\
- and not frappe.db.get_value("Leave Type", self.leave_type, "is_compensatory"):
+ self.total_leaves_allocated = flt(self.carry_forwarded_leaves) + flt(self.new_leaves_allocated)
+
+ if not self.total_leaves_allocated and not frappe.db.get_value("Leave Type", self.leave_type, "is_earned_leave") and not frappe.db.get_value("Leave Type", self.leave_type, "is_compensatory"):
frappe.throw(_("Total leaves allocated is mandatory for Leave Type {0}".format(self.leave_type)))
def validate_total_leaves_allocated(self):
# Adding a day to include To Date in the difference
date_difference = date_diff(self.to_date, self.from_date) + 1
- if date_difference < flt(self.total_leaves_allocated):
+ if date_difference < self.total_leaves_allocated:
frappe.throw(_("Total allocated leaves are more than days in the period"), OverAllocationError)
def validate_against_leave_applications(self):
@@ -123,43 +118,16 @@ class LeaveAllocation(Document):
else:
frappe.throw(_("Total allocated leaves {0} cannot be less than already approved leaves {1} for the period").format(self.total_leaves_allocated, leaves_taken), LessAllocationError)
- def set_carry_forwarded_leaves(self):
- self.carry_forwarded_leaves = get_carry_forwarded_leaves(self.employee, self.leave_type, self.from_date)
-
- max_leaves, leaves_allocated = self.get_max_leaves_with_leaves_allocated_for_leave_type(self.carry_forwarded_leaves)
-
- if leaves_allocated > max_leaves:
- self.carry_forwarded_leaves = max_leaves - (leaves_allocated - self.carry_forwarded_leaves)
-
- def get_max_leaves_with_leaves_allocated_for_leave_type(self, new_leaves):
- ''' compare new leaves allocated with max leaves '''
- company = frappe.db.get_value("Employee", self.employee, "company")
- leaves_allocated = 0
- leave_period = get_leave_period(self.from_date, self.to_date, company)
- max_leaves_allowed = frappe.db.get_value("Leave Type", self.leave_type, "max_leaves_allowed")
- if max_leaves_allowed > 0:
- if leave_period:
- leaves_allocated = get_leave_allocation_for_period(self.employee, self.leave_type, leave_period[0].from_date, leave_period[0].to_date)
- leaves_allocated += new_leaves
- return max_leaves_allowed, leaves_allocated
-
def get_leave_allocation_for_period(employee, leave_type, from_date, to_date):
leave_allocated = 0
leave_allocations = frappe.db.sql("""
- SELECT
- employee,
- leave_type,
- from_date,
- to_date,
- total_leaves_allocated
- FROM `tabLeave Allocation`
- WHERE
- employee=%(employee)s
- AND leave_type=%(leave_type)s
- AND docstatus=1
- AND (from_date BETWEEN %(from_date)s AND %(to_date)s
- OR to_date BETWEEN %(from_date)s AND %(to_date)s
- OR (from_date < %(from_date)s AND to_date > %(to_date)s))
+ select employee, leave_type, from_date, to_date, total_leaves_allocated
+ from `tabLeave Allocation`
+ where employee=%(employee)s and leave_type=%(leave_type)s
+ and docstatus=1
+ and (from_date between %(from_date)s and %(to_date)s
+ or to_date between %(from_date)s and %(to_date)s
+ or (from_date < %(from_date)s and to_date > %(to_date)s))
""", {
"from_date": from_date,
"to_date": to_date,
@@ -174,43 +142,14 @@ def get_leave_allocation_for_period(employee, leave_type, from_date, to_date):
return leave_allocated
@frappe.whitelist()
-def get_carry_forwarded_leaves(employee, leave_type, date):
- ''' Calculates carry forwarded days based on previous unused leave allocations '''
- carry_forwarded_leaves = 0
- expiry_days = get_days_to_expiry_for_leave_type(leave_type)
- validate_carry_forward(leave_type)
- filters = {
- "employee": employee,
- "leave_type": leave_type,
- "docstatus": 1,
- "to_date": ("<", date)
- }
- limit = 2
+def get_carry_forwarded_leaves(employee, leave_type, date, carry_forward=None):
+ leave_records = frappe.get_all("Leave Ledger Entry",
+ filters={'Employee':employee,
+ 'leave_type':leave_type,
+ 'to_date':("<=", date)},
+ fields=['leaves'])
- # check number of days to expire, ignore expiry for default value 0
- if expiry_days:
- filters.update(carry_forward=0)
- limit = 1
-
- previous_allocation = frappe.get_all("Leave Allocation",
- filters=filters,
- fields=["name","from_date","to_date","total_leaves_allocated"],
- order_by="to_date desc",
- limit=limit)
-
- if previous_allocation:
- leaves_taken = get_approved_leaves_for_period(employee, leave_type,
- previous_allocation[0].from_date, previous_allocation[0].to_date)
-
- carry_forwarded_leaves = flt(previous_allocation[0].total_leaves_allocated) - flt(leaves_taken)
-
- return carry_forwarded_leaves
-
-def get_days_to_expiry_for_leave_type(leave_type):
- ''' returns days to expiry for a provided leave type '''
- return frappe.db.get_value("Leave Type",
- filters={"leave_type_name": leave_type, "is_carry_forward": 1},
- fieldname="carry_forward_leave_expiry")
+ return sum(record.get("leaves") for record in leave_records)
def validate_carry_forward(leave_type):
if not frappe.db.get_value("Leave Type", leave_type, "is_carry_forward"):
diff --git a/erpnext/hr/doctype/leave_period/leave_period.py b/erpnext/hr/doctype/leave_period/leave_period.py
index a6198a8918..91cc9b8340 100644
--- a/erpnext/hr/doctype/leave_period/leave_period.py
+++ b/erpnext/hr/doctype/leave_period/leave_period.py
@@ -114,22 +114,7 @@ def create_leave_allocation(employee, leave_type, new_leaves_allocated, leave_ty
allocation.leave_period = leave_period.name
if carry_forward_leaves:
if leave_type_details.get(leave_type).is_carry_forward:
- create_carry_forward_leaves_allocation(employee, leave_type, leave_type_details, leave_period, carry_forward_leaves)
- allocation.save(ignore_permissions=True)
+ allocation.carry_forward = carry_forward_leaves
+ allocation.save(ignore_permissions = True)
allocation.submit()
- return allocation.name
-
-def create_carry_forward_leaves_allocation(employee, leave_type, leave_type_details, leave_period, carry_forward_leaves):
- carry_forwarded_leaves = get_carry_forwarded_leaves(employee, leave_type, leave_period.from_date)
- if not carry_forwarded_leaves:
- return
- allocation = frappe.new_doc("Leave Allocation")
- allocation.employee = employee
- allocation.leave_type = leave_type
- allocation.from_date = leave_period.from_date
- allocation.to_date = add_days(leave_period.from_date, leave_type_details.carry_forward_leave_expiry) if not leave_type_details.carry_forward_leave_expiry else leave_period.to_date
- allocation.leave_period = leave_period.name
- allocation.carry_forward = carry_forward_leaves
- allocation.carry_forwarded_leaves = carry_forwarded_leaves
- allocation.save(ignore_permissions=True)
- allocation.submit()
\ No newline at end of file
+ return allocation.name
\ No newline at end of file
From 5ad83c06c225f5a8a8cb47f0f5b5dc412f988fe5 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Fri, 10 May 2019 19:50:04 +0530
Subject: [PATCH 019/484] feat: add ledger entries on leave addition
---
.../leave_allocation/leave_allocation.py | 24 ++++++++++++++++---
.../leave_application/leave_application.py | 21 ++++++++++++++++
.../leave_ledger_entry/leave_ledger_entry.py | 19 +++------------
3 files changed, 45 insertions(+), 19 deletions(-)
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.py b/erpnext/hr/doctype/leave_allocation/leave_allocation.py
index aa1cc9ecad..5f474a4554 100755
--- a/erpnext/hr/doctype/leave_allocation/leave_allocation.py
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.py
@@ -42,10 +42,10 @@ class LeaveAllocation(Document):
.format(self.leave_type, self.employee))
def on_submit(self):
- create_leave_ledger_entry(self)
+ self.create_leave_ledger_entry()
- def on_cancel(self):
- create_leave_ledger_entry(self)
+ # def before_cancel(self):
+ # self.create_leave_ledger_entry(submit=False)
def on_update_after_submit(self):
self.validate_new_leaves_allocated_value()
@@ -118,6 +118,24 @@ class LeaveAllocation(Document):
else:
frappe.throw(_("Total allocated leaves {0} cannot be less than already approved leaves {1} for the period").format(self.total_leaves_allocated, leaves_taken), LessAllocationError)
+ def create_leave_ledger_entry(self, submit=True):
+ if self.carry_forwarded_leaves:
+ expiry_days = frappe.db.get_value("Leave Type", self.leave_type, "carry_forward_leave_expiry")
+
+ args = dict(
+ leaves=self.carry_forwarded_leaves * 1 if submit else -1,
+ to_date=add_days(self.from_date, expiry_days) if expiry_days else self.to_date,
+ is_carry_forward=1
+ )
+ create_leave_ledger_entry(self, args)
+
+ args = dict(
+ leaves=self.new_leaves_allocated * 1 if submit else -1,
+ to_date=self.to_date,
+ is_carry_forward=0
+ )
+ create_leave_ledger_entry(self, args)
+
def get_leave_allocation_for_period(employee, leave_type, from_date, to_date):
leave_allocated = 0
leave_allocations = frappe.db.sql("""
diff --git a/erpnext/hr/doctype/leave_application/leave_application.py b/erpnext/hr/doctype/leave_application/leave_application.py
index f542fa1e5c..61f617806f 100755
--- a/erpnext/hr/doctype/leave_application/leave_application.py
+++ b/erpnext/hr/doctype/leave_application/leave_application.py
@@ -10,6 +10,7 @@ from erpnext.hr.utils import set_employee_name, get_leave_period
from erpnext.hr.doctype.leave_block_list.leave_block_list import get_applicable_block_dates
from erpnext.hr.doctype.employee.employee import get_holiday_list_for_employee
from erpnext.buying.doctype.supplier_scorecard.supplier_scorecard import daterange
+from erpnext.hr.doctype.leave_ledger_entry.leave_ledger_entry import create_leave_ledger_entry
class LeaveDayBlockedError(frappe.ValidationError): pass
class OverlapError(frappe.ValidationError): pass
@@ -50,6 +51,7 @@ class LeaveApplication(Document):
# notify leave applier about approval
self.notify_employee()
+ self.create_leave_ledger_entry()
self.reload()
def on_cancel(self):
@@ -57,6 +59,7 @@ class LeaveApplication(Document):
# notify leave applier about cancellation
self.notify_employee()
self.cancel_attendance()
+ self.create_leave_ledger_entry(submit=False)
def validate_applicable_after(self):
if self.leave_type:
@@ -346,6 +349,14 @@ class LeaveApplication(Document):
except frappe.OutgoingEmailError:
pass
+ def create_leave_ledger_entry(self, submit=True):
+ args = dict(
+ leaves=self.total_leave_days * -1 if submit else 1,
+ to_date=self.to_date,
+ is_carry_forward=0
+ )
+ create_leave_ledger_entry(self, args)
+
@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
@@ -384,6 +395,16 @@ def get_leave_details(employee, date):
return ret
+@frappe.whitelist()
+def get_leave_balance(employee, leave_type, date):
+ leave_records = frappe.get_all("Leave Ledger Entry",
+ filters={'Employee':employee,
+ 'leave_type':leave_type,
+ 'to_date':("<=", date)},
+ fields=['leaves'])
+
+ return sum(record.get("leaves") for record in leave_records)
+
@frappe.whitelist()
def get_leave_balance_on(employee, leave_type, date, allocation_records=None, docname=None,
consider_all_leaves_in_the_allocation_period=False, consider_encashed_leaves=True):
diff --git a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
index 35dce97936..60d35957b9 100644
--- a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
+++ b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
@@ -10,7 +10,7 @@ from frappe.utils import add_days
class LeaveLedgerEntry(Document):
pass
-def create_leave_ledger_entry(ref_doc, submit=True):
+def create_leave_ledger_entry(ref_doc, args):
ledger = dict(
doctype='Leave Ledger Entry',
employee=ref_doc.employee,
@@ -20,19 +20,6 @@ def create_leave_ledger_entry(ref_doc, submit=True):
transaction_type=ref_doc.doctype,
transaction_name=ref_doc.name
)
- if ref_doc.carry_forwarded_leaves:
- expiry_days = frappe.db.get_value("Leave Type", ref_doc.leave_type, "carry_forward_leave_expiry")
- ledger.update(dict(
- leaves=ref_doc.carry_forwarded_leaves * 1 if submit else -1,
- to_date=add_days(ref_doc.from_date, expiry_days) if expiry_days else ref_doc.to_date,
- is_carry_forward=1
- ))
- frappe.get_doc(ledger).submit()
-
- ledger.update(dict(
- leaves=ref_doc.new_leaves_allocated * 1 if submit else -1,
- to_date=ref_doc.to_date,
- is_carry_forward=0
- ))
- frappe.get_doc(ledger).submit()
\ No newline at end of file
+ ledger.update(args)
+ frappe.get_doc(ledger).insert(ignore_permissions=True)
\ No newline at end of file
From 01490f1560e5fcdae2e6b8923f016b5c1c83ba68 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Sun, 12 May 2019 21:01:25 +0530
Subject: [PATCH 020/484] feat: add cancellation workflow for leave allocation
ledger entry
---
.../hr/doctype/leave_allocation/leave_allocation.py | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.py b/erpnext/hr/doctype/leave_allocation/leave_allocation.py
index 5f474a4554..57fe9830f6 100755
--- a/erpnext/hr/doctype/leave_allocation/leave_allocation.py
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.py
@@ -44,8 +44,8 @@ class LeaveAllocation(Document):
def on_submit(self):
self.create_leave_ledger_entry()
- # def before_cancel(self):
- # self.create_leave_ledger_entry(submit=False)
+ def on_cancel(self):
+ self.create_leave_ledger_entry(submit=False)
def on_update_after_submit(self):
self.validate_new_leaves_allocated_value()
@@ -123,14 +123,14 @@ class LeaveAllocation(Document):
expiry_days = frappe.db.get_value("Leave Type", self.leave_type, "carry_forward_leave_expiry")
args = dict(
- leaves=self.carry_forwarded_leaves * 1 if submit else -1,
+ leaves=self.carry_forwarded_leaves,
to_date=add_days(self.from_date, expiry_days) if expiry_days else self.to_date,
is_carry_forward=1
)
- create_leave_ledger_entry(self, args)
+ create_leave_ledger_entry(self, args, submit)
args = dict(
- leaves=self.new_leaves_allocated * 1 if submit else -1,
+ leaves=self.new_leaves_allocated,
to_date=self.to_date,
is_carry_forward=0
)
From 5448edff2c9ec4be725c96d0d9b82c19dd651261 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Sun, 12 May 2019 21:02:05 +0530
Subject: [PATCH 021/484] feat: delete cancelled allocation from ledger
---
.../leave_ledger_entry/leave_ledger_entry.py | 30 ++++++++++++++++---
1 file changed, 26 insertions(+), 4 deletions(-)
diff --git a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
index 60d35957b9..12be4794aa 100644
--- a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
+++ b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
@@ -5,13 +5,14 @@
from __future__ import unicode_literals
import frappe
from frappe.model.document import Document
+from frappe import _
from frappe.utils import add_days
class LeaveLedgerEntry(Document):
pass
-def create_leave_ledger_entry(ref_doc, args):
- ledger = dict(
+def create_leave_ledger_entry(ref_doc, args, submit):
+ ledger = frappe._dict(
doctype='Leave Ledger Entry',
employee=ref_doc.employee,
employee_name=ref_doc.employee_name,
@@ -20,6 +21,27 @@ def create_leave_ledger_entry(ref_doc, args):
transaction_type=ref_doc.doctype,
transaction_name=ref_doc.name
)
-
ledger.update(args)
- frappe.get_doc(ledger).insert(ignore_permissions=True)
\ No newline at end of file
+
+ if submit:
+ frappe.get_doc(ledger).insert(ignore_permissions=True)
+ else:
+ delete_ledger_entry(ledger)
+
+def delete_ledger_entry(ledger):
+ ''' Delete ledger entry on cancel of leave application/allocation '''
+ ledger_entry, creation_date = frappe.db.get_value("Leave Ledger Entry",
+ {'transaction_name': ledger.transaction_name},
+ ['name', 'creation']
+ )
+ leave_application_records = frappe.get_all("Leave Ledger Entry",
+ filters={
+ 'transaction_type': 'Leave Application',
+ 'creation_date': (">", creation_date)
+ },
+ fields=['transaction_type'])
+ if not leave_application_records:
+ frappe.delete_doc("Leave Ledger Entry", ledger_entry)
+ else:
+ frappe.throw(_("Leave allocation %s is linked with leave application %s"
+ % (ledger_entry, ', '.join(leave_application_records))))
\ No newline at end of file
From 783bd89413b2fc7fa3572ef123fddafc17f3b531 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Sun, 12 May 2019 21:59:36 +0530
Subject: [PATCH 022/484] feat: handle cancellation workflow for leave
application
---
erpnext/hr/doctype/leave_application/leave_application.py | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/erpnext/hr/doctype/leave_application/leave_application.py b/erpnext/hr/doctype/leave_application/leave_application.py
index 61f617806f..76a3af7ae9 100755
--- a/erpnext/hr/doctype/leave_application/leave_application.py
+++ b/erpnext/hr/doctype/leave_application/leave_application.py
@@ -350,12 +350,12 @@ class LeaveApplication(Document):
pass
def create_leave_ledger_entry(self, submit=True):
- args = dict(
- leaves=self.total_leave_days * -1 if submit else 1,
+ args = frappe._dict(
+ leaves=self.total_leave_days,
to_date=self.to_date,
is_carry_forward=0
)
- create_leave_ledger_entry(self, args)
+ create_leave_ledger_entry(self, args, submit)
@frappe.whitelist()
def get_number_of_leave_days(employee, leave_type, from_date, to_date, half_day = None, half_day_date = None):
From cf8f4bda8fc4d9521a47168cad220034a3f42b15 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Sun, 12 May 2019 22:45:14 +0530
Subject: [PATCH 023/484] fix: skip application fetch for non allocation
records
---
.../leave_ledger_entry/leave_ledger_entry.py | 15 +++++++++------
1 file changed, 9 insertions(+), 6 deletions(-)
diff --git a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
index 12be4794aa..23258f1c77 100644
--- a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
+++ b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
@@ -34,12 +34,15 @@ def delete_ledger_entry(ledger):
{'transaction_name': ledger.transaction_name},
['name', 'creation']
)
- leave_application_records = frappe.get_all("Leave Ledger Entry",
- filters={
- 'transaction_type': 'Leave Application',
- 'creation_date': (">", creation_date)
- },
- fields=['transaction_type'])
+
+ leave_application_records = []
+ if ledger.transaction_type == "Leave Allocation":
+ leave_application_records = frappe.get_all("Leave Ledger Entry",
+ filters={
+ 'transaction_type': 'Leave Application',
+ 'creation_date': (">", creation_date)
+ },
+ fields=['transaction_type'])
if not leave_application_records:
frappe.delete_doc("Leave Ledger Entry", ledger_entry)
else:
From 9bb4b8e8b29eec81af9c6599a6772ec714a0116a Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Sun, 12 May 2019 23:21:04 +0530
Subject: [PATCH 024/484] feat: create expiry ledger entry on allocation period
completion
---
erpnext/hooks.py | 1 +
.../leave_ledger_entry/leave_ledger_entry.py | 29 +++++++++++++++++--
2 files changed, 27 insertions(+), 3 deletions(-)
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index 53da013f8d..72c538fd3c 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -264,6 +264,7 @@ scheduler_events = {
"erpnext.projects.doctype.project.project.update_project_sales_billing",
"erpnext.projects.doctype.project.project.send_project_status_email_to_users",
"erpnext.quality_management.doctype.quality_review.quality_review.review",
+ "erpnext.hr.doctype.leave_ledger_entry.leave_ledger_entry.check_expired_allocation"
"erpnext.support.doctype.service_level_agreement.service_level_agreement.check_agreement_status"
],
"daily_long": [
diff --git a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
index 23258f1c77..585e1079f7 100644
--- a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
+++ b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
@@ -6,12 +6,12 @@ from __future__ import unicode_literals
import frappe
from frappe.model.document import Document
from frappe import _
-from frappe.utils import add_days
+from frappe.utils import add_days, today
class LeaveLedgerEntry(Document):
pass
-def create_leave_ledger_entry(ref_doc, args, submit):
+def create_leave_ledger_entry(ref_doc, args, submit=True):
ledger = frappe._dict(
doctype='Leave Ledger Entry',
employee=ref_doc.employee,
@@ -47,4 +47,27 @@ def delete_ledger_entry(ledger):
frappe.delete_doc("Leave Ledger Entry", ledger_entry)
else:
frappe.throw(_("Leave allocation %s is linked with leave application %s"
- % (ledger_entry, ', '.join(leave_application_records))))
\ No newline at end of file
+ % (ledger_entry, ', '.join(leave_application_records))))
+
+def check_expired_allocation():
+ ''' Checks for expired allocation by comparing to_date with current_date and
+ based on that creates an expiry ledger entry '''
+ expired_allocation = frappe.db.get_all("Leave Ledger Allocation",
+ filters={
+ 'to_date': today(),
+ 'transaction_type': 'Leave Allocation'
+ },
+ fields=['name', 'transaction_name'])
+
+ if expired_allocation:
+ create_expiry_ledger_entry(expired_allocation)
+
+def create_expiry_ledger_entry(expired_allocation):
+ for allocation in expired_allocation:
+ ledger_entry = frappe.get_doc('Leave Ledger Entry', allocation.name)
+ args = {
+ 'leaves': -ledger_entry.leaves,
+ 'to_date': '',
+ 'is_carry_forward': ledger_entry.is_carry_forward
+ }
+ create_leave_ledger_entry(ledger_entry, args)
\ No newline at end of file
From 170b8dded8cd5c9bb7309193d1260bbcb5435b3d Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Mon, 13 May 2019 19:17:44 +0530
Subject: [PATCH 025/484] fix: expiry logic for carry forwarded allocation
---
.../leave_ledger_entry.json | 8 +++-
.../leave_ledger_entry/leave_ledger_entry.py | 45 ++++++++++++++-----
2 files changed, 41 insertions(+), 12 deletions(-)
diff --git a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.json b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.json
index c7e6b709bd..89c703db65 100644
--- a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.json
+++ b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.json
@@ -12,6 +12,7 @@
"from_date",
"to_date",
"is_carry_forward",
+ "is_expired",
"amended_from"
],
"fields": [
@@ -72,10 +73,15 @@
"fieldname": "is_carry_forward",
"fieldtype": "Check",
"label": "Is Carry Forward"
+ },
+ {
+ "fieldname": "is_expired",
+ "fieldtype": "Check",
+ "label": "Is Expired"
}
],
"is_submittable": 1,
- "modified": "2019-05-09 18:36:07.383714",
+ "modified": "2019-05-13 12:56:45.542495",
"modified_by": "Administrator",
"module": "HR",
"name": "Leave Ledger Entry",
diff --git a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
index 585e1079f7..526a91e976 100644
--- a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
+++ b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
@@ -9,7 +9,10 @@ from frappe import _
from frappe.utils import add_days, today
class LeaveLedgerEntry(Document):
- pass
+ def validate_entries(self):
+ leave_records = frappe.get_all('Leave Ledger Entry', ['leaves'])
+ if sum(record.get("leaves") for record in leave_records) <0:
+ frappe.throw(_("Invalid Ledger Entry"))
def create_leave_ledger_entry(ref_doc, args, submit=True):
ledger = frappe._dict(
@@ -19,7 +22,7 @@ def create_leave_ledger_entry(ref_doc, args, submit=True):
leave_type=ref_doc.leave_type,
from_date=ref_doc.from_date,
transaction_type=ref_doc.doctype,
- transaction_name=ref_doc.name
+ transaction_name=ref_doc.name,
)
ledger.update(args)
@@ -52,22 +55,42 @@ def delete_ledger_entry(ledger):
def check_expired_allocation():
''' Checks for expired allocation by comparing to_date with current_date and
based on that creates an expiry ledger entry '''
- expired_allocation = frappe.db.get_all("Leave Ledger Allocation",
+ expired_allocation = frappe.get_all("Leave Ledger Allocation",
filters={
'to_date': today(),
'transaction_type': 'Leave Allocation'
},
- fields=['name', 'transaction_name'])
+ fields=['*'])
if expired_allocation:
create_expiry_ledger_entry(expired_allocation)
def create_expiry_ledger_entry(expired_allocation):
for allocation in expired_allocation:
- ledger_entry = frappe.get_doc('Leave Ledger Entry', allocation.name)
- args = {
- 'leaves': -ledger_entry.leaves,
- 'to_date': '',
- 'is_carry_forward': ledger_entry.is_carry_forward
- }
- create_leave_ledger_entry(ledger_entry, args)
\ No newline at end of file
+ filters = {
+ 'employee': allocation.employee,
+ 'leave_type': allocation.leave_type,
+ 'from_date': ('>=', allocation.from_date),
+ }
+ # get only application ledger entries in case of carry forward
+ if allocation.is_carry_forward:
+ filters.update(dict(transaction_type='Leave Application'))
+
+ leave_records = frappe.get_all("Leave Ledger Entry",
+ filters=filters,
+ fields=['leaves'])
+
+ leaves = sum(record.get("leaves") for record in leave_records)
+
+ if allocation.is_carry_forward:
+ leaves = allocation.leaves + leaves
+
+ if leaves > 0:
+ args = frappe._dict(
+ leaves=allocation.leaves * -1,
+ to_date='',
+ is_carry_forward=allocation.is_carry_forward,
+ is_expired=1,
+ from_date=allocation.to_date
+ )
+ create_leave_ledger_entry(allocation, args)
\ No newline at end of file
From 201aeeb20d6286e9ed8eaea25500889626be8767 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Mon, 13 May 2019 19:19:02 +0530
Subject: [PATCH 026/484] test: creation of ledger entries on allocation submit
---
.../leave_allocation/test_leave_allocation.py | 30 ++++++++-----------
1 file changed, 13 insertions(+), 17 deletions(-)
diff --git a/erpnext/hr/doctype/leave_allocation/test_leave_allocation.py b/erpnext/hr/doctype/leave_allocation/test_leave_allocation.py
index 325f3a7299..a0113e2d9f 100644
--- a/erpnext/hr/doctype/leave_allocation/test_leave_allocation.py
+++ b/erpnext/hr/doctype/leave_allocation/test_leave_allocation.py
@@ -68,27 +68,22 @@ class TestLeaveAllocation(unittest.TestCase):
#allocated leave more than period
self.assertRaises(frappe.ValidationError, doc.save)
- def test_carry_forward_allocation(self):
+ def test_creation_of_leave_ledger_entry_on_submit(self):
frappe.db.sql("delete from `tabLeave Allocation`")
- leave_type = create_leave_type(
- leave_type_name="_Test Carry Forward",
- is_carry_forward=1,
- carry_forward_leave_expiry=366)
- leave_type.submit()
-
- leave_allocation = create_leave_allocation(
- from_date=add_months(nowdate(), -12),
- to_date=add_days(nowdate(), -1),
- leave_type=leave_type
- )
- leave_allocation.new_leaves_allocated = 10
+ leave_allocation = create_leave_allocation()
leave_allocation.submit()
- carry_forward_alloc = create_leave_allocation(leave_type=leave_type)
- carry_forward_alloc.carry_forward = 1
- carry_forward_alloc.save()
- self.assertEquals(carry_forward_alloc.total_leaves_allocated, 10)
+ leave_ledger_entry = frappe.get_all('Leave Ledger Entry', fields='*', filters=dict(transaction_name=leave_allocation.name))
+
+ self.assertEquals(len(leave_ledger_entry), 1)
+ self.assertEquals(leave_ledger_entry[0].employee, leave_allocation.employee)
+ self.assertEquals(leave_ledger_entry[0].leave_type, leave_allocation.leave_type)
+ self.assertEquals(leave_ledger_entry[0].leaves, leave_allocation.new_leaves_allocated)
+
+ # check if leave ledger entry is deleted on cancellation
+ leave_allocation.cancel()
+ self.assertFalse(frappe.db.exists("Leave Ledger Entry", {'transaction_name':leave_allocation.name}))
def create_leave_allocation(**args):
args = frappe._dict(args)
@@ -101,6 +96,7 @@ def create_leave_allocation(**args):
"employee_name": employee.employee_name,
"leave_type": args.leave_type.leave_type_name or "_Test Leave Type",
"from_date": args.from_date or nowdate(),
+ "new_leaves_allocated": args.new_leaves_created or 15,
"to_date": args.to_date or add_months(nowdate(), 12)
})
return leave_allocation
From 964deaca96e7a4ea5fc8f2eea03297a70720b5f6 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Mon, 13 May 2019 19:19:39 +0530
Subject: [PATCH 027/484] test: creation of ledger entries on application
submit
---
.../test_leave_application.py | 24 ++++++++++++++++++-
1 file changed, 23 insertions(+), 1 deletion(-)
diff --git a/erpnext/hr/doctype/leave_application/test_leave_application.py b/erpnext/hr/doctype/leave_application/test_leave_application.py
index d3dcca1da0..2581c2a659 100644
--- a/erpnext/hr/doctype/leave_application/test_leave_application.py
+++ b/erpnext/hr/doctype/leave_application/test_leave_application.py
@@ -457,6 +457,28 @@ class TestLeaveApplication(unittest.TestCase):
leave_application.submit()
self.assertEqual(leave_application.docstatus, 1)
+ def test_creation_of_leave_ledger_entry_on_submit(self):
+
+ leave_application = frappe.get_doc(dict(
+ doctype = 'Leave Application',
+ employee = employee.name,
+ leave_type = leave_type_1.name,
+ from_date = nowdate(),
+ to_date = add_days(nowdate(), 4),
+ company = "_Test Company",
+ docstatus = 1,
+ status = "Approved"
+ )).submit()
+ leave_ledger_entry = frappe.get_all('Leave Ledger Entry', fields='*', filters=dict(transaction_name=leave_application.name))
+
+ self.assertEquals(leave_ledger_entry[0].employee, leave_application.employee)
+ self.assertEquals(leave_ledger_entry[0].leave_type, leave_application.leave_type)
+ self.assertEquals(leave_ledger_entry[0].leaves, leave_application.new_leaves_allocated)
+
+ # check if leave ledger entry is deleted on cancellation
+ leave_application.cancel()
+ self.assertFalse(frappe.db.exists("Leave Ledger Entry", {'transaction_name':leave_application.name}))
+
def make_allocation_record(employee=None, leave_type=None):
frappe.db.sql("delete from `tabLeave Allocation`")
@@ -513,4 +535,4 @@ def allocate_leaves(employee, leave_period, leave_type, new_leaves_allocated, el
"docstatus": 1
}).insert()
- allocate_leave.submit()
+ allocate_leave.submit()
\ No newline at end of file
From 6ba9a128e7fd95c2b2ebea29c36738550209c666 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Tue, 14 May 2019 11:23:10 +0530
Subject: [PATCH 028/484] feat: calculate leave balance using ledger entries
---
.../leave_application/leave_application.py | 57 ++++++++++++-------
1 file changed, 36 insertions(+), 21 deletions(-)
diff --git a/erpnext/hr/doctype/leave_application/leave_application.py b/erpnext/hr/doctype/leave_application/leave_application.py
index 76a3af7ae9..70d7aa4b3a 100755
--- a/erpnext/hr/doctype/leave_application/leave_application.py
+++ b/erpnext/hr/doctype/leave_application/leave_application.py
@@ -197,6 +197,7 @@ class LeaveApplication(Document):
if not is_lwp(self.leave_type):
self.leave_balance = get_leave_balance_on(self.employee, self.leave_type, self.from_date, docname=self.name,
consider_all_leaves_in_the_allocation_period=True)
+
if self.status != "Rejected" and self.leave_balance < self.total_leave_days:
if frappe.db.get_value("Leave Type", self.leave_type, "allow_negative"):
frappe.msgprint(_("Note: There is not enough leave balance for Leave Type {0}")
@@ -350,6 +351,13 @@ class LeaveApplication(Document):
pass
def create_leave_ledger_entry(self, submit=True):
+ # check if there is a carry forwarded allocation expiry between application
+ allocation = frappe.db.get_value('Leave Ledger Entry',
+ filters={
+ 'transaction_type': "Leave Allocation",
+ 'is_carry_forward': 1,
+ 'from_date': self.to_date
+ })
args = frappe._dict(
leaves=self.total_leave_days,
to_date=self.to_date,
@@ -396,31 +404,38 @@ def get_leave_details(employee, date):
return ret
@frappe.whitelist()
-def get_leave_balance(employee, leave_type, date):
+def get_leave_balance_on(employee, leave_type, date, allocation_records=None, consider_all_leaves_in_the_allocation_period=False):
+
+ if allocation_records:
+ # leave_balance based on current allocation records
+ allocation = allocation_records.get(leave_type, frappe._dict())
+ from_date = allocation.from_date
+ to_date = allocation.to_date
+ else:
+ # fetched the expired allocation creation date
+ from_date, to_date = frappe.db.get_value('Leave Ledger Entry',
+ filters={
+ 'transaction_type': 'Leave Allocation',
+ 'employee': employee,
+ 'leave_type': leave_type,
+ 'is_expired': 0,
+ 'is_carry_forward': 0,
+ },
+ fieldname=['from_date', 'to_date'],
+ order_by='to_date DESC')
+
+ if consider_all_leaves_in_the_allocation_period:
+ date = to_date
+
leave_records = frappe.get_all("Leave Ledger Entry",
- filters={'Employee':employee,
- 'leave_type':leave_type,
- 'to_date':("<=", date)},
- fields=['leaves'])
+ filters={'Employee':employee,
+ 'leave_type':leave_type,
+ 'to_date':("<=", date),
+ 'from_date': from_date},
+ fields=['leaves'])
return sum(record.get("leaves") for record in leave_records)
-@frappe.whitelist()
-def get_leave_balance_on(employee, leave_type, date, allocation_records=None, docname=None,
- consider_all_leaves_in_the_allocation_period=False, consider_encashed_leaves=True):
-
- if allocation_records == None:
- allocation_records = get_leave_allocation_records(date, employee).get(employee, frappe._dict())
- allocation = allocation_records.get(leave_type, frappe._dict())
- if consider_all_leaves_in_the_allocation_period:
- date = allocation.to_date
- leaves_taken = get_leaves_for_period(employee, leave_type, allocation.from_date, date, status="Approved", docname=docname)
- leaves_encashed = 0
- if frappe.db.get_value("Leave Type", leave_type, 'allow_encashment') and consider_encashed_leaves:
- leaves_encashed = flt(allocation.total_leaves_encashed)
-
- return flt(allocation.total_leaves_allocated) - (flt(leaves_taken) + flt(leaves_encashed))
-
def get_total_allocated_leaves(employee, leave_type, date):
filters= {
'from_date': ['<=', date],
From 50037f86097ab5f744772041026c0ca172d10a34 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Wed, 15 May 2019 21:49:27 +0530
Subject: [PATCH 029/484] fix: consider min days remaining as remaining leaves
---
.../leave_application/leave_application.py | 67 +++++++++----------
1 file changed, 31 insertions(+), 36 deletions(-)
diff --git a/erpnext/hr/doctype/leave_application/leave_application.py b/erpnext/hr/doctype/leave_application/leave_application.py
index 70d7aa4b3a..9e0ed0f1b5 100755
--- a/erpnext/hr/doctype/leave_application/leave_application.py
+++ b/erpnext/hr/doctype/leave_application/leave_application.py
@@ -351,15 +351,9 @@ class LeaveApplication(Document):
pass
def create_leave_ledger_entry(self, submit=True):
- # check if there is a carry forwarded allocation expiry between application
- allocation = frappe.db.get_value('Leave Ledger Entry',
- filters={
- 'transaction_type': "Leave Allocation",
- 'is_carry_forward': 1,
- 'from_date': self.to_date
- })
args = frappe._dict(
leaves=self.total_leave_days,
+ from_date=self.from_date,
to_date=self.to_date,
is_carry_forward=0
)
@@ -403,38 +397,37 @@ def get_leave_details(employee, date):
return ret
-@frappe.whitelist()
-def get_leave_balance_on(employee, leave_type, date, allocation_records=None, consider_all_leaves_in_the_allocation_period=False):
-
- if allocation_records:
- # leave_balance based on current allocation records
- allocation = allocation_records.get(leave_type, frappe._dict())
- from_date = allocation.from_date
- to_date = allocation.to_date
- else:
- # fetched the expired allocation creation date
- from_date, to_date = frappe.db.get_value('Leave Ledger Entry',
- filters={
- 'transaction_type': 'Leave Allocation',
- 'employee': employee,
- 'leave_type': leave_type,
- 'is_expired': 0,
- 'is_carry_forward': 0,
- },
- fieldname=['from_date', 'to_date'],
- order_by='to_date DESC')
+def get_leave_balance_on(employee, leave_type, date, allocation_records=None, docname=None,
+ consider_all_leaves_in_the_allocation_period=False, consider_encashed_leaves=True):
+ if allocation_records == None:
+ allocation_records = get_leave_allocation_records(date, employee).get(employee, frappe._dict())
+ allocation = allocation_records.get(leave_type, frappe._dict())
if consider_all_leaves_in_the_allocation_period:
- date = to_date
-
- leave_records = frappe.get_all("Leave Ledger Entry",
- filters={'Employee':employee,
+ date = allocation.to_date
+ leaves_taken = frappe.db.get_value("Leave Ledger Entry", filters={
+ 'Employee':employee,
'leave_type':leave_type,
+ 'transaction_type': ('!=', 'Leave Allocation'),
'to_date':("<=", date),
'from_date': from_date},
- fields=['leaves'])
+ fields=['SUM(leaves)'])
- return sum(record.get("leaves") for record in leave_records)
+ remaining_unused_leaves = flt(allocation.unused_leaves + leaves_taken)
+ if allocation.carry_forward and remaining_unused_leaves > 0:
+ expiry_date = frappe.db.get_value("Leave Ledger Entry", filters={
+ 'Employee':employee,
+ 'leave_type':leave_type,
+ 'transaction_type': 'Leave Allocation',
+ 'transaction_name': allocation.name,
+ 'is_carry_forward': 1,
+ 'is_expiry': 0
+ }, fieldname=['to_date'])
+ remaining_days = date_diff(expiry_date, date) + 1
+
+ remaining_unused_leaves = min(remaining_days, remaining_unused_leaves)
+
+ return flt(allocation.new_leaves) + remaining_unused_leaves + leaves_taken
def get_total_allocated_leaves(employee, leave_type, date):
filters= {
@@ -495,8 +488,10 @@ def get_leave_allocation_records(date, employee=None):
allocated_leaves.setdefault(d.employee, frappe._dict()).setdefault(d.leave_type, frappe._dict({
"from_date": d.from_date,
"to_date": d.to_date,
- "total_leaves_allocated": d.total_leaves_allocated,
- "total_leaves_encashed":d.total_leaves_encashed
+ "carry_forward": d.carry_forward,
+ "unused_leaves": d.carry_forwarded_leaves,
+ "new_leaves": d.new_leaves_allocated,
+ "name": d.name
}))
return allocated_leaves
@@ -677,4 +672,4 @@ def get_leave_approver(employee, department=None):
if department:
return frappe.db.get_value('Department Approver', {'parent': department,
- 'parentfield': 'leave_approvers', 'idx': 1}, 'approver')
+ 'parentfield': 'leave_approvers', 'idx': 1}, 'approver')
\ No newline at end of file
From f8f02c508d5122b3af0fc1e4eb829b3ba2a3e995 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Wed, 15 May 2019 21:50:06 +0530
Subject: [PATCH 030/484] feat: create leave ledger entry on leave encashment
creation
---
.../hr/doctype/leave_encashment/leave_encashment.py | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/erpnext/hr/doctype/leave_encashment/leave_encashment.py b/erpnext/hr/doctype/leave_encashment/leave_encashment.py
index 9944bc5380..4f4a8760cf 100644
--- a/erpnext/hr/doctype/leave_encashment/leave_encashment.py
+++ b/erpnext/hr/doctype/leave_encashment/leave_encashment.py
@@ -10,6 +10,7 @@ from frappe.utils import getdate, nowdate, flt
from erpnext.hr.utils import set_employee_name
from erpnext.hr.doctype.leave_application.leave_application import get_leave_balance_on
from erpnext.hr.doctype.salary_structure_assignment.salary_structure_assignment import get_assigned_salary_structure
+from erpnext.hr.doctype.leave_ledger_entry.leave_ledger_entry import create_leave_ledger_entry
class LeaveEncashment(Document):
def validate(self):
@@ -40,6 +41,8 @@ class LeaveEncashment(Document):
frappe.db.set_value("Leave Allocation", self.leave_allocation, "total_leaves_encashed",
frappe.db.get_value('Leave Allocation', self.leave_allocation, 'total_leaves_encashed') + self.encashable_days)
+ self.create_leave_ledger_entry()
+
def on_cancel(self):
if self.additional_salary:
frappe.get_doc("Additional Salary", self.additional_salary).cancel()
@@ -48,6 +51,7 @@ class LeaveEncashment(Document):
if self.leave_allocation:
frappe.db.set_value("Leave Allocation", self.leave_allocation, "total_leaves_encashed",
frappe.db.get_value('Leave Allocation', self.leave_allocation, 'total_leaves_encashed') - self.encashable_days)
+ self.create_leave_ledger_entry(submit=False)
def get_leave_details_for_encashment(self):
salary_structure = get_assigned_salary_structure(self.employee, self.encashment_date or getdate(nowdate()))
@@ -75,3 +79,11 @@ class LeaveEncashment(Document):
and employee= '{2}'""".format(self.encashment_date or getdate(nowdate()), self.leave_type, self.employee))
return leave_allocation[0][0] if leave_allocation else None
+
+ def create_leave_ledger_entry(self, submit=True):
+ args = frappe._dict(
+ leaves=self.encashable_days * -1,
+ from_date=self.encashment_date,
+ is_carry_forward=0
+ )
+ create_leave_ledger_entry(self, args, submit)
\ No newline at end of file
From afb0c4aa431f55415397c6c8b6fe2c23eb0d5979 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Wed, 15 May 2019 21:50:34 +0530
Subject: [PATCH 031/484] fix: delete entry on cancellation of transaction
---
.../leave_ledger_entry/leave_ledger_entry.py | 24 ++++++++++---------
1 file changed, 13 insertions(+), 11 deletions(-)
diff --git a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
index 526a91e976..1c8fed3d7e 100644
--- a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
+++ b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
@@ -20,34 +20,36 @@ def create_leave_ledger_entry(ref_doc, args, submit=True):
employee=ref_doc.employee,
employee_name=ref_doc.employee_name,
leave_type=ref_doc.leave_type,
- from_date=ref_doc.from_date,
transaction_type=ref_doc.doctype,
transaction_name=ref_doc.name,
)
ledger.update(args)
-
if submit:
- frappe.get_doc(ledger).insert(ignore_permissions=True)
+ frappe.get_doc(ledger).submit()
else:
delete_ledger_entry(ledger)
def delete_ledger_entry(ledger):
- ''' Delete ledger entry on cancel of leave application/allocation '''
- ledger_entry, creation_date = frappe.db.get_value("Leave Ledger Entry",
- {'transaction_name': ledger.transaction_name},
- ['name', 'creation']
- )
+ ''' Delete ledger entry on cancel of leave application/allocation/encashment '''
leave_application_records = []
+ # prevent deletion when leave application has been created after allocation
if ledger.transaction_type == "Leave Allocation":
leave_application_records = frappe.get_all("Leave Ledger Entry",
filters={
+ 'employee': ledger.employee,
+ 'leave_type': ledger.leave_type,
'transaction_type': 'Leave Application',
- 'creation_date': (">", creation_date)
+ 'from_date': (">=", ledger.from_date),
+ 'to_date': ('<=', ledger.to_date)
},
- fields=['transaction_type'])
+ fields=['transaction_name'])
+
if not leave_application_records:
- frappe.delete_doc("Leave Ledger Entry", ledger_entry)
+ frappe.db.sql("""DELETE
+ FROM `tabLeave Ledger Entry`
+ WHERE
+ `transaction_name`=%s""", (ledger.transaction_name))
else:
frappe.throw(_("Leave allocation %s is linked with leave application %s"
% (ledger_entry, ', '.join(leave_application_records))))
From 5ba17c87e53bf0b3a99fb25690c19ddebf5415e4 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Wed, 22 May 2019 18:29:22 +0530
Subject: [PATCH 032/484] feat: remove update allocation after submit
---
.../leave_allocation/leave_allocation.json | 591 ++++++++++++++++--
.../leave_allocation/leave_allocation.py | 55 +-
2 files changed, 577 insertions(+), 69 deletions(-)
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.json b/erpnext/hr/doctype/leave_allocation/leave_allocation.json
index bb851c6850..568182d3b7 100644
--- a/erpnext/hr/doctype/leave_allocation/leave_allocation.json
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.json
@@ -1,192 +1,683 @@
{
+ "allow_copy": 0,
+ "allow_events_in_timeline": 0,
+ "allow_guest_to_view": 0,
"allow_import": 1,
+ "allow_rename": 0,
"autoname": "naming_series:",
+ "beta": 0,
"creation": "2013-02-20 19:10:38",
+ "custom": 0,
+ "docstatus": 0,
"doctype": "DocType",
"document_type": "Setup",
+ "editable_grid": 0,
"engine": "InnoDB",
- "field_order": [
- "naming_series",
- "employee",
- "employee_name",
- "department",
- "column_break1",
- "leave_type",
- "from_date",
- "to_date",
- "section_break_6",
- "new_leaves_allocated",
- "carry_forward",
- "carry_forwarded_leaves",
- "total_leaves_allocated",
- "total_leaves_encashed",
- "column_break_10",
- "compensatory_request",
- "leave_period",
- "amended_from",
- "notes",
- "description"
- ],
"fields": [
{
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "default": "",
"fieldname": "naming_series",
"fieldtype": "Select",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
"label": "Series",
+ "length": 0,
"no_copy": 1,
"options": "HR-LAL-.YYYY.-",
+ "permlevel": 0,
+ "precision": "",
"print_hide": 1,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
"reqd": 1,
- "set_only_once": 1
+ "search_index": 0,
+ "set_only_once": 1,
+ "translatable": 0,
+ "unique": 0
},
{
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
"fieldname": "employee",
"fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
"in_global_search": 1,
"in_list_view": 1,
"in_standard_filter": 1,
"label": "Employee",
+ "length": 0,
+ "no_copy": 0,
"oldfieldname": "employee",
"oldfieldtype": "Link",
"options": "Employee",
+ "permlevel": 0,
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
"reqd": 1,
- "search_index": 1
+ "search_index": 1,
+ "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,
"fetch_from": "employee.employee_name",
"fieldname": "employee_name",
"fieldtype": "Data",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
"in_global_search": 1,
"in_list_view": 1,
+ "in_standard_filter": 0,
"label": "Employee Name",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
"read_only": 1,
- "search_index": 1
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 1,
+ "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,
"fetch_from": "employee.department",
"fieldname": "department",
"fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
"label": "Department",
+ "length": 0,
+ "no_copy": 0,
"options": "Department",
- "read_only": 1
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "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": "column_break1",
"fieldtype": "Column Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "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,
+ "translatable": 0,
+ "unique": 0,
"width": "50%"
},
{
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
"fieldname": "leave_type",
"fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 1,
"label": "Leave Type",
+ "length": 0,
+ "no_copy": 0,
"oldfieldname": "leave_type",
"oldfieldtype": "Link",
"options": "Leave Type",
+ "permlevel": 0,
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
"reqd": 1,
- "search_index": 1
+ "search_index": 1,
+ "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": "from_date",
"fieldtype": "Date",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
"label": "From Date",
- "reqd": 1
+ "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": 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,
+ "columns": 0,
"fieldname": "to_date",
"fieldtype": "Date",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
"label": "To Date",
- "reqd": 1
+ "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": 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,
+ "columns": 0,
"fieldname": "section_break_6",
"fieldtype": "Section Break",
- "label": "Allocation"
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Allocation",
+ "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,
+ "translatable": 0,
+ "unique": 0
},
{
- "allow_on_submit": 1,
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
"bold": 1,
+ "collapsible": 0,
+ "columns": 0,
"fieldname": "new_leaves_allocated",
"fieldtype": "Float",
- "label": "New Leaves Allocated"
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "New Leaves Allocated",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "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,
+ "translatable": 0,
+ "unique": 0
},
{
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "description": "",
"fieldname": "carry_forward",
"fieldtype": "Check",
- "label": "Add unused leaves from previous allocations"
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Add unused leaves from previous allocations",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "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,
+ "translatable": 0,
+ "unique": 0
},
{
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
"depends_on": "carry_forward",
"fieldname": "carry_forwarded_leaves",
"fieldtype": "Float",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
"label": "Unused leaves",
- "read_only": 1
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "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": 1,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
"fieldname": "total_leaves_allocated",
"fieldtype": "Float",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
"label": "Total Leaves Allocated",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
"read_only": 1,
- "reqd": 1
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "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,
+ "columns": 0,
"depends_on": "eval:doc.total_leaves_encashed>0",
"fieldname": "total_leaves_encashed",
"fieldtype": "Float",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
"label": "Total Leaves Encashed",
- "read_only": 1
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "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": "column_break_10",
- "fieldtype": "Column Break"
+ "fieldtype": "Column Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 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,
+ "translatable": 0,
+ "unique": 0
},
{
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
"fieldname": "compensatory_request",
"fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
"label": "Compensatory Leave Request",
+ "length": 0,
+ "no_copy": 0,
"options": "Compensatory Leave Request",
- "read_only": 1
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "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": "leave_period",
"fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
"in_standard_filter": 1,
"label": "Leave Period",
+ "length": 0,
+ "no_copy": 0,
"options": "Leave Period",
- "read_only": 1
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "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": "amended_from",
"fieldtype": "Link",
+ "hidden": 0,
"ignore_user_permissions": 1,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
"label": "Amended From",
+ "length": 0,
"no_copy": 1,
"oldfieldname": "amended_from",
"oldfieldtype": "Data",
"options": "Leave Allocation",
+ "permlevel": 0,
"print_hide": 1,
- "read_only": 1
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "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": 1,
+ "columns": 0,
"fieldname": "notes",
"fieldtype": "Section Break",
- "label": "Notes"
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Notes",
+ "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,
+ "translatable": 0,
+ "unique": 0
},
{
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
"fieldname": "description",
"fieldtype": "Small Text",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
"label": "Description",
+ "length": 0,
+ "no_copy": 0,
"oldfieldname": "reason",
"oldfieldtype": "Small Text",
+ "permlevel": 0,
+ "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,
+ "translatable": 0,
+ "unique": 0,
"width": "300px"
}
],
+ "has_web_view": 0,
+ "hide_heading": 0,
+ "hide_toolbar": 0,
"icon": "fa fa-ok",
"idx": 1,
+ "image_view": 0,
+ "in_create": 0,
"is_submittable": 1,
- "modified": "2019-05-09 19:06:33.659196",
+ "issingle": 0,
+ "istable": 0,
+ "max_attachments": 0,
+ "modified": "2019-05-22 11:28:09.360525",
"modified_by": "Administrator",
"module": "HR",
"name": "Leave Allocation",
@@ -198,10 +689,15 @@
"create": 1,
"delete": 1,
"email": 1,
+ "export": 0,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "HR User",
+ "set_user_permissions": 0,
"share": 1,
"submit": 1,
"write": 1
@@ -213,19 +709,28 @@
"delete": 1,
"email": 1,
"export": 1,
+ "if_owner": 0,
"import": 1,
+ "permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "HR Manager",
+ "set_user_permissions": 0,
"share": 1,
"submit": 1,
"write": 1
}
],
+ "quick_entry": 0,
+ "read_only": 0,
+ "read_only_onload": 0,
"search_fields": "employee,employee_name,leave_type,total_leaves_allocated",
"show_name_in_global_search": 1,
"sort_field": "modified",
"sort_order": "DESC",
- "timeline_field": "employee"
+ "timeline_field": "employee",
+ "track_changes": 0,
+ "track_seen": 0,
+ "track_views": 0
}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.py b/erpnext/hr/doctype/leave_allocation/leave_allocation.py
index 57fe9830f6..8429ad4308 100755
--- a/erpnext/hr/doctype/leave_allocation/leave_allocation.py
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.py
@@ -47,15 +47,6 @@ class LeaveAllocation(Document):
def on_cancel(self):
self.create_leave_ledger_entry(submit=False)
- def on_update_after_submit(self):
- self.validate_new_leaves_allocated_value()
- self.set_total_leaves_allocated()
-
- frappe.db.set(self,'carry_forwarded_leaves', flt(self.carry_forwarded_leaves))
- frappe.db.set(self,'total_leaves_allocated',flt(self.total_leaves_allocated))
-
- self.validate_against_leave_applications()
-
def validate_period(self):
if date_diff(self.to_date, self.from_date) <= 0:
frappe.throw(_("To date cannot be before from date"))
@@ -108,16 +99,6 @@ class LeaveAllocation(Document):
if date_difference < self.total_leaves_allocated:
frappe.throw(_("Total allocated leaves are more than days in the period"), OverAllocationError)
- def validate_against_leave_applications(self):
- leaves_taken = get_approved_leaves_for_period(self.employee, self.leave_type,
- self.from_date, self.to_date)
-
- if flt(leaves_taken) > flt(self.total_leaves_allocated):
- if frappe.db.get_value("Leave Type", self.leave_type, "allow_negative"):
- frappe.msgprint(_("Note: Total allocated leaves {0} shouldn't be less than already approved leaves {1} for the period").format(self.total_leaves_allocated, leaves_taken))
- else:
- frappe.throw(_("Total allocated leaves {0} cannot be less than already approved leaves {1} for the period").format(self.total_leaves_allocated, leaves_taken), LessAllocationError)
-
def create_leave_ledger_entry(self, submit=True):
if self.carry_forwarded_leaves:
expiry_days = frappe.db.get_value("Leave Type", self.leave_type, "carry_forward_leave_expiry")
@@ -134,7 +115,7 @@ class LeaveAllocation(Document):
to_date=self.to_date,
is_carry_forward=0
)
- create_leave_ledger_entry(self, args)
+ create_leave_ledger_entry(self, args, submit)
def get_leave_allocation_for_period(employee, leave_type, from_date, to_date):
leave_allocated = 0
@@ -161,13 +142,35 @@ def get_leave_allocation_for_period(employee, leave_type, from_date, to_date):
@frappe.whitelist()
def get_carry_forwarded_leaves(employee, leave_type, date, carry_forward=None):
- leave_records = frappe.get_all("Leave Ledger Entry",
- filters={'Employee':employee,
- 'leave_type':leave_type,
- 'to_date':("<=", date)},
- fields=['leaves'])
+ carry_forwarded_leaves = 0
- return sum(record.get("leaves") for record in leave_records)
+ if carry_forward:
+ validate_carry_forward(leave_type)
+
+ carry_forwarded_leaves = frappe.db.sql("""
+ SELECT
+ SUM(leaves)
+ FROM `tabLeave Ledger Entry`
+ WHERE
+ employee=%s
+ AND leave_type=%s
+ AND docstatus=1
+ AND to_date < %s
+ AND name NOT IN (
+ SELECT name
+ from `tabLeave Ledger Entry`
+ WHERE
+ employee=%s
+ AND leave_type=%s
+ AND docstatus=1
+ AND to_date < %s
+ is_expired=1
+ ORDER BY creation DESC
+ )
+ ORDER BY creation DESC
+ """, (employee, leave_type, date), as_dict=1)
+
+ return carry_forwarded_leaves
def validate_carry_forward(leave_type):
if not frappe.db.get_value("Leave Type", leave_type, "is_carry_forward"):
From 8ef81870bb1f282caecc51a2de7c2c0ba9bf204d Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Thu, 23 May 2019 20:28:16 +0530
Subject: [PATCH 033/484] test: create leave ledger entry for encashment
---
.../leave_encashment/test_leave_encashment.py | 57 +++++++++++++------
1 file changed, 39 insertions(+), 18 deletions(-)
diff --git a/erpnext/hr/doctype/leave_encashment/test_leave_encashment.py b/erpnext/hr/doctype/leave_encashment/test_leave_encashment.py
index ef5c2aa6f3..cfed780eb7 100644
--- a/erpnext/hr/doctype/leave_encashment/test_leave_encashment.py
+++ b/erpnext/hr/doctype/leave_encashment/test_leave_encashment.py
@@ -9,41 +9,39 @@ from frappe.utils import today, add_months
from erpnext.hr.doctype.employee.test_employee import make_employee
from erpnext.hr.doctype.salary_structure.test_salary_structure import make_salary_structure
from erpnext.hr.doctype.leave_period.test_leave_period import create_leave_period
+from erpnext.hr.doctype.leave_policy.test_leave_policy import create_leave_policy\
test_dependencies = ["Leave Type"]
class TestLeaveEncashment(unittest.TestCase):
def setUp(self):
frappe.db.sql('''delete from `tabLeave Period`''')
- def test_leave_balance_value_and_amount(self):
- employee = "test_employee_encashment@salary.com"
- leave_type = "_Test Leave Type Encashment"
+ frappe.db.sql('''delete from `tabLeave Allocation`''')
# create the leave policy
- leave_policy = frappe.get_doc({
- "doctype": "Leave Policy",
- "leave_policy_details": [{
- "leave_type": leave_type,
- "annual_allocation": 10
- }]
- }).insert()
+ leave_policy = create_leave_policy(
+ leave_type="_Test Leave Type Encashment",
+ annual_allocation=10)
leave_policy.submit()
# create employee, salary structure and assignment
- employee = make_employee(employee)
- frappe.db.set_value("Employee", employee, "leave_policy", leave_policy.name)
- salary_structure = make_salary_structure("Salary Structure for Encashment", "Monthly", employee,
+ self.employee = make_employee("test_employee_encashment@example.com")
+ frappe.db.set_value("Employee", "test_employee_encashment@example.com", "leave_policy", leave_policy.name)
+ salary_structure = make_salary_structure("Salary Structure for Encashment", "Monthly", self.employee,
other_details={"leave_encashment_amount_per_day": 50})
# create the leave period and assign the leaves
- leave_period = create_leave_period(add_months(today(), -3), add_months(today(), 3))
- leave_period.grant_leave_allocation(employee=employee)
+ self.leave_period = create_leave_period(add_months(today(), -3), add_months(today(), 3))
+ self.leave_period.grant_leave_allocation(employee=self.employee)
+
+ def test_leave_balance_value_and_amount(self):
+ frappe.db.sql('''delete from `tabLeave Encashment`''')
leave_encashment = frappe.get_doc(dict(
doctype = 'Leave Encashment',
- employee = employee,
- leave_type = leave_type,
- leave_period = leave_period.name,
+ employee = self.employee,
+ leave_type = "_Test Leave Type Encashment",
+ leave_period = self.leave_period.name,
payroll_date = today()
)).insert()
@@ -53,3 +51,26 @@ class TestLeaveEncashment(unittest.TestCase):
leave_encashment.submit()
self.assertTrue(frappe.db.get_value("Leave Encashment", leave_encashment.name, "additional_salary"))
+
+ def test_creation_of_leave_ledger_entry_on_submit(self):
+ frappe.db.sql('''delete from `tabLeave Encashment`''')
+ leave_encashment = frappe.get_doc(dict(
+ doctype = 'Leave Encashment',
+ employee = self.employee,
+ leave_type = "_Test Leave Type Encashment",
+ leave_period = self.leave_period.name,
+ payroll_date = today()
+ )).insert()
+
+ leave_encashment.submit()
+
+ leave_ledger_entry = frappe.get_all('Leave Ledger Entry', fields='*', filters=dict(transaction_name=leave_encashment.name))
+
+ self.assertEquals(len(leave_ledger_entry), 1)
+ self.assertEquals(leave_ledger_entry[0].employee, leave_encashment.employee)
+ self.assertEquals(leave_ledger_entry[0].leave_type, leave_encashment.leave_type)
+ self.assertEquals(leave_ledger_entry[0].leaves, leave_encashment.encashable_days * -1)
+
+ # check if leave ledger entry is deleted on cancellation
+ leave_encashment.cancel()
+ self.assertFalse(frappe.db.exists("Leave Ledger Entry", {'transaction_name':leave_encashment.name}))
From 45cf02308e8ef0effb3260d340988b95b342f5a2 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Thu, 23 May 2019 20:29:18 +0530
Subject: [PATCH 034/484] fix: prevent manual creation of ledger entries
---
.../leave_ledger_entry.json | 49 ++++++++++++++++++-
1 file changed, 48 insertions(+), 1 deletion(-)
diff --git a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.json b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.json
index 89c703db65..ae36735570 100644
--- a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.json
+++ b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.json
@@ -19,6 +19,7 @@
{
"fieldname": "employee",
"fieldtype": "Link",
+ "in_list_view": 1,
"label": "Employee",
"options": "Employee"
},
@@ -30,6 +31,7 @@
{
"fieldname": "leave_type",
"fieldtype": "Link",
+ "in_list_view": 1,
"label": "Leave Type",
"options": "Leave Type"
},
@@ -57,16 +59,19 @@
{
"fieldname": "leaves",
"fieldtype": "Int",
+ "in_list_view": 1,
"label": "Leaves"
},
{
"fieldname": "from_date",
"fieldtype": "Date",
+ "in_list_view": 1,
"label": "From Date"
},
{
"fieldname": "to_date",
"fieldtype": "Date",
+ "in_list_view": 1,
"label": "To Date"
},
{
@@ -80,8 +85,9 @@
"label": "Is Expired"
}
],
+ "in_create": 1,
"is_submittable": 1,
- "modified": "2019-05-13 12:56:45.542495",
+ "modified": "2019-05-23 19:22:09.028366",
"modified_by": "Administrator",
"module": "HR",
"name": "Leave Ledger Entry",
@@ -97,6 +103,47 @@
"report": 1,
"role": "System Manager",
"share": 1,
+ "submit": 1,
+ "write": 1
+ },
+ {
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "HR Manager",
+ "share": 1,
+ "submit": 1,
+ "write": 1
+ },
+ {
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "HR User",
+ "share": 1,
+ "submit": 1,
+ "write": 1
+ },
+ {
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "if_owner": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "All",
+ "share": 1,
+ "submit": 1,
"write": 1
}
],
From f3926d0fcbd57e7e3c59f33b2992a699ce3902a7 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Sun, 26 May 2019 20:17:16 +0530
Subject: [PATCH 035/484] patch: leave ledger entries
---
erpnext/patches.txt | 1 +
.../v12_0/generate_leave_ledger_entries.py | 95 +++++++++++++++++++
2 files changed, 96 insertions(+)
create mode 100644 erpnext/patches/v12_0/generate_leave_ledger_entries.py
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index bdc1ed4f10..a7fb7a2bb5 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -602,3 +602,4 @@ erpnext.patches.v11_1.set_salary_details_submittable
erpnext.patches.v11_1.rename_depends_on_lwp
execute:frappe.delete_doc("Report", "Inactive Items")
erpnext.patches.v11_1.delete_scheduling_tool
+erpnext.patches.v12_0.generate_leave_ledger_entries
\ No newline at end of file
diff --git a/erpnext/patches/v12_0/generate_leave_ledger_entries.py b/erpnext/patches/v12_0/generate_leave_ledger_entries.py
new file mode 100644
index 0000000000..9223bb2ebc
--- /dev/null
+++ b/erpnext/patches/v12_0/generate_leave_ledger_entries.py
@@ -0,0 +1,95 @@
+# Copyright (c) 2018, Frappe and Contributors
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+import frappe
+
+def execute():
+ """ Generates leave ledger entries for leave allocation/application/encashment
+ for last allocation """
+ if frappe.db.exists("DocType","Leave Ledger Entry"):
+ return
+
+ allocation_list = get_allocation_records()
+ generate_allocation_ledger_entries(allocation_list)
+ generate_application_leave_ledger_entries(allocation_list)
+ generate_encashment_leave_ledger_entries(allocation_list)
+
+def generate_allocation_ledger_entries(allocation_list):
+ ''' fix ledger entries for missing leave allocation transaction '''
+ from erpnext.hr.doctype.leave_allocation.leave_allocation import LeaveAllocation
+
+ for allocation in allocation_list:
+ LeaveAllocation.create_leave_ledger_entry(allocation)
+
+def generate_application_leave_ledger_entries(allocation_list):
+ ''' fix ledger entries for missing leave application transaction '''
+ from erpnext.hr.doctype.leave_application.leave_application import LeaveApplication
+
+ leave_applications = get_leaves_application_records(allocation_list)
+
+ for record in leave_applications:
+ LeaveApplication.create_leave_ledger_entry(record)
+
+def generate_encashment_leave_ledger_entries(allocation_list):
+ ''' fix ledger entries for missing leave encashment transaction '''
+ from erpnext.hr.doctype.leave_encashment.leave_encashment import LeaveEncashment
+
+ leave_encashments = get_leave_encashment_records(allocation_list)
+
+ for record in leave_encashments:
+ LeaveEncashment.create_leave_ledger_entry(record)
+
+def get_allocation_records():
+ return frappe.db.sql("""
+ SELECT
+ DISTINCT name,
+ employee,
+ leave_type,
+ new_leaves_allocated,
+ carry_forwarded_leaves,
+ from_date,
+ to_date,
+ carry_forward,
+ RANK() OVER(PARTITION BY employee, leave_type ORDER BY to_date DESC) as allocation
+ FROM `tabLeave Allocation`
+ WHERE
+ allocation=1
+ """, as_dict=1)
+
+def get_leaves_application_records(allocation_list):
+ leave_applications = []
+ for allocation in allocation_list:
+ leave_applications.append(frappe.db.sql("""
+ SELECT
+ name,
+ employee,
+ leave_type,
+ total_leave_days,
+ from_date,
+ to_date
+ FROM `tabLeave Application`
+ WHERE
+ from_date >= %s
+ leave_type = %s
+ employee = %s
+ """, (allocation.from_date, allocation.leave_type, allocation.employee)))
+ return leave_applications
+
+def get_leave_encashment_records(allocation_list):
+ leave_encashments = []
+ for allocation in allocation_list:
+ leave_encashments.append(frappe.db.sql("""
+ SELECT
+ DISTINCT name,
+ employee,
+ leave_type,
+ encashable_days,
+ from_date,
+ to_date
+ FROM `tabLeave Encashment`
+ WHERE
+ leave_type = %s
+ employee = %s
+ """, (allocation.leave_type, allocation.employee)))
+ return leave_encashments
\ No newline at end of file
From 9e3b6883332ac26d6aca89c147e1cda233709960 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Mon, 27 May 2019 03:10:39 +0530
Subject: [PATCH 036/484] test: create leave policy
---
.../doctype/leave_policy/test_leave_policy.py | 22 +++++++++++--------
1 file changed, 13 insertions(+), 9 deletions(-)
diff --git a/erpnext/hr/doctype/leave_policy/test_leave_policy.py b/erpnext/hr/doctype/leave_policy/test_leave_policy.py
index 2c6f1d0a21..fc868ea15a 100644
--- a/erpnext/hr/doctype/leave_policy/test_leave_policy.py
+++ b/erpnext/hr/doctype/leave_policy/test_leave_policy.py
@@ -12,16 +12,20 @@ class TestLeavePolicy(unittest.TestCase):
if random_leave_type:
random_leave_type = random_leave_type[0]
leave_type = frappe.get_doc("Leave Type", random_leave_type.name)
- old_max_leaves_allowed = leave_type.max_leaves_allowed
leave_type.max_leaves_allowed = 2
leave_type.save()
- leave_policy_details = {
- "doctype": "Leave Policy",
- "leave_policy_details": [{
- "leave_type": leave_type.name,
- "annual_allocation": leave_type.max_leaves_allowed + 1
- }]
- }
+ leave_policy = create_leave_policy(leave_type=leave_type.name, annual_allocation=leave_type.max_leaves_allowed + 1)
- self.assertRaises(frappe.ValidationError, frappe.get_doc(leave_policy_details).insert)
+ self.assertRaises(frappe.ValidationError, leave_policy.insert)
+
+def create_leave_policy(**args):
+ ''' Returns an object of leave policy '''
+ args = frappe._dict(args)
+ return frappe.get_doc({
+ "doctype": "Leave Policy",
+ "leave_policy_details": [{
+ "leave_type": args.leave_type or "_Test Leave Type",
+ "annual_allocation": args.annual_allocation or 10
+ }]
+ })
\ No newline at end of file
From 7a7f4bd822f0474ba9b97d85786b66d20369644d Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Mon, 27 May 2019 03:12:57 +0530
Subject: [PATCH 037/484] fix: leave balance calculation
---
.../leave_application/leave_application.js | 3 +-
.../leave_application/leave_application.py | 127 +++++++++++++-----
2 files changed, 92 insertions(+), 38 deletions(-)
diff --git a/erpnext/hr/doctype/leave_application/leave_application.js b/erpnext/hr/doctype/leave_application/leave_application.js
index 5bce348489..0b0a69f7a1 100755
--- a/erpnext/hr/doctype/leave_application/leave_application.js
+++ b/erpnext/hr/doctype/leave_application/leave_application.js
@@ -143,7 +143,8 @@ frappe.ui.form.on("Leave Application", {
method: "erpnext.hr.doctype.leave_application.leave_application.get_leave_balance_on",
args: {
employee: frm.doc.employee,
- date: frm.doc.from_date,
+ from_date: frm.doc.from_date,
+ to_date: frm.doc.to_date,
leave_type: frm.doc.leave_type,
consider_all_leaves_in_the_allocation_period: true
},
diff --git a/erpnext/hr/doctype/leave_application/leave_application.py b/erpnext/hr/doctype/leave_application/leave_application.py
index 9e0ed0f1b5..2adf8fba71 100755
--- a/erpnext/hr/doctype/leave_application/leave_application.py
+++ b/erpnext/hr/doctype/leave_application/leave_application.py
@@ -195,9 +195,8 @@ class LeaveApplication(Document):
frappe.throw(_("The day(s) on which you are applying for leave are holidays. You need not apply for leave."))
if not is_lwp(self.leave_type):
- self.leave_balance = get_leave_balance_on(self.employee, self.leave_type, self.from_date, docname=self.name,
+ self.leave_balance = get_leave_balance_on(self.employee, self.leave_type, self.from_date, self.to_date,
consider_all_leaves_in_the_allocation_period=True)
-
if self.status != "Rejected" and self.leave_balance < self.total_leave_days:
if frappe.db.get_value("Leave Type", self.leave_type, "allow_negative"):
frappe.msgprint(_("Note: There is not enough leave balance for Leave Type {0}")
@@ -351,13 +350,46 @@ class LeaveApplication(Document):
pass
def create_leave_ledger_entry(self, submit=True):
- args = frappe._dict(
- leaves=self.total_leave_days,
+ expiry_date = get_allocation_expiry(self.employee, self.leave_type,
+ self.to_date, self.from_date)
+
+ if expiry_date:
+ self.create_application_entry_for_expiry(expiry_date)
+ else:
+ args = dict(
+ leaves=self.total_leave_days * -1,
+ from_date=self.from_date,
+ to_date=self.to_date,
+ )
+ create_leave_ledger_entry(self, args, submit)
+
+ def create_application_entry_for_expiry(self, expiry_date):
+ ''' splits leave application into two ledger entries to consider expiry '''
+ args = dict(
from_date=self.from_date,
to_date=self.to_date,
- is_carry_forward=0
+ leaves=date_diff(expiry_date, self.from_date) * -1
)
create_leave_ledger_entry(self, args, submit)
+ start_date = add_days(expiry_date, 1)
+ args.update(dict(
+ from_date=start_date,
+ to_date=self.to_date,
+ leaves=date_diff(self.to_date, start_date) * -1
+ ))
+ create_leave_ledger_entry(self, args, submit)
+
+def get_allocation_expiry(employee, leave_type, to_date, from_date):
+ return frappe.db.sql("""
+ SELECT
+ to_date
+ FROM `tabLeave Ledger Entry`
+ WHERE
+ employee='%s'
+ AND leave_type='%s'
+ AND transaction_type='Leave Allocation'
+ AND (to_date BETWEEN %s AND %s)
+ """ %(employee, leave_type, from_date, to_date), as_dict=1)
@frappe.whitelist()
def get_number_of_leave_days(employee, leave_type, from_date, to_date, half_day = None, half_day_date = None):
@@ -380,10 +412,11 @@ def get_leave_details(employee, date):
leave_allocation = {}
for d in allocation_records:
allocation = allocation_records.get(d, frappe._dict())
+ remaining_leaves = get_leave_balance_on(employee, d, date)
date = allocation.to_date
leaves_taken = get_leaves_for_period(employee, d, allocation.from_date, date, status="Approved")
leaves_pending = get_leaves_for_period(employee, d, allocation.from_date, date, status="Open")
- remaining_leaves = allocation.total_leaves_allocated - leaves_taken - leaves_pending
+
leave_allocation[d] = {
"total_leaves": allocation.total_leaves_allocated,
"leaves_taken": leaves_taken,
@@ -397,37 +430,45 @@ def get_leave_details(employee, date):
return ret
-def get_leave_balance_on(employee, leave_type, date, allocation_records=None, docname=None,
- consider_all_leaves_in_the_allocation_period=False, consider_encashed_leaves=True):
+@frappe.whitelist()
+def get_leave_balance_on(employee, leave_type, from_date, to_date=nowdate(), allocation_records=None, docname=None,
+ consider_all_leaves_in_the_allocation_period=False):
if allocation_records == None:
- allocation_records = get_leave_allocation_records(date, employee).get(employee, frappe._dict())
+ allocation_records = get_leave_allocation_records(from_date, employee).get(employee, frappe._dict())
allocation = allocation_records.get(leave_type, frappe._dict())
- if consider_all_leaves_in_the_allocation_period:
- date = allocation.to_date
- leaves_taken = frappe.db.get_value("Leave Ledger Entry", filters={
+
+ end_date = allocation.to_date if consider_all_leaves_in_the_allocation_period else from_date
+ expiry = get_allocation_expiry(employee, leave_type, to_date, from_date)
+
+ leaves_taken = get_leaves_taken(employee, leave_type, allocation.from_date, end_date)
+ return get_remaining_leaves(allocation, leaves_taken, from_date, expiry)
+
+def get_remaining_leaves(allocation, leaves_taken, date, expiry):
+ ''' Returns leaves remaining after comparing with remaining days for allocation expiry '''
+ def _get_remaining_leaves(allocated_leaves, end_date):
+ remaining_leaves = flt(allocated_leaves) + flt(leaves_taken)
+
+ if remaining_leaves > 0:
+ remaining_days = date_diff(end_date, date) + 1
+ remaining_leaves = min(remaining_days, remaining_leaves)
+ return remaining_leaves
+
+ if expiry:
+ remaining_leaves = _get_remaining_leaves(allocation.carry_forwarded_leaves, expiry)
+ return flt(allocation.new_leaves_allocated) + flt(remaining_leaves)
+ else:
+ return _get_remaining_leaves(allocation.total_leaves_allocated, allocation.to_date)
+
+def get_leaves_taken(employee, leave_type, from_date, to_date):
+ ''' Returns leaves taken based on leave application/encashment '''
+ return frappe.db.get_value("Leave Ledger Entry", filters={
'Employee':employee,
'leave_type':leave_type,
- 'transaction_type': ('!=', 'Leave Allocation'),
- 'to_date':("<=", date),
- 'from_date': from_date},
- fields=['SUM(leaves)'])
-
- remaining_unused_leaves = flt(allocation.unused_leaves + leaves_taken)
- if allocation.carry_forward and remaining_unused_leaves > 0:
- expiry_date = frappe.db.get_value("Leave Ledger Entry", filters={
- 'Employee':employee,
- 'leave_type':leave_type,
- 'transaction_type': 'Leave Allocation',
- 'transaction_name': allocation.name,
- 'is_carry_forward': 1,
- 'is_expiry': 0
- }, fieldname=['to_date'])
- remaining_days = date_diff(expiry_date, date) + 1
-
- remaining_unused_leaves = min(remaining_days, remaining_unused_leaves)
-
- return flt(allocation.new_leaves) + remaining_unused_leaves + leaves_taken
+ 'leaves': ("<", 0),
+ 'to_date':("<=", to_date),
+ 'from_date': (">=", from_date)},
+ fieldname=['SUM(leaves)'])
def get_total_allocated_leaves(employee, leave_type, date):
filters= {
@@ -479,19 +520,31 @@ def get_leave_allocation_records(date, employee=None):
conditions = (" and employee='%s'" % employee) if employee else ""
leave_allocation_records = frappe.db.sql("""
- select employee, leave_type, total_leaves_allocated, total_leaves_encashed, from_date, to_date
- from `tabLeave Allocation`
- where %s between from_date and to_date and docstatus=1 {0}""".format(conditions), (date), as_dict=1)
+ SELECT
+ employee,
+ leave_type,
+ total_leaves_allocated,
+ carry_forwarded_leaves,
+ new_leaves_allocated,
+ carry_forward,
+ from_date,
+ to_date
+ FROM
+ `tabLeave Allocation`
+ WHERE
+ %s between from_date and to_date
+ AND docstatus=1 {0}""".format(conditions), (date), as_dict=1) #nosec
allocated_leaves = frappe._dict()
for d in leave_allocation_records:
allocated_leaves.setdefault(d.employee, frappe._dict()).setdefault(d.leave_type, frappe._dict({
"from_date": d.from_date,
"to_date": d.to_date,
+ "total_leaves_allocated": d.total_leaves_allocated,
"carry_forward": d.carry_forward,
- "unused_leaves": d.carry_forwarded_leaves,
+ "carry_forwarded_leaves": d.carry_forwarded_leaves,
"new_leaves": d.new_leaves_allocated,
- "name": d.name
+ "leave_type": d.leave_type
}))
return allocated_leaves
From c99f644ffe661af081df406824dda294a7aef4c2 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Mon, 27 May 2019 03:13:47 +0530
Subject: [PATCH 038/484] test: carry forward and expiry allocation
---
.../leave_allocation/test_leave_allocation.py | 68 ++++++++++++++++++-
1 file changed, 65 insertions(+), 3 deletions(-)
diff --git a/erpnext/hr/doctype/leave_allocation/test_leave_allocation.py b/erpnext/hr/doctype/leave_allocation/test_leave_allocation.py
index a0113e2d9f..308f2245b9 100644
--- a/erpnext/hr/doctype/leave_allocation/test_leave_allocation.py
+++ b/erpnext/hr/doctype/leave_allocation/test_leave_allocation.py
@@ -3,6 +3,7 @@ import frappe
import unittest
from frappe.utils import nowdate, add_months, getdate, add_days
from erpnext.hr.doctype.leave_type.test_leave_type import create_leave_type
+from erpnext.hr.doctype.leave_ledger_entry.leave_ledger_entry import process_expired_allocation
class TestLeaveAllocation(unittest.TestCase):
def test_overlapping_allocation(self):
@@ -68,6 +69,65 @@ class TestLeaveAllocation(unittest.TestCase):
#allocated leave more than period
self.assertRaises(frappe.ValidationError, doc.save)
+ def test_carry_forward_calculation(self):
+ frappe.db.sql("delete from `tabLeave Allocation`")
+ frappe.db.sql("delete from `tabLeave Ledger Entry`")
+ leave_type = create_leave_type(leave_type_name="_Test_CF_leave", is_carry_forward=1)
+ leave_type.submit()
+
+ # initial leave allocation
+ leave_allocation = create_leave_allocation(
+ leave_type="_Test_CF_leave",
+ from_date=add_months(nowdate(), -12),
+ to_date=add_months(nowdate(), -1),
+ carry_forward=1)
+ leave_allocation.submit()
+
+ # leave allocation with carry forward from previous allocation
+ leave_allocation_1 = create_leave_allocation(
+ leave_type="_Test_CF_leave",
+ carry_forward=1)
+ leave_allocation_1.submit()
+
+ self.assertEquals(leave_allocation.total_leaves_allocated, leave_allocation_1.carry_forwarded_leaves)
+
+ def test_carry_forward_leaves_expiry(self):
+ frappe.db.sql("delete from `tabLeave Allocation`")
+ frappe.db.sql("delete from `tabLeave Ledger Entry`")
+ leave_type = create_leave_type(
+ leave_type_name="_Test_CF_leave_expiry",
+ is_carry_forward=1,
+ carry_forward_leave_expiry=90)
+ leave_type.submit()
+
+ # initial leave allocation
+ leave_allocation = create_leave_allocation(
+ leave_type="_Test_CF_leave_expiry",
+ from_date=add_months(nowdate(), -24),
+ to_date=add_months(nowdate(), -12),
+ carry_forward=1)
+ leave_allocation.submit()
+
+ leave_allocation = create_leave_allocation(
+ leave_type="_Test_CF_leave_expiry",
+ from_date=add_days(nowdate(), -90),
+ to_date=add_days(nowdate(), 100),
+ carry_forward=1)
+ leave_allocation.submit()
+
+ # expires all the carry forwarded leaves after 90 days
+ process_expired_allocation()
+
+ # leave allocation with carry forward of only new leaves allocated
+ leave_allocation_1 = create_leave_allocation(
+ leave_type="_Test_CF_leave_expiry",
+ carry_forward=1,
+ from_date=add_months(nowdate(), 6),
+ to_date=add_months(nowdate(), 12))
+ leave_allocation_1.submit()
+
+ self.assertEquals(leave_allocation_1.carry_forwarded_leaves, leave_allocation.new_leaves_allocated)
+
def test_creation_of_leave_ledger_entry_on_submit(self):
frappe.db.sql("delete from `tabLeave Allocation`")
@@ -92,11 +152,13 @@ def create_leave_allocation(**args):
leave_allocation = frappe.get_doc({
"doctype": "Leave Allocation",
"__islocal": 1,
- "employee": employee.name,
- "employee_name": employee.employee_name,
- "leave_type": args.leave_type.leave_type_name or "_Test Leave Type",
+ "employee": args.employee or employee.name,
+ "employee_name": args.employee_name or employee.employee_name,
+ "leave_type": args.leave_type or "_Test Leave Type",
"from_date": args.from_date or nowdate(),
"new_leaves_allocated": args.new_leaves_created or 15,
+ "carry_forward": args.carry_forward or 0,
+ "carry_forwarded_leaves": args.carry_forwarded_leaves or 0,
"to_date": args.to_date or add_months(nowdate(), 12)
})
return leave_allocation
From 2417c93d0eaff061cff7416d7f5f27ace72ecfeb Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Mon, 27 May 2019 03:20:10 +0530
Subject: [PATCH 039/484] feat: create expiry and carry forward calculation on
leave allocation creation
---
.../leave_allocation/leave_allocation.js | 2 +-
.../leave_allocation/leave_allocation.py | 63 +++++++++++--------
2 files changed, 38 insertions(+), 27 deletions(-)
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.js b/erpnext/hr/doctype/leave_allocation/leave_allocation.js
index 228b5528de..1fc1d89635 100755
--- a/erpnext/hr/doctype/leave_allocation/leave_allocation.js
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.js
@@ -66,4 +66,4 @@ frappe.ui.form.on("Leave Allocation", {
frm.set_value("total_leaves_allocated", flt(frm.doc.new_leaves_allocated));
}
}
-})
\ No newline at end of file
+});
\ No newline at end of file
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.py b/erpnext/hr/doctype/leave_allocation/leave_allocation.py
index 8429ad4308..6fe8fdff24 100755
--- a/erpnext/hr/doctype/leave_allocation/leave_allocation.py
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.py
@@ -3,7 +3,7 @@
from __future__ import unicode_literals
import frappe
-from frappe.utils import flt, date_diff, formatdate
+from frappe.utils import flt, date_diff, formatdate, add_days
from frappe import _
from frappe.model.document import Document
from erpnext.hr.utils import set_employee_name, get_leave_period
@@ -42,6 +42,7 @@ class LeaveAllocation(Document):
.format(self.leave_type, self.employee))
def on_submit(self):
+ self.expire_previous_allocation()
self.create_leave_ledger_entry()
def on_cancel(self):
@@ -89,10 +90,20 @@ class LeaveAllocation(Document):
self.leave_type, self.from_date, self.carry_forward)
self.total_leaves_allocated = flt(self.carry_forwarded_leaves) + flt(self.new_leaves_allocated)
+ self.maintain_carry_forwarded_leaves()
if not self.total_leaves_allocated and not frappe.db.get_value("Leave Type", self.leave_type, "is_earned_leave") and not frappe.db.get_value("Leave Type", self.leave_type, "is_compensatory"):
frappe.throw(_("Total leaves allocated is mandatory for Leave Type {0}".format(self.leave_type)))
+ def maintain_carry_forwarded_leaves(self):
+ ''' reduce the carry forwarded leaves to be within the maximum allowed leaves '''
+ if not self.carry_forward:
+ return
+ max_leaves_allowed = frappe.db.get_value("Leave Type", self.leave_type, "max_leaves_allowed")
+ if self.new_leaves_allocated <= max_leaves_allowed <= self.total_leaves_allocated:
+ self.carry_forwarded_leaves = max_leaves_allowed - flt(self.new_leaves_allocated)
+ self.total_leaves_allocated = flt(max_leaves_allowed)
+
def validate_total_leaves_allocated(self):
# Adding a day to include To Date in the difference
date_difference = date_diff(self.to_date, self.from_date) + 1
@@ -102,9 +113,9 @@ class LeaveAllocation(Document):
def create_leave_ledger_entry(self, submit=True):
if self.carry_forwarded_leaves:
expiry_days = frappe.db.get_value("Leave Type", self.leave_type, "carry_forward_leave_expiry")
-
args = dict(
leaves=self.carry_forwarded_leaves,
+ from_date=self.from_date,
to_date=add_days(self.from_date, expiry_days) if expiry_days else self.to_date,
is_carry_forward=1
)
@@ -112,11 +123,26 @@ class LeaveAllocation(Document):
args = dict(
leaves=self.new_leaves_allocated,
+ from_date=self.from_date,
to_date=self.to_date,
is_carry_forward=0
)
create_leave_ledger_entry(self, args, submit)
+ def expire_previous_allocation(self):
+ ''' expire previous allocation leaves '''
+ leaves = get_remaining_leaves(self.employee, self.leave_type, self.from_date)
+
+ if flt(leaves) > 0:
+ args = dict(
+ leaves=leaves * -1,
+ from_date=self.to_date,
+ to_date=self.to_date,
+ is_carry_forward=0,
+ is_expired=1
+ )
+ create_leave_ledger_entry(self, args)
+
def get_leave_allocation_for_period(employee, leave_type, from_date, to_date):
leave_allocated = 0
leave_allocations = frappe.db.sql("""
@@ -143,35 +169,20 @@ def get_leave_allocation_for_period(employee, leave_type, from_date, to_date):
@frappe.whitelist()
def get_carry_forwarded_leaves(employee, leave_type, date, carry_forward=None):
carry_forwarded_leaves = 0
-
if carry_forward:
validate_carry_forward(leave_type)
-
- carry_forwarded_leaves = frappe.db.sql("""
- SELECT
- SUM(leaves)
- FROM `tabLeave Ledger Entry`
- WHERE
- employee=%s
- AND leave_type=%s
- AND docstatus=1
- AND to_date < %s
- AND name NOT IN (
- SELECT name
- from `tabLeave Ledger Entry`
- WHERE
- employee=%s
- AND leave_type=%s
- AND docstatus=1
- AND to_date < %s
- is_expired=1
- ORDER BY creation DESC
- )
- ORDER BY creation DESC
- """, (employee, leave_type, date), as_dict=1)
+ carry_forwarded_leaves = get_remaining_leaves(employee, leave_type, date)
return carry_forwarded_leaves
+def get_remaining_leaves(employee, leave_type, date):
+ return frappe.db.get_value("Leave Ledger Entry", filters={
+ "to_date": ("<=", date),
+ "employee": employee,
+ "docstatus": 1,
+ "leave_type": leave_type,
+ }, fieldname=['SUM(leaves)'])
+
def validate_carry_forward(leave_type):
if not frappe.db.get_value("Leave Type", leave_type, "is_carry_forward"):
frappe.throw(_("Leave Type {0} cannot be carry-forwarded").format(leave_type))
\ No newline at end of file
From e7d307e6bf98eceb2741bf36d848263611043b71 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Mon, 27 May 2019 03:21:32 +0530
Subject: [PATCH 040/484] fix: only expire carry forwarded allocation via
scheduler
---
erpnext/hooks.py | 2 +-
.../leave_ledger_entry/leave_ledger_entry.py | 115 ++++++++++--------
2 files changed, 65 insertions(+), 52 deletions(-)
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index 72c538fd3c..28dd4e8f9c 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -264,7 +264,7 @@ scheduler_events = {
"erpnext.projects.doctype.project.project.update_project_sales_billing",
"erpnext.projects.doctype.project.project.send_project_status_email_to_users",
"erpnext.quality_management.doctype.quality_review.quality_review.review",
- "erpnext.hr.doctype.leave_ledger_entry.leave_ledger_entry.check_expired_allocation"
+ "erpnext.hr.doctype.leave_ledger_entry.leave_ledger_entry.process_expired_allocation"
"erpnext.support.doctype.service_level_agreement.service_level_agreement.check_agreement_status"
],
"daily_long": [
diff --git a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
index 1c8fed3d7e..e85d5cef0a 100644
--- a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
+++ b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
@@ -6,14 +6,34 @@ from __future__ import unicode_literals
import frappe
from frappe.model.document import Document
from frappe import _
-from frappe.utils import add_days, today
+from frappe.utils import add_days, today, flt
class LeaveLedgerEntry(Document):
def validate_entries(self):
- leave_records = frappe.get_all('Leave Ledger Entry', ['leaves'])
- if sum(record.get("leaves") for record in leave_records) <0:
+ total_leaves = frappe.get_all('Leave Ledger Entry', ['SUM(leaves)'])
+ if total_leaves < 0:
frappe.throw(_("Invalid Ledger Entry"))
+ def on_cancel(self):
+ # allow cancellation of expiry leaves
+ if not self.is_expired:
+ frappe.throw(_("Only expired allocation can be cancelled"))
+
+def validate_leave_allocation_against_leave_application(ledger):
+ ''' Checks that leave allocation has no leave application against it '''
+ leave_application_records = frappe.get_all("Leave Ledger Entry",
+ filters={
+ 'employee': ledger.employee,
+ 'leave_type': ledger.leave_type,
+ 'transaction_type': 'Leave Application',
+ 'from_date': (">=", ledger.from_date),
+ 'to_date': ('<=', ledger.to_date)
+ }, fields=['transaction_name'])
+
+ if leave_application_records:
+ frappe.throw(_("Leave allocation %s is linked with leave application %s"
+ % (ledger.transaction_name, ', '.join(leave_application_records))))
+
def create_leave_ledger_entry(ref_doc, args, submit=True):
ledger = frappe._dict(
doctype='Leave Ledger Entry',
@@ -22,6 +42,8 @@ def create_leave_ledger_entry(ref_doc, args, submit=True):
leave_type=ref_doc.leave_type,
transaction_type=ref_doc.doctype,
transaction_name=ref_doc.name,
+ is_carry_forward=0,
+ is_expired=0
)
ledger.update(args)
if submit:
@@ -32,67 +54,58 @@ def create_leave_ledger_entry(ref_doc, args, submit=True):
def delete_ledger_entry(ledger):
''' Delete ledger entry on cancel of leave application/allocation/encashment '''
- leave_application_records = []
- # prevent deletion when leave application has been created after allocation
if ledger.transaction_type == "Leave Allocation":
- leave_application_records = frappe.get_all("Leave Ledger Entry",
+ validate_leave_allocation_against_leave_application(ledger)
+
+ frappe.db.sql("""DELETE
+ FROM `tabLeave Ledger Entry`
+ WHERE
+ `transaction_name`=%s""", (ledger.transaction_name))
+
+def process_expired_allocation():
+ ''' Check if a carry forwarded allocation has expired and create a expiry ledger entry '''
+
+ # fetch leave type records that has carry forwarded leaves expiry
+ leave_type_records = frappe.db.get_values("Leave Type", filters={
+ 'carry_forward_leave_expiry': (">", 0)
+ }, fieldname=['name'])
+
+ if leave_type_records:
+ leave_type = [record[0] for record in leave_type_records]
+ expired_allocation = frappe.get_all("Leave Ledger Entry",
filters={
- 'employee': ledger.employee,
- 'leave_type': ledger.leave_type,
- 'transaction_type': 'Leave Application',
- 'from_date': (">=", ledger.from_date),
- 'to_date': ('<=', ledger.to_date)
- },
- fields=['transaction_name'])
-
- if not leave_application_records:
- frappe.db.sql("""DELETE
- FROM `tabLeave Ledger Entry`
- WHERE
- `transaction_name`=%s""", (ledger.transaction_name))
- else:
- frappe.throw(_("Leave allocation %s is linked with leave application %s"
- % (ledger_entry, ', '.join(leave_application_records))))
-
-def check_expired_allocation():
- ''' Checks for expired allocation by comparing to_date with current_date and
- based on that creates an expiry ledger entry '''
- expired_allocation = frappe.get_all("Leave Ledger Allocation",
- filters={
- 'to_date': today(),
- 'transaction_type': 'Leave Allocation'
- },
- fields=['*'])
+ 'to_date': today(),
+ 'transaction_type': 'Leave Allocation',
+ 'is_carry_forward': 1,
+ 'leave_type': ('in', leave_type)
+ }, fields=['leaves', 'to_date', 'employee', 'leave_type'])
if expired_allocation:
create_expiry_ledger_entry(expired_allocation)
def create_expiry_ledger_entry(expired_allocation):
+ ''' Create expiry ledger entry for carry forwarded leaves '''
for allocation in expired_allocation:
- filters = {
- 'employee': allocation.employee,
- 'leave_type': allocation.leave_type,
- 'from_date': ('>=', allocation.from_date),
- }
- # get only application ledger entries in case of carry forward
- if allocation.is_carry_forward:
- filters.update(dict(transaction_type='Leave Application'))
- leave_records = frappe.get_all("Leave Ledger Entry",
- filters=filters,
- fields=['leaves'])
-
- leaves = sum(record.get("leaves") for record in leave_records)
-
- if allocation.is_carry_forward:
- leaves = allocation.leaves + leaves
+ leaves_taken = get_leaves_taken(allocation)
+ leaves = flt(allocation.leaves) + flt(leaves_taken)
if leaves > 0:
args = frappe._dict(
leaves=allocation.leaves * -1,
- to_date='',
- is_carry_forward=allocation.is_carry_forward,
+ to_date=allocation.to_date,
+ is_carry_forward=1,
is_expired=1,
from_date=allocation.to_date
)
- create_leave_ledger_entry(allocation, args)
\ No newline at end of file
+ create_leave_ledger_entry(allocation, args)
+
+def get_leaves_taken(allocation):
+ return frappe.db.get_value("Leave Ledger Entry",
+ filters={
+ 'employee': allocation.employee,
+ 'leave_type': allocation.leave_type,
+ 'from_date': ('>=', allocation.from_date),
+ 'to_date': ('<=', allocation.to_date),
+ 'transaction_type': 'Leave application'
+ }, fieldname=['SUM(leaves)'])
\ No newline at end of file
From d751281fa721c0ac75e452826e61f381c91a6186 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Mon, 27 May 2019 03:23:58 +0530
Subject: [PATCH 041/484] fix: application and leave encashment test cases
---
.../test_leave_application.py | 31 +++++++++++++------
.../leave_encashment/leave_encashment.py | 1 +
2 files changed, 23 insertions(+), 9 deletions(-)
diff --git a/erpnext/hr/doctype/leave_application/test_leave_application.py b/erpnext/hr/doctype/leave_application/test_leave_application.py
index 2581c2a659..4dea413dc3 100644
--- a/erpnext/hr/doctype/leave_application/test_leave_application.py
+++ b/erpnext/hr/doctype/leave_application/test_leave_application.py
@@ -8,6 +8,8 @@ import unittest
from erpnext.hr.doctype.leave_application.leave_application import LeaveDayBlockedError, OverlapError, NotAnOptionalHoliday, get_leave_balance_on
from frappe.permissions import clear_user_permissions_for_doctype
from frappe.utils import add_days, nowdate, now_datetime, getdate
+from erpnext.hr.doctype.leave_type.test_leave_type import create_leave_type
+from erpnext.hr.doctype.leave_allocation.test_leave_allocation import create_leave_allocation
test_dependencies = ["Leave Allocation", "Leave Block List"]
@@ -274,7 +276,7 @@ class TestLeaveApplication(unittest.TestCase):
))
# can only apply on optional holidays
- self.assertTrue(NotAnOptionalHoliday, leave_application.insert)
+ self.assertRaises(NotAnOptionalHoliday, leave_application.insert)
leave_application.from_date = today
leave_application.to_date = today
@@ -287,6 +289,8 @@ class TestLeaveApplication(unittest.TestCase):
def test_leaves_allowed(self):
+ frappe.db.sql("delete from `tabLeave Allocation`")
+ frappe.db.sql("delete from `tabLeave Ledger Entry`")
employee = get_employee()
leave_period = get_leave_period()
frappe.delete_doc_if_exists("Leave Type", "Test Leave Type", force=1)
@@ -301,7 +305,7 @@ class TestLeaveApplication(unittest.TestCase):
allocate_leaves(employee, leave_period, leave_type.name, 5)
leave_application = frappe.get_doc(dict(
- doctype = 'Leave Application',
+ doctype = 'Leave Application',
employee = employee.name,
leave_type = leave_type.name,
from_date = date,
@@ -310,15 +314,14 @@ class TestLeaveApplication(unittest.TestCase):
docstatus = 1,
status = "Approved"
))
-
- self.assertTrue(leave_application.insert())
+ leave_application.submit()
leave_application = frappe.get_doc(dict(
doctype = 'Leave Application',
employee = employee.name,
leave_type = leave_type.name,
from_date = add_days(date, 4),
- to_date = add_days(date, 7),
+ to_date = add_days(date, 8),
company = "_Test Company",
docstatus = 1,
status = "Approved"
@@ -458,22 +461,32 @@ class TestLeaveApplication(unittest.TestCase):
self.assertEqual(leave_application.docstatus, 1)
def test_creation_of_leave_ledger_entry_on_submit(self):
+ frappe.db.sql("delete from `tabLeave Allocation`")
+ employee = get_employee()
+
+ leave_type = create_leave_type(leave_type_name = 'Test Leave Type 1')
+ leave_type.save()
+
+ leave_allocation = create_leave_allocation(employee=employee.name, employee_name=employee.employee_name,
+ leave_type=leave_type.name)
+ leave_allocation.submit()
leave_application = frappe.get_doc(dict(
doctype = 'Leave Application',
employee = employee.name,
- leave_type = leave_type_1.name,
- from_date = nowdate(),
+ leave_type = leave_type.name,
+ from_date = add_days(nowdate(), 1),
to_date = add_days(nowdate(), 4),
company = "_Test Company",
docstatus = 1,
status = "Approved"
- )).submit()
+ ))
+ leave_application.submit()
leave_ledger_entry = frappe.get_all('Leave Ledger Entry', fields='*', filters=dict(transaction_name=leave_application.name))
self.assertEquals(leave_ledger_entry[0].employee, leave_application.employee)
self.assertEquals(leave_ledger_entry[0].leave_type, leave_application.leave_type)
- self.assertEquals(leave_ledger_entry[0].leaves, leave_application.new_leaves_allocated)
+ self.assertEquals(leave_ledger_entry[0].leaves, leave_application.total_leave_days * -1)
# check if leave ledger entry is deleted on cancellation
leave_application.cancel()
diff --git a/erpnext/hr/doctype/leave_encashment/leave_encashment.py b/erpnext/hr/doctype/leave_encashment/leave_encashment.py
index 4f4a8760cf..c59ce63c7c 100644
--- a/erpnext/hr/doctype/leave_encashment/leave_encashment.py
+++ b/erpnext/hr/doctype/leave_encashment/leave_encashment.py
@@ -84,6 +84,7 @@ class LeaveEncashment(Document):
args = frappe._dict(
leaves=self.encashable_days * -1,
from_date=self.encashment_date,
+ to_date=self.encashable_days,
is_carry_forward=0
)
create_leave_ledger_entry(self, args, submit)
\ No newline at end of file
From 45197965d7ab957ccd7b493478655cd213d72469 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Mon, 27 May 2019 03:26:48 +0530
Subject: [PATCH 042/484] fix: give cancellation permission to hr manager
---
erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.json | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.json b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.json
index ae36735570..ba33d75029 100644
--- a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.json
+++ b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.json
@@ -87,7 +87,7 @@
],
"in_create": 1,
"is_submittable": 1,
- "modified": "2019-05-23 19:22:09.028366",
+ "modified": "2019-05-27 03:25:47.805142",
"modified_by": "Administrator",
"module": "HR",
"name": "Leave Ledger Entry",
@@ -107,6 +107,7 @@
"write": 1
},
{
+ "cancel": 1,
"create": 1,
"delete": 1,
"email": 1,
From 24248f687b4067ce56bb13f94274170310683979 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Mon, 27 May 2019 10:58:42 +0530
Subject: [PATCH 043/484] patch: create entries for only missing transactions
---
.../v12_0/generate_leave_ledger_entries.py | 16 +++++++++++-----
1 file changed, 11 insertions(+), 5 deletions(-)
diff --git a/erpnext/patches/v12_0/generate_leave_ledger_entries.py b/erpnext/patches/v12_0/generate_leave_ledger_entries.py
index 9223bb2ebc..9c638abaff 100644
--- a/erpnext/patches/v12_0/generate_leave_ledger_entries.py
+++ b/erpnext/patches/v12_0/generate_leave_ledger_entries.py
@@ -7,7 +7,7 @@ import frappe
def execute():
""" Generates leave ledger entries for leave allocation/application/encashment
for last allocation """
- if frappe.db.exists("DocType","Leave Ledger Entry"):
+ if frappe.db.a_row_exists("Leave Ledger Entry"):
return
allocation_list = get_allocation_records()
@@ -20,7 +20,9 @@ def generate_allocation_ledger_entries(allocation_list):
from erpnext.hr.doctype.leave_allocation.leave_allocation import LeaveAllocation
for allocation in allocation_list:
- LeaveAllocation.create_leave_ledger_entry(allocation)
+ if not frappe.db.exists("Leave Ledger Entry", {'transaction_type': 'Leave Allocation',
+ 'transaction_name': allocation.name}):
+ LeaveAllocation.create_leave_ledger_entry(allocation)
def generate_application_leave_ledger_entries(allocation_list):
''' fix ledger entries for missing leave application transaction '''
@@ -29,7 +31,9 @@ def generate_application_leave_ledger_entries(allocation_list):
leave_applications = get_leaves_application_records(allocation_list)
for record in leave_applications:
- LeaveApplication.create_leave_ledger_entry(record)
+ if not frappe.db.exists("Leave Ledger Entry", {'transaction_type': 'Leave Application',
+ 'transaction_name': record.name}):
+ LeaveApplication.create_leave_ledger_entry(record)
def generate_encashment_leave_ledger_entries(allocation_list):
''' fix ledger entries for missing leave encashment transaction '''
@@ -38,7 +42,9 @@ def generate_encashment_leave_ledger_entries(allocation_list):
leave_encashments = get_leave_encashment_records(allocation_list)
for record in leave_encashments:
- LeaveEncashment.create_leave_ledger_entry(record)
+ if not frappe.db.exists("Leave Ledger Entry", {'transaction_type': 'Leave Encashment',
+ 'transaction_name': record.name}):
+ LeaveEncashment.create_leave_ledger_entry(record)
def get_allocation_records():
return frappe.db.sql("""
@@ -62,7 +68,7 @@ def get_leaves_application_records(allocation_list):
for allocation in allocation_list:
leave_applications.append(frappe.db.sql("""
SELECT
- name,
+ DISTINCT name,
employee,
leave_type,
total_leave_days,
From 71cdcb35930e37befd227fc6e0200041eb26aec1 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Mon, 27 May 2019 11:00:04 +0530
Subject: [PATCH 044/484] style: add a more descriptive method name
---
erpnext/hr/doctype/leave_application/leave_application.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/erpnext/hr/doctype/leave_application/leave_application.py b/erpnext/hr/doctype/leave_application/leave_application.py
index 2adf8fba71..8e8e47e510 100755
--- a/erpnext/hr/doctype/leave_application/leave_application.py
+++ b/erpnext/hr/doctype/leave_application/leave_application.py
@@ -354,7 +354,7 @@ class LeaveApplication(Document):
self.to_date, self.from_date)
if expiry_date:
- self.create_application_entry_for_expiry(expiry_date)
+ self.create_ledger_entry_for_intermediate_expiry(expiry_date, submit)
else:
args = dict(
leaves=self.total_leave_days * -1,
@@ -363,7 +363,7 @@ class LeaveApplication(Document):
)
create_leave_ledger_entry(self, args, submit)
- def create_application_entry_for_expiry(self, expiry_date):
+ def create_ledger_entry_for_intermediate_expiry(self, expiry_date, submit):
''' splits leave application into two ledger entries to consider expiry '''
args = dict(
from_date=self.from_date,
From 7fbaef5de34d14d4535813179f888336fd7b7076 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Mon, 27 May 2019 15:39:48 +0530
Subject: [PATCH 045/484] fix: expiry ledger creation
---
.../leave_application/leave_application.py | 29 ++++++++++---------
1 file changed, 15 insertions(+), 14 deletions(-)
diff --git a/erpnext/hr/doctype/leave_application/leave_application.py b/erpnext/hr/doctype/leave_application/leave_application.py
index 8e8e47e510..e5ee4e6a26 100755
--- a/erpnext/hr/doctype/leave_application/leave_application.py
+++ b/erpnext/hr/doctype/leave_application/leave_application.py
@@ -364,32 +364,31 @@ class LeaveApplication(Document):
create_leave_ledger_entry(self, args, submit)
def create_ledger_entry_for_intermediate_expiry(self, expiry_date, submit):
- ''' splits leave application into two ledger entries to consider expiry '''
+ ''' splits leave application into two ledger entries to consider expiry of allocation '''
args = dict(
from_date=self.from_date,
to_date=self.to_date,
- leaves=date_diff(expiry_date, self.from_date) * -1
+ leaves=(date_diff(expiry_date, self.from_date) + 1) * -1
)
create_leave_ledger_entry(self, args, submit)
+
start_date = add_days(expiry_date, 1)
args.update(dict(
from_date=start_date,
to_date=self.to_date,
- leaves=date_diff(self.to_date, start_date) * -1
+ leaves=date_diff(self.to_date, expiry_date) * -1
))
create_leave_ledger_entry(self, args, submit)
def get_allocation_expiry(employee, leave_type, to_date, from_date):
- return frappe.db.sql("""
- SELECT
- to_date
- FROM `tabLeave Ledger Entry`
- WHERE
- employee='%s'
- AND leave_type='%s'
- AND transaction_type='Leave Allocation'
- AND (to_date BETWEEN %s AND %s)
- """ %(employee, leave_type, from_date, to_date), as_dict=1)
+ expiry = frappe.get_all("Leave Ledger Entry",
+ filters={
+ 'employee': employee,
+ 'leave_type': leave_type,
+ 'transaction_type': 'Leave Allocation',
+ 'to_date': ['between', (from_date, to_date)]
+ },fields=['to_date'])
+ return expiry[0]['to_date'] if expiry else None
@frappe.whitelist()
def get_number_of_leave_days(employee, leave_type, from_date, to_date, half_day = None, half_day_date = None):
@@ -452,10 +451,12 @@ def get_remaining_leaves(allocation, leaves_taken, date, expiry):
if remaining_leaves > 0:
remaining_days = date_diff(end_date, date) + 1
remaining_leaves = min(remaining_days, remaining_leaves)
+
return remaining_leaves
if expiry:
remaining_leaves = _get_remaining_leaves(allocation.carry_forwarded_leaves, expiry)
+
return flt(allocation.new_leaves_allocated) + flt(remaining_leaves)
else:
return _get_remaining_leaves(allocation.total_leaves_allocated, allocation.to_date)
@@ -543,7 +544,7 @@ def get_leave_allocation_records(date, employee=None):
"total_leaves_allocated": d.total_leaves_allocated,
"carry_forward": d.carry_forward,
"carry_forwarded_leaves": d.carry_forwarded_leaves,
- "new_leaves": d.new_leaves_allocated,
+ "new_leaves_allocated": d.new_leaves_allocated,
"leave_type": d.leave_type
}))
return allocated_leaves
From 6f69bbe1d782bb710ddb80111458984a4ac35e55 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Mon, 27 May 2019 15:40:36 +0530
Subject: [PATCH 046/484] test: leave ledger balance
---
.../leave_allocation/test_leave_allocation.py | 1 -
.../leave_application/leave_application.py | 4 +-
.../test_leave_application.py | 70 ++++++++++++++++++-
.../leave_encashment/test_leave_encashment.py | 15 ++--
4 files changed, 79 insertions(+), 11 deletions(-)
diff --git a/erpnext/hr/doctype/leave_allocation/test_leave_allocation.py b/erpnext/hr/doctype/leave_allocation/test_leave_allocation.py
index 308f2245b9..dfae329da1 100644
--- a/erpnext/hr/doctype/leave_allocation/test_leave_allocation.py
+++ b/erpnext/hr/doctype/leave_allocation/test_leave_allocation.py
@@ -158,7 +158,6 @@ def create_leave_allocation(**args):
"from_date": args.from_date or nowdate(),
"new_leaves_allocated": args.new_leaves_created or 15,
"carry_forward": args.carry_forward or 0,
- "carry_forwarded_leaves": args.carry_forwarded_leaves or 0,
"to_date": args.to_date or add_months(nowdate(), 12)
})
return leave_allocation
diff --git a/erpnext/hr/doctype/leave_application/leave_application.py b/erpnext/hr/doctype/leave_application/leave_application.py
index e5ee4e6a26..f3bb9f7eb9 100755
--- a/erpnext/hr/doctype/leave_application/leave_application.py
+++ b/erpnext/hr/doctype/leave_application/leave_application.py
@@ -354,7 +354,7 @@ class LeaveApplication(Document):
self.to_date, self.from_date)
if expiry_date:
- self.create_ledger_entry_for_intermediate_expiry(expiry_date, submit)
+ self.create_ledger_entry_for_intermediate_allocation_expiry(expiry_date, submit)
else:
args = dict(
leaves=self.total_leave_days * -1,
@@ -363,7 +363,7 @@ class LeaveApplication(Document):
)
create_leave_ledger_entry(self, args, submit)
- def create_ledger_entry_for_intermediate_expiry(self, expiry_date, submit):
+ def create_ledger_entry_for_intermediate_allocation_expiry(self, expiry_date, submit):
''' splits leave application into two ledger entries to consider expiry of allocation '''
args = dict(
from_date=self.from_date,
diff --git a/erpnext/hr/doctype/leave_application/test_leave_application.py b/erpnext/hr/doctype/leave_application/test_leave_application.py
index 4dea413dc3..f5f4fa55f5 100644
--- a/erpnext/hr/doctype/leave_application/test_leave_application.py
+++ b/erpnext/hr/doctype/leave_application/test_leave_application.py
@@ -7,7 +7,7 @@ import unittest
from erpnext.hr.doctype.leave_application.leave_application import LeaveDayBlockedError, OverlapError, NotAnOptionalHoliday, get_leave_balance_on
from frappe.permissions import clear_user_permissions_for_doctype
-from frappe.utils import add_days, nowdate, now_datetime, getdate
+from frappe.utils import add_days, nowdate, now_datetime, getdate, add_months
from erpnext.hr.doctype.leave_type.test_leave_type import create_leave_type
from erpnext.hr.doctype.leave_allocation.test_leave_allocation import create_leave_allocation
@@ -287,7 +287,6 @@ class TestLeaveApplication(unittest.TestCase):
# check leave balance is reduced
self.assertEqual(get_leave_balance_on(employee.name, leave_type, today), 9)
-
def test_leaves_allowed(self):
frappe.db.sql("delete from `tabLeave Allocation`")
frappe.db.sql("delete from `tabLeave Ledger Entry`")
@@ -404,6 +403,20 @@ class TestLeaveApplication(unittest.TestCase):
self.assertRaises(frappe.ValidationError, leave_application.insert)
+ def test_leave_balance_near_allocaton_expiry(self):
+ frappe.db.sql("delete from `tabLeave Allocation`")
+ frappe.db.sql("delete from `tabLeave Ledger Entry`")
+ employee = get_employee()
+ leave_type = create_leave_type(
+ leave_type_name="_Test_CF_leave_expiry",
+ is_carry_forward=1,
+ carry_forward_leave_expiry=90)
+ leave_type.submit()
+
+ create_carry_forwarded_allocation(employee, leave_type)
+
+ self.assertEqual(get_leave_balance_on(employee.name, leave_type.name, nowdate(), add_days(nowdate(), 8)), 21)
+
def test_earned_leave(self):
leave_period = get_leave_period()
employee = get_employee()
@@ -492,6 +505,59 @@ class TestLeaveApplication(unittest.TestCase):
leave_application.cancel()
self.assertFalse(frappe.db.exists("Leave Ledger Entry", {'transaction_name':leave_application.name}))
+ def test_ledger_entry_creation_on_intermediate_allocation_expiry(self):
+ frappe.db.sql("delete from `tabLeave Allocation`")
+ frappe.db.sql("delete from `tabLeave Ledger Entry`")
+ employee = get_employee()
+ leave_type = create_leave_type(
+ leave_type_name="_Test_CF_leave_expiry",
+ is_carry_forward=1,
+ carry_forward_leave_expiry=90)
+ leave_type.submit()
+
+ create_carry_forwarded_allocation(employee, leave_type)
+
+ leave_application = frappe.get_doc(dict(
+ doctype = 'Leave Application',
+ employee = employee.name,
+ leave_type = leave_type.name,
+ from_date = add_days(nowdate(), -3),
+ to_date = add_days(nowdate(), 7),
+ company = "_Test Company",
+ docstatus = 1,
+ status = "Approved"
+ ))
+ leave_application.submit()
+
+ leave_ledger_entry = frappe.get_all('Leave Ledger Entry', '*', filters=dict(transaction_name=leave_application.name))
+
+ self.assertEquals(len(leave_ledger_entry), 2)
+ self.assertEquals(leave_ledger_entry[0].employee, leave_application.employee)
+ self.assertEquals(leave_ledger_entry[0].leave_type, leave_application.leave_type)
+ self.assertEquals(leave_ledger_entry[0].leaves, -9)
+ self.assertEquals(leave_ledger_entry[1].leaves, -2)
+
+def create_carry_forwarded_allocation(employee, leave_type):
+
+ # initial leave allocation
+ leave_allocation = create_leave_allocation(
+ leave_type="_Test_CF_leave_expiry",
+ employee=employee.name,
+ employee_name=employee.employee_name,
+ from_date=add_months(nowdate(), -24),
+ to_date=add_months(nowdate(), -12),
+ carry_forward=1)
+ leave_allocation.submit()
+
+ leave_allocation = create_leave_allocation(
+ leave_type="_Test_CF_leave_expiry",
+ employee=employee.name,
+ employee_name=employee.employee_name,
+ from_date=add_days(nowdate(), -85),
+ to_date=add_days(nowdate(), 100),
+ carry_forward=1)
+ leave_allocation.submit()
+
def make_allocation_record(employee=None, leave_type=None):
frappe.db.sql("delete from `tabLeave Allocation`")
diff --git a/erpnext/hr/doctype/leave_encashment/test_leave_encashment.py b/erpnext/hr/doctype/leave_encashment/test_leave_encashment.py
index cfed780eb7..7d4fb285d8 100644
--- a/erpnext/hr/doctype/leave_encashment/test_leave_encashment.py
+++ b/erpnext/hr/doctype/leave_encashment/test_leave_encashment.py
@@ -17,6 +17,7 @@ class TestLeaveEncashment(unittest.TestCase):
def setUp(self):
frappe.db.sql('''delete from `tabLeave Period`''')
frappe.db.sql('''delete from `tabLeave Allocation`''')
+ frappe.db.sql('''delete from `tabAdditional Salary`''')
# create the leave policy
leave_policy = create_leave_policy(
@@ -26,7 +27,9 @@ class TestLeaveEncashment(unittest.TestCase):
# create employee, salary structure and assignment
self.employee = make_employee("test_employee_encashment@example.com")
- frappe.db.set_value("Employee", "test_employee_encashment@example.com", "leave_policy", leave_policy.name)
+
+ frappe.db.set_value("Employee", self.employee, "leave_policy", leave_policy.name)
+
salary_structure = make_salary_structure("Salary Structure for Encashment", "Monthly", self.employee,
other_details={"leave_encashment_amount_per_day": 50})
@@ -55,11 +58,11 @@ class TestLeaveEncashment(unittest.TestCase):
def test_creation_of_leave_ledger_entry_on_submit(self):
frappe.db.sql('''delete from `tabLeave Encashment`''')
leave_encashment = frappe.get_doc(dict(
- doctype = 'Leave Encashment',
- employee = self.employee,
- leave_type = "_Test Leave Type Encashment",
- leave_period = self.leave_period.name,
- payroll_date = today()
+ doctype='Leave Encashment',
+ employee=self.employee,
+ leave_type="_Test Leave Type Encashment",
+ leave_period=self.leave_period.name,
+ payroll_date=today()
)).insert()
leave_encashment.submit()
From 61bb236cfaf234fadd69cce768c8e6915de0156e Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Mon, 27 May 2019 19:36:40 +0530
Subject: [PATCH 047/484] test: delete ledger entry after each test to maintain
balance
---
.../doctype/leave_encashment/test_leave_encashment.py | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/erpnext/hr/doctype/leave_encashment/test_leave_encashment.py b/erpnext/hr/doctype/leave_encashment/test_leave_encashment.py
index 7d4fb285d8..2daeffcffe 100644
--- a/erpnext/hr/doctype/leave_encashment/test_leave_encashment.py
+++ b/erpnext/hr/doctype/leave_encashment/test_leave_encashment.py
@@ -17,6 +17,7 @@ class TestLeaveEncashment(unittest.TestCase):
def setUp(self):
frappe.db.sql('''delete from `tabLeave Period`''')
frappe.db.sql('''delete from `tabLeave Allocation`''')
+ frappe.db.sql('''delete from `tabLeave Ledger Entry`''')
frappe.db.sql('''delete from `tabAdditional Salary`''')
# create the leave policy
@@ -41,11 +42,11 @@ class TestLeaveEncashment(unittest.TestCase):
def test_leave_balance_value_and_amount(self):
frappe.db.sql('''delete from `tabLeave Encashment`''')
leave_encashment = frappe.get_doc(dict(
- doctype = 'Leave Encashment',
- employee = self.employee,
- leave_type = "_Test Leave Type Encashment",
- leave_period = self.leave_period.name,
- payroll_date = today()
+ doctype='Leave Encashment',
+ employee=self.employee,
+ leave_type="_Test Leave Type Encashment",
+ leave_period=self.leave_period.name,
+ payroll_date=today()
)).insert()
self.assertEqual(leave_encashment.leave_balance, 10)
From c6d6adcbf3889a642ff1ed7deb955e5fd0bda04f Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Tue, 28 May 2019 09:44:38 +0530
Subject: [PATCH 048/484] fix: ledger entry creation for encashment
---
erpnext/hr/doctype/leave_encashment/leave_encashment.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/hr/doctype/leave_encashment/leave_encashment.py b/erpnext/hr/doctype/leave_encashment/leave_encashment.py
index c59ce63c7c..70cd5780c8 100644
--- a/erpnext/hr/doctype/leave_encashment/leave_encashment.py
+++ b/erpnext/hr/doctype/leave_encashment/leave_encashment.py
@@ -84,7 +84,7 @@ class LeaveEncashment(Document):
args = frappe._dict(
leaves=self.encashable_days * -1,
from_date=self.encashment_date,
- to_date=self.encashable_days,
+ to_date=self.encashment_date,
is_carry_forward=0
)
create_leave_ledger_entry(self, args, submit)
\ No newline at end of file
From 9d6151d20047bfa54b6ffa96c14acedc25b74146 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Tue, 28 May 2019 11:45:51 +0530
Subject: [PATCH 049/484] patch: add reload doc for leave ledger entry
---
erpnext/patches/v12_0/generate_leave_ledger_entries.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/erpnext/patches/v12_0/generate_leave_ledger_entries.py b/erpnext/patches/v12_0/generate_leave_ledger_entries.py
index 9c638abaff..b8e82ef416 100644
--- a/erpnext/patches/v12_0/generate_leave_ledger_entries.py
+++ b/erpnext/patches/v12_0/generate_leave_ledger_entries.py
@@ -7,6 +7,7 @@ import frappe
def execute():
""" Generates leave ledger entries for leave allocation/application/encashment
for last allocation """
+ frappe.reload_doc("HR","doctype", "Leave Ledger Entry")
if frappe.db.a_row_exists("Leave Ledger Entry"):
return
From ae4228aed4d5097a35ec65d585238c8320784121 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Tue, 28 May 2019 13:24:15 +0530
Subject: [PATCH 050/484] fix: fetch queries
---
.../v12_0/generate_leave_ledger_entries.py | 44 ++++++++++++-------
1 file changed, 27 insertions(+), 17 deletions(-)
diff --git a/erpnext/patches/v12_0/generate_leave_ledger_entries.py b/erpnext/patches/v12_0/generate_leave_ledger_entries.py
index b8e82ef416..8b1ca8c7ad 100644
--- a/erpnext/patches/v12_0/generate_leave_ledger_entries.py
+++ b/erpnext/patches/v12_0/generate_leave_ledger_entries.py
@@ -49,17 +49,26 @@ def generate_encashment_leave_ledger_entries(allocation_list):
def get_allocation_records():
return frappe.db.sql("""
+ WITH allocation_values AS (
+ SELECT
+ DISTINCT name,
+ employee,
+ leave_type,
+ new_leaves_allocated,
+ carry_forwarded_leaves,
+ from_date,
+ to_date,
+ carry_forward,
+ RANK() OVER(
+ PARTITION BY employee, leave_type
+ ORDER BY to_date DESC
+ ) as allocation
+ FROM `tabLeave Allocation`
+ )
SELECT
- DISTINCT name,
- employee,
- leave_type,
- new_leaves_allocated,
- carry_forwarded_leaves,
- from_date,
- to_date,
- carry_forward,
- RANK() OVER(PARTITION BY employee, leave_type ORDER BY to_date DESC) as allocation
- FROM `tabLeave Allocation`
+ *
+ FROM
+ `allocation_values`
WHERE
allocation=1
""", as_dict=1)
@@ -67,7 +76,7 @@ def get_allocation_records():
def get_leaves_application_records(allocation_list):
leave_applications = []
for allocation in allocation_list:
- leave_applications.append(frappe.db.sql("""
+ leave_applications += frappe.db.sql("""
SELECT
DISTINCT name,
employee,
@@ -78,15 +87,15 @@ def get_leaves_application_records(allocation_list):
FROM `tabLeave Application`
WHERE
from_date >= %s
- leave_type = %s
- employee = %s
- """, (allocation.from_date, allocation.leave_type, allocation.employee)))
+ AND leave_type = %s
+ AND employee = %s
+ """, (allocation.from_date, allocation.leave_type, allocation.employee))
return leave_applications
def get_leave_encashment_records(allocation_list):
leave_encashments = []
for allocation in allocation_list:
- leave_encashments.append(frappe.db.sql("""
+ leave_encashments += frappe.db.sql("""
SELECT
DISTINCT name,
employee,
@@ -97,6 +106,7 @@ def get_leave_encashment_records(allocation_list):
FROM `tabLeave Encashment`
WHERE
leave_type = %s
- employee = %s
- """, (allocation.leave_type, allocation.employee)))
+ AND employee = %s
+ AND encashment_date >= %s
+ """, (allocation.leave_type, allocation.employee, allocation.from_date))
return leave_encashments
\ No newline at end of file
From 8f47bffa0ef85040621b57a2a6defbfb6031e403 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Wed, 29 May 2019 15:54:14 +0530
Subject: [PATCH 051/484] fix: create an instance
---
.../v12_0/generate_leave_ledger_entries.py | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/erpnext/patches/v12_0/generate_leave_ledger_entries.py b/erpnext/patches/v12_0/generate_leave_ledger_entries.py
index 8b1ca8c7ad..3cdfa53f88 100644
--- a/erpnext/patches/v12_0/generate_leave_ledger_entries.py
+++ b/erpnext/patches/v12_0/generate_leave_ledger_entries.py
@@ -21,9 +21,9 @@ def generate_allocation_ledger_entries(allocation_list):
from erpnext.hr.doctype.leave_allocation.leave_allocation import LeaveAllocation
for allocation in allocation_list:
- if not frappe.db.exists("Leave Ledger Entry", {'transaction_type': 'Leave Allocation',
- 'transaction_name': allocation.name}):
- LeaveAllocation.create_leave_ledger_entry(allocation)
+ if not frappe.db.exists("Leave Ledger Entry", {'transaction_type': 'Leave Allocation', 'transaction_name': allocation.name}):
+ leave_allocation = LeaveAllocation(allocation)
+ leave_allocation.create_leave_ledger_entry()
def generate_application_leave_ledger_entries(allocation_list):
''' fix ledger entries for missing leave application transaction '''
@@ -32,9 +32,9 @@ def generate_application_leave_ledger_entries(allocation_list):
leave_applications = get_leaves_application_records(allocation_list)
for record in leave_applications:
- if not frappe.db.exists("Leave Ledger Entry", {'transaction_type': 'Leave Application',
- 'transaction_name': record.name}):
- LeaveApplication.create_leave_ledger_entry(record)
+ if not frappe.db.exists("Leave Ledger Entry", {'transaction_type': 'Leave Application', 'transaction_name': record.name}):
+ leave_application = LeaveApplication(record)
+ leave_application.create_leave_ledger_entry()
def generate_encashment_leave_ledger_entries(allocation_list):
''' fix ledger entries for missing leave encashment transaction '''
@@ -43,9 +43,9 @@ def generate_encashment_leave_ledger_entries(allocation_list):
leave_encashments = get_leave_encashment_records(allocation_list)
for record in leave_encashments:
- if not frappe.db.exists("Leave Ledger Entry", {'transaction_type': 'Leave Encashment',
- 'transaction_name': record.name}):
- LeaveEncashment.create_leave_ledger_entry(record)
+ if not frappe.db.exists("Leave Ledger Entry", {'transaction_type': 'Leave Encashment', 'transaction_name': record.name}):
+ leave_encashment = LeaveEncashment(record)
+ leave_encashment.create_leave_ledger_entry()
def get_allocation_records():
return frappe.db.sql("""
From 7cc6a67c186bd492c3af10e715acd3346f048e0b Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Wed, 29 May 2019 15:59:20 +0530
Subject: [PATCH 052/484] add department filter to employee leave balance
---
.../leave_application/leave_application.py | 4 +++-
.../leave_ledger_entry.json | 6 +++---
.../employee_leave_balance.js | 7 +++++++
.../employee_leave_balance.py | 21 +++++++++++++------
4 files changed, 28 insertions(+), 10 deletions(-)
diff --git a/erpnext/hr/doctype/leave_application/leave_application.py b/erpnext/hr/doctype/leave_application/leave_application.py
index f3bb9f7eb9..9eb0b91c7c 100755
--- a/erpnext/hr/doctype/leave_application/leave_application.py
+++ b/erpnext/hr/doctype/leave_application/leave_application.py
@@ -411,7 +411,8 @@ def get_leave_details(employee, date):
leave_allocation = {}
for d in allocation_records:
allocation = allocation_records.get(d, frappe._dict())
- remaining_leaves = get_leave_balance_on(employee, d, date)
+ remaining_leaves = get_leave_balance_on(employee, d, date, to_date = allocation.to_date,
+ consider_all_leaves_in_the_allocation_period=True)
date = allocation.to_date
leaves_taken = get_leaves_for_period(employee, d, allocation.from_date, date, status="Approved")
leaves_pending = get_leaves_for_period(employee, d, allocation.from_date, date, status="Open")
@@ -441,6 +442,7 @@ def get_leave_balance_on(employee, leave_type, from_date, to_date=nowdate(), all
expiry = get_allocation_expiry(employee, leave_type, to_date, from_date)
leaves_taken = get_leaves_taken(employee, leave_type, allocation.from_date, end_date)
+
return get_remaining_leaves(allocation, leaves_taken, from_date, expiry)
def get_remaining_leaves(allocation, leaves_taken, date, expiry):
diff --git a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.json b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.json
index ba33d75029..3af013d12b 100644
--- a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.json
+++ b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.json
@@ -65,21 +65,21 @@
{
"fieldname": "from_date",
"fieldtype": "Date",
- "in_list_view": 1,
"label": "From Date"
},
{
"fieldname": "to_date",
"fieldtype": "Date",
- "in_list_view": 1,
"label": "To Date"
},
{
+ "default": "0",
"fieldname": "is_carry_forward",
"fieldtype": "Check",
"label": "Is Carry Forward"
},
{
+ "default": "0",
"fieldname": "is_expired",
"fieldtype": "Check",
"label": "Is Expired"
@@ -87,7 +87,7 @@
],
"in_create": 1,
"is_submittable": 1,
- "modified": "2019-05-27 03:25:47.805142",
+ "modified": "2019-05-29 15:58:29.656351",
"modified_by": "Administrator",
"module": "HR",
"name": "Leave Ledger Entry",
diff --git a/erpnext/hr/report/employee_leave_balance/employee_leave_balance.js b/erpnext/hr/report/employee_leave_balance/employee_leave_balance.js
index 59c25608c2..ecb3e3061f 100644
--- a/erpnext/hr/report/employee_leave_balance/employee_leave_balance.js
+++ b/erpnext/hr/report/employee_leave_balance/employee_leave_balance.js
@@ -24,6 +24,13 @@ frappe.query_reports["Employee Leave Balance"] = {
"options": "Company",
"reqd": 1,
"default": frappe.defaults.get_user_default("Company")
+ },
+ {
+ "fieldname":"department",
+ "label": __("Department"),
+ "fieldtype": "Link",
+ "options": "Department",
+ "reqd": 1,
}
]
}
diff --git a/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py b/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py
index 95cb30b791..02be799501 100644
--- a/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py
+++ b/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py
@@ -4,6 +4,7 @@
from __future__ import unicode_literals
import frappe
from frappe import _
+from frappe.utils import flt
from erpnext.hr.doctype.leave_application.leave_application \
import get_leave_allocation_records, get_leave_balance_on, get_approved_leaves_for_period, get_total_allocated_leaves
@@ -30,14 +31,23 @@ def get_columns(leave_types):
return columns
+def get_conditions(filters):
+ filters = {
+ "status": "Active",
+ "company": filters.company,
+ }
+ if filters.get("Department"):
+ filters.update(filters.get("Department"))
+
+ return filters
+
def get_data(filters, leave_types):
user = frappe.session.user
- allocation_records_based_on_to_date = get_leave_allocation_records(filters.to_date)
- allocation_records_based_on_from_date = get_leave_allocation_records(filters.from_date)
+ conditions = get_conditions(filters)
active_employees = frappe.get_all("Employee",
- filters = { "status": "Active", "company": filters.company},
- fields = ["name", "employee_name", "department", "user_id"])
+ filters=conditions,
+ fields=["name", "employee_name", "department", "user_id"])
data = []
for employee in active_employees:
@@ -54,8 +64,7 @@ def get_data(filters, leave_types):
opening = get_total_allocated_leaves(employee.name, leave_type, filters.to_date)
# closing balance
- closing = get_leave_balance_on(employee.name, leave_type, filters.to_date,
- allocation_records_based_on_to_date.get(employee.name, frappe._dict()))
+ closing = flt(opening) - flt(leaves_taken)
row += [opening, leaves_taken, closing]
From ded33a7e2e18c393783889984aa2cfd5c7e3ee02 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Wed, 29 May 2019 19:12:19 +0530
Subject: [PATCH 053/484] fix: ledger entries creation
---
.../doctype/leave_allocation/leave_allocation.py | 4 ++--
.../doctype/leave_application/leave_application.py | 14 ++++++++------
.../patches/v12_0/generate_leave_ledger_entries.py | 7 +++++--
3 files changed, 15 insertions(+), 10 deletions(-)
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.py b/erpnext/hr/doctype/leave_allocation/leave_allocation.py
index 6fe8fdff24..2a1301d2fd 100755
--- a/erpnext/hr/doctype/leave_allocation/leave_allocation.py
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.py
@@ -136,8 +136,8 @@ class LeaveAllocation(Document):
if flt(leaves) > 0:
args = dict(
leaves=leaves * -1,
- from_date=self.to_date,
- to_date=self.to_date,
+ from_date=self.from_date,
+ to_date=self.from_date,
is_carry_forward=0,
is_expired=1
)
diff --git a/erpnext/hr/doctype/leave_application/leave_application.py b/erpnext/hr/doctype/leave_application/leave_application.py
index 9eb0b91c7c..b1c666ca83 100755
--- a/erpnext/hr/doctype/leave_application/leave_application.py
+++ b/erpnext/hr/doctype/leave_application/leave_application.py
@@ -431,22 +431,24 @@ def get_leave_details(employee, date):
return ret
@frappe.whitelist()
-def get_leave_balance_on(employee, leave_type, from_date, to_date=nowdate(), allocation_records=None, docname=None,
+def get_leave_balance_on(employee, leave_type, date, to_date=nowdate(), allocation_records=None, docname=None,
consider_all_leaves_in_the_allocation_period=False):
+ ''' Returns leave balance till date and fetches expiry date based on to_date
+ to calculate minimum remaining leave balance '''
if allocation_records == None:
- allocation_records = get_leave_allocation_records(from_date, employee).get(employee, frappe._dict())
+ allocation_records = get_leave_allocation_records(date, employee).get(employee, frappe._dict())
allocation = allocation_records.get(leave_type, frappe._dict())
- end_date = allocation.to_date if consider_all_leaves_in_the_allocation_period else from_date
- expiry = get_allocation_expiry(employee, leave_type, to_date, from_date)
+ end_date = allocation.to_date if consider_all_leaves_in_the_allocation_period else date
+ expiry = get_allocation_expiry(employee, leave_type, to_date, date)
leaves_taken = get_leaves_taken(employee, leave_type, allocation.from_date, end_date)
- return get_remaining_leaves(allocation, leaves_taken, from_date, expiry)
+ return get_remaining_leaves(allocation, leaves_taken, date, expiry)
def get_remaining_leaves(allocation, leaves_taken, date, expiry):
- ''' Returns leaves remaining after comparing with remaining days for allocation expiry '''
+ ''' Returns minimum leaves remaining after comparing with remaining days for allocation expiry '''
def _get_remaining_leaves(allocated_leaves, end_date):
remaining_leaves = flt(allocated_leaves) + flt(leaves_taken)
diff --git a/erpnext/patches/v12_0/generate_leave_ledger_entries.py b/erpnext/patches/v12_0/generate_leave_ledger_entries.py
index 3cdfa53f88..31cbcc6181 100644
--- a/erpnext/patches/v12_0/generate_leave_ledger_entries.py
+++ b/erpnext/patches/v12_0/generate_leave_ledger_entries.py
@@ -22,6 +22,7 @@ def generate_allocation_ledger_entries(allocation_list):
for allocation in allocation_list:
if not frappe.db.exists("Leave Ledger Entry", {'transaction_type': 'Leave Allocation', 'transaction_name': allocation.name}):
+ allocation.update(dict(doctype="Leave Allocation"))
leave_allocation = LeaveAllocation(allocation)
leave_allocation.create_leave_ledger_entry()
@@ -33,6 +34,7 @@ def generate_application_leave_ledger_entries(allocation_list):
for record in leave_applications:
if not frappe.db.exists("Leave Ledger Entry", {'transaction_type': 'Leave Application', 'transaction_name': record.name}):
+ record.update(dict(doctype="Leave Application"))
leave_application = LeaveApplication(record)
leave_application.create_leave_ledger_entry()
@@ -44,6 +46,7 @@ def generate_encashment_leave_ledger_entries(allocation_list):
for record in leave_encashments:
if not frappe.db.exists("Leave Ledger Entry", {'transaction_type': 'Leave Encashment', 'transaction_name': record.name}):
+ record.update(dict(doctype="Leave Encashment"))
leave_encashment = LeaveEncashment(record)
leave_encashment.create_leave_ledger_entry()
@@ -89,7 +92,7 @@ def get_leaves_application_records(allocation_list):
from_date >= %s
AND leave_type = %s
AND employee = %s
- """, (allocation.from_date, allocation.leave_type, allocation.employee))
+ """, (allocation.from_date, allocation.leave_type, allocation.employee), as_dict=1)
return leave_applications
def get_leave_encashment_records(allocation_list):
@@ -108,5 +111,5 @@ def get_leave_encashment_records(allocation_list):
leave_type = %s
AND employee = %s
AND encashment_date >= %s
- """, (allocation.leave_type, allocation.employee, allocation.from_date))
+ """, (allocation.leave_type, allocation.employee, allocation.from_date), as_dict=1)
return leave_encashments
\ No newline at end of file
From aafb5cb6f684ca28921d2a6de934a5f6fd4f3162 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Thu, 30 May 2019 13:13:14 +0530
Subject: [PATCH 054/484] fix: ignore expired non-carry forwarded allocation on
calculating leaves taken
---
.../hr/doctype/leave_application/leave_application.py | 10 +++++++---
.../leave_application/test_leave_application.py | 1 -
erpnext/patches/v12_0/generate_leave_ledger_entries.py | 3 +--
3 files changed, 8 insertions(+), 6 deletions(-)
diff --git a/erpnext/hr/doctype/leave_application/leave_application.py b/erpnext/hr/doctype/leave_application/leave_application.py
index b1c666ca83..fd13436d8f 100755
--- a/erpnext/hr/doctype/leave_application/leave_application.py
+++ b/erpnext/hr/doctype/leave_application/leave_application.py
@@ -431,7 +431,7 @@ def get_leave_details(employee, date):
return ret
@frappe.whitelist()
-def get_leave_balance_on(employee, leave_type, date, to_date=nowdate(), allocation_records=None, docname=None,
+def get_leave_balance_on(employee, leave_type, date, to_date=nowdate(), allocation_records=None,
consider_all_leaves_in_the_allocation_period=False):
''' Returns leave balance till date and fetches expiry date based on to_date
to calculate minimum remaining leave balance '''
@@ -467,13 +467,17 @@ def get_remaining_leaves(allocation, leaves_taken, date, expiry):
def get_leaves_taken(employee, leave_type, from_date, to_date):
''' Returns leaves taken based on leave application/encashment '''
- return frappe.db.get_value("Leave Ledger Entry", filters={
+ leaves = frappe.db.get_all("Leave Ledger Entry", filters={
'Employee':employee,
'leave_type':leave_type,
'leaves': ("<", 0),
'to_date':("<=", to_date),
'from_date': (">=", from_date)},
- fieldname=['SUM(leaves)'])
+ or_filters={
+ 'is_expired': 0,
+ 'is_carry_forward': 1
+ }, fields=['SUM(leaves) as leaves'])
+ return leaves[0]['leaves'] if leaves else None
def get_total_allocated_leaves(employee, leave_type, date):
filters= {
diff --git a/erpnext/hr/doctype/leave_application/test_leave_application.py b/erpnext/hr/doctype/leave_application/test_leave_application.py
index f5f4fa55f5..30dcafafc7 100644
--- a/erpnext/hr/doctype/leave_application/test_leave_application.py
+++ b/erpnext/hr/doctype/leave_application/test_leave_application.py
@@ -538,7 +538,6 @@ class TestLeaveApplication(unittest.TestCase):
self.assertEquals(leave_ledger_entry[1].leaves, -2)
def create_carry_forwarded_allocation(employee, leave_type):
-
# initial leave allocation
leave_allocation = create_leave_allocation(
leave_type="_Test_CF_leave_expiry",
diff --git a/erpnext/patches/v12_0/generate_leave_ledger_entries.py b/erpnext/patches/v12_0/generate_leave_ledger_entries.py
index 31cbcc6181..dff749fce7 100644
--- a/erpnext/patches/v12_0/generate_leave_ledger_entries.py
+++ b/erpnext/patches/v12_0/generate_leave_ledger_entries.py
@@ -104,8 +104,7 @@ def get_leave_encashment_records(allocation_list):
employee,
leave_type,
encashable_days,
- from_date,
- to_date
+ encashment_date
FROM `tabLeave Encashment`
WHERE
leave_type = %s
From 2124d9884ba6bbf22e88111a229e053001832cb3 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Thu, 30 May 2019 13:21:34 +0530
Subject: [PATCH 055/484] fix: pass positional arguments on creation of leave
application
---
erpnext/hr/doctype/leave_application/leave_application.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/hr/doctype/leave_application/leave_application.js b/erpnext/hr/doctype/leave_application/leave_application.js
index 0b0a69f7a1..11146abce2 100755
--- a/erpnext/hr/doctype/leave_application/leave_application.js
+++ b/erpnext/hr/doctype/leave_application/leave_application.js
@@ -143,7 +143,7 @@ frappe.ui.form.on("Leave Application", {
method: "erpnext.hr.doctype.leave_application.leave_application.get_leave_balance_on",
args: {
employee: frm.doc.employee,
- from_date: frm.doc.from_date,
+ date: frm.doc.from_date,
to_date: frm.doc.to_date,
leave_type: frm.doc.leave_type,
consider_all_leaves_in_the_allocation_period: true
From 91e62f575e51fe21058ea296adc32ddbb785faa0 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Thu, 30 May 2019 13:38:35 +0530
Subject: [PATCH 056/484] fix: department filters in employee leave balance
---
.../employee_leave_balance/employee_leave_balance.js | 1 -
.../employee_leave_balance/employee_leave_balance.py | 11 ++++++-----
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/erpnext/hr/report/employee_leave_balance/employee_leave_balance.js b/erpnext/hr/report/employee_leave_balance/employee_leave_balance.js
index ecb3e3061f..68302f6ee4 100644
--- a/erpnext/hr/report/employee_leave_balance/employee_leave_balance.js
+++ b/erpnext/hr/report/employee_leave_balance/employee_leave_balance.js
@@ -30,7 +30,6 @@ frappe.query_reports["Employee Leave Balance"] = {
"label": __("Department"),
"fieldtype": "Link",
"options": "Department",
- "reqd": 1,
}
]
}
diff --git a/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py b/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py
index 02be799501..e65220ae25 100644
--- a/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py
+++ b/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py
@@ -32,14 +32,15 @@ def get_columns(leave_types):
return columns
def get_conditions(filters):
- filters = {
+ conditions = {
"status": "Active",
"company": filters.company,
}
- if filters.get("Department"):
- filters.update(filters.get("Department"))
-
- return filters
+ if filters.get("department"):
+ conditions.update({
+ "department": filters.get("department")
+ })
+ return conditions
def get_data(filters, leave_types):
user = frappe.session.user
From 95e5d812fef9ff2a03a40fa443f0007e95797582 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Thu, 30 May 2019 22:22:15 +0530
Subject: [PATCH 057/484] fix: UX changes
---
.../leave_application/leave_application.json | 197 +++----
.../leave_ledger_entry.json | 12 +-
.../hr/doctype/leave_period/leave_period.json | 538 +++++++++---------
erpnext/hr/doctype/leave_type/leave_type.json | 5 +-
.../v12_0/generate_leave_ledger_entries.py | 1 +
5 files changed, 381 insertions(+), 372 deletions(-)
diff --git a/erpnext/hr/doctype/leave_application/leave_application.json b/erpnext/hr/doctype/leave_application/leave_application.json
index d7b2c9f875..812494c1c0 100644
--- a/erpnext/hr/doctype/leave_application/leave_application.json
+++ b/erpnext/hr/doctype/leave_application/leave_application.json
@@ -485,7 +485,7 @@
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
- "reqd": 0,
+ "reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
@@ -507,6 +507,7 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
+ "label": "Approval",
"length": 0,
"no_copy": 0,
"permlevel": 0,
@@ -652,39 +653,6 @@
"translatable": 0,
"unique": 0
},
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "salary_slip",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Salary Slip",
- "length": 0,
- "no_copy": 0,
- "options": "Salary Slip",
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
@@ -748,6 +716,38 @@
"translatable": 0,
"unique": 0
},
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Company",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Company",
+ "permlevel": 0,
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 1,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
@@ -780,38 +780,6 @@
"translatable": 0,
"unique": 0
},
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "color",
- "fieldtype": "Color",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Color",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
@@ -843,37 +811,38 @@
"unique": 0
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "company",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Company",
- "length": 0,
- "no_copy": 0,
- "options": "Company",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 1,
- "report_hide": 0,
- "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,
+ "columns": 0,
+ "fieldname": "salary_slip",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Salary Slip",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Salary Slip",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 1,
+ "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,
+ "translatable": 0,
+ "unique": 0
+ },
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
@@ -906,6 +875,38 @@
"translatable": 0,
"unique": 0
},
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 1,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "color",
+ "fieldtype": "Color",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Color",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 1,
+ "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,
+ "translatable": 0,
+ "unique": 0
+ },
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
@@ -950,7 +951,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 3,
- "modified": "2019-01-30 11:28:14.745572",
+ "modified": "2019-05-30 11:28:14.745572",
"modified_by": "Administrator",
"module": "HR",
"name": "Leave Application",
diff --git a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.json b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.json
index 3af013d12b..20b64f81aa 100644
--- a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.json
+++ b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.json
@@ -9,6 +9,7 @@
"transaction_type",
"transaction_name",
"leaves",
+ "column_break_7",
"from_date",
"to_date",
"is_carry_forward",
@@ -20,6 +21,7 @@
"fieldname": "employee",
"fieldtype": "Link",
"in_list_view": 1,
+ "in_standard_filter": 1,
"label": "Employee",
"options": "Employee"
},
@@ -32,6 +34,7 @@
"fieldname": "leave_type",
"fieldtype": "Link",
"in_list_view": 1,
+ "in_standard_filter": 1,
"label": "Leave Type",
"options": "Leave Type"
},
@@ -83,11 +86,15 @@
"fieldname": "is_expired",
"fieldtype": "Check",
"label": "Is Expired"
+ },
+ {
+ "fieldname": "column_break_7",
+ "fieldtype": "Column Break"
}
],
"in_create": 1,
"is_submittable": 1,
- "modified": "2019-05-29 15:58:29.656351",
+ "modified": "2019-05-30 14:45:16.577534",
"modified_by": "Administrator",
"module": "HR",
"name": "Leave Ledger Entry",
@@ -149,5 +156,6 @@
}
],
"sort_field": "modified",
- "sort_order": "ASC"
+ "sort_order": "ASC",
+ "title_field": "employee"
}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/leave_period/leave_period.json b/erpnext/hr/doctype/leave_period/leave_period.json
index df28763c79..9e895c34fb 100644
--- a/erpnext/hr/doctype/leave_period/leave_period.json
+++ b/erpnext/hr/doctype/leave_period/leave_period.json
@@ -1,294 +1,294 @@
{
- "allow_copy": 0,
- "allow_guest_to_view": 0,
- "allow_import": 1,
- "allow_rename": 1,
- "autoname": "HR-LPR-.YYYY.-.#####",
- "beta": 0,
- "creation": "2018-04-13 15:20:52.864288",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "",
- "editable_grid": 1,
- "engine": "InnoDB",
+ "allow_copy": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 1,
+ "allow_rename": 1,
+ "autoname": "HR-LPR-.YYYY.-.#####",
+ "beta": 0,
+ "creation": "2018-04-13 15:20:52.864288",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
+ "editable_grid": 1,
+ "engine": "InnoDB",
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "from_date",
- "fieldtype": "Date",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "From Date",
- "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": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "from_date",
+ "fieldtype": "Date",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "From Date",
+ "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": 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,
- "columns": 0,
- "fieldname": "to_date",
- "fieldtype": "Date",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "To Date",
- "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": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "to_date",
+ "fieldtype": "Date",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "To Date",
+ "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": 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,
- "columns": 0,
- "fieldname": "column_break_3",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 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,
- "translatable": 0,
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "is_active",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Is Active",
+ "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,
+ "translatable": 0,
"unique": 0
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "company",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Company",
- "length": 0,
- "no_copy": 0,
- "options": "Company",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "column_break_3",
+ "fieldtype": "Column Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 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,
+ "translatable": 0,
"unique": 0
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "is_active",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Is Active",
- "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,
- "translatable": 0,
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Company",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Company",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "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,
- "columns": 0,
- "fieldname": "optional_holiday_list",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Holiday List for Optional Leave",
- "length": 0,
- "no_copy": 0,
- "options": "Holiday List",
- "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,
- "translatable": 0,
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "optional_holiday_list",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Holiday List for Optional Leave",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Holiday List",
+ "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,
+ "translatable": 0,
"unique": 0
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2018-08-21 16:15:43.305502",
- "modified_by": "Administrator",
- "module": "HR",
- "name": "Leave Period",
- "name_case": "",
- "owner": "Administrator",
+ ],
+ "has_web_view": 0,
+ "hide_heading": 0,
+ "hide_toolbar": 0,
+ "idx": 0,
+ "image_view": 0,
+ "in_create": 0,
+ "is_submittable": 0,
+ "issingle": 0,
+ "istable": 0,
+ "max_attachments": 0,
+ "modified": "2019-05-30 16:15:43.305502",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Leave Period",
+ "name_case": "",
+ "owner": "Administrator",
"permissions": [
{
- "amend": 0,
- "cancel": 0,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "System Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
+ "amend": 0,
+ "cancel": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "System Manager",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
"write": 1
- },
+ },
{
- "amend": 0,
- "cancel": 0,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "HR Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
+ "amend": 0,
+ "cancel": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "HR Manager",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
"write": 1
- },
+ },
{
- "amend": 0,
- "cancel": 0,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "HR User",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
+ "amend": 0,
+ "cancel": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "HR User",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
"write": 1
}
- ],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1,
- "track_seen": 0,
+ ],
+ "quick_entry": 0,
+ "read_only": 0,
+ "read_only_onload": 0,
+ "show_name_in_global_search": 0,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1,
+ "track_seen": 0,
"track_views": 0
}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/leave_type/leave_type.json b/erpnext/hr/doctype/leave_type/leave_type.json
index 0b8e38ea73..7899c2f1e6 100644
--- a/erpnext/hr/doctype/leave_type/leave_type.json
+++ b/erpnext/hr/doctype/leave_type/leave_type.json
@@ -418,7 +418,6 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
- "default": "1",
"depends_on": "",
"description": "calculated in days",
"fetch_if_empty": 0,
@@ -431,7 +430,7 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
- "label": "Carry Forward Leave Expiry",
+ "label": "Expire Carried Forward Leaves",
"length": 0,
"no_copy": 0,
"permlevel": 0,
@@ -729,7 +728,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2019-04-11 15:38:39.334283",
+ "modified": "2019-05-30 15:38:39.334283",
"modified_by": "Administrator",
"module": "HR",
"name": "Leave Type",
diff --git a/erpnext/patches/v12_0/generate_leave_ledger_entries.py b/erpnext/patches/v12_0/generate_leave_ledger_entries.py
index dff749fce7..065a0137a5 100644
--- a/erpnext/patches/v12_0/generate_leave_ledger_entries.py
+++ b/erpnext/patches/v12_0/generate_leave_ledger_entries.py
@@ -8,6 +8,7 @@ def execute():
""" Generates leave ledger entries for leave allocation/application/encashment
for last allocation """
frappe.reload_doc("HR","doctype", "Leave Ledger Entry")
+ frappe.reload_doc("HR","doctype", "Leave Encashment")
if frappe.db.a_row_exists("Leave Ledger Entry"):
return
From c5385e141b0b9ecf192375dfc52207c880f8200c Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Fri, 31 May 2019 00:53:28 +0530
Subject: [PATCH 058/484] fix: add mandatory reason fields in leave application
---
.../test_leave_application.py | 27 ++++++++++---------
1 file changed, 15 insertions(+), 12 deletions(-)
diff --git a/erpnext/hr/doctype/leave_application/test_leave_application.py b/erpnext/hr/doctype/leave_application/test_leave_application.py
index 30dcafafc7..899ce2ae8d 100644
--- a/erpnext/hr/doctype/leave_application/test_leave_application.py
+++ b/erpnext/hr/doctype/leave_application/test_leave_application.py
@@ -19,6 +19,7 @@ _test_records = [
"doctype": "Leave Application",
"employee": "_T-Employee-00001",
"from_date": "2013-05-01",
+ "description": "_Test Reason",
"leave_type": "_Test Leave Type",
"posting_date": "2013-01-02",
"to_date": "2013-05-05"
@@ -28,6 +29,7 @@ _test_records = [
"doctype": "Leave Application",
"employee": "_T-Employee-00002",
"from_date": "2013-05-01",
+ "description": "_Test Reason",
"leave_type": "_Test Leave Type",
"posting_date": "2013-01-02",
"to_date": "2013-05-05"
@@ -37,6 +39,7 @@ _test_records = [
"doctype": "Leave Application",
"employee": "_T-Employee-00001",
"from_date": "2013-01-15",
+ "description": "_Test Reason",
"leave_type": "_Test Leave Type LWP",
"posting_date": "2013-01-02",
"to_date": "2013-01-15"
@@ -46,8 +49,8 @@ _test_records = [
class TestLeaveApplication(unittest.TestCase):
def setUp(self):
- for dt in ["Leave Application", "Leave Allocation", "Salary Slip"]:
- frappe.db.sql("delete from `tab%s`" % dt)
+ for dt in ["Leave Application", "Leave Allocation", "Salary Slip", "Leave Ledger Entry"]:
+ frappe.db.sql("DELETE FROM `tab%s`" % dt)
@classmethod
def setUpClass(cls):
@@ -270,6 +273,7 @@ class TestLeaveApplication(unittest.TestCase):
doctype = 'Leave Application',
employee = employee.name,
company = '_Test Company',
+ description = "_Test Reason",
leave_type = leave_type,
from_date = date,
to_date = date,
@@ -288,8 +292,6 @@ class TestLeaveApplication(unittest.TestCase):
self.assertEqual(get_leave_balance_on(employee.name, leave_type, today), 9)
def test_leaves_allowed(self):
- frappe.db.sql("delete from `tabLeave Allocation`")
- frappe.db.sql("delete from `tabLeave Ledger Entry`")
employee = get_employee()
leave_period = get_leave_period()
frappe.delete_doc_if_exists("Leave Type", "Test Leave Type", force=1)
@@ -307,6 +309,7 @@ class TestLeaveApplication(unittest.TestCase):
doctype = 'Leave Application',
employee = employee.name,
leave_type = leave_type.name,
+ description = "_Test Reason",
from_date = date,
to_date = add_days(date, 2),
company = "_Test Company",
@@ -319,6 +322,7 @@ class TestLeaveApplication(unittest.TestCase):
doctype = 'Leave Application',
employee = employee.name,
leave_type = leave_type.name,
+ description = "_Test Reason",
from_date = add_days(date, 4),
to_date = add_days(date, 8),
company = "_Test Company",
@@ -344,6 +348,7 @@ class TestLeaveApplication(unittest.TestCase):
doctype = 'Leave Application',
employee = employee.name,
leave_type = leave_type.name,
+ description = "_Test Reason",
from_date = date,
to_date = add_days(date, 4),
company = "_Test Company",
@@ -365,6 +370,7 @@ class TestLeaveApplication(unittest.TestCase):
doctype = 'Leave Application',
employee = employee.name,
leave_type = leave_type_1.name,
+ description = "_Test Reason",
from_date = date,
to_date = add_days(date, 4),
company = "_Test Company",
@@ -394,6 +400,7 @@ class TestLeaveApplication(unittest.TestCase):
doctype = 'Leave Application',
employee = employee.name,
leave_type = leave_type.name,
+ description = "_Test Reason",
from_date = date,
to_date = add_days(date, 4),
company = "_Test Company",
@@ -404,8 +411,6 @@ class TestLeaveApplication(unittest.TestCase):
self.assertRaises(frappe.ValidationError, leave_application.insert)
def test_leave_balance_near_allocaton_expiry(self):
- frappe.db.sql("delete from `tabLeave Allocation`")
- frappe.db.sql("delete from `tabLeave Ledger Entry`")
employee = get_employee()
leave_type = create_leave_type(
leave_type_name="_Test_CF_leave_expiry",
@@ -460,9 +465,10 @@ class TestLeaveApplication(unittest.TestCase):
allocation.insert(ignore_permissions=True)
allocation.submit()
leave_application = frappe.get_doc(dict(
- doctype = 'Leave Application',
+ doctype = 'Leave Application',
employee = employee.name,
leave_type = leave_type,
+ description = "_Test Reason",
from_date = '2018-10-02',
to_date = '2018-10-02',
company = '_Test Company',
@@ -474,7 +480,6 @@ class TestLeaveApplication(unittest.TestCase):
self.assertEqual(leave_application.docstatus, 1)
def test_creation_of_leave_ledger_entry_on_submit(self):
- frappe.db.sql("delete from `tabLeave Allocation`")
employee = get_employee()
leave_type = create_leave_type(leave_type_name = 'Test Leave Type 1')
@@ -490,6 +495,7 @@ class TestLeaveApplication(unittest.TestCase):
leave_type = leave_type.name,
from_date = add_days(nowdate(), 1),
to_date = add_days(nowdate(), 4),
+ description = "_Test Reason",
company = "_Test Company",
docstatus = 1,
status = "Approved"
@@ -506,8 +512,6 @@ class TestLeaveApplication(unittest.TestCase):
self.assertFalse(frappe.db.exists("Leave Ledger Entry", {'transaction_name':leave_application.name}))
def test_ledger_entry_creation_on_intermediate_allocation_expiry(self):
- frappe.db.sql("delete from `tabLeave Allocation`")
- frappe.db.sql("delete from `tabLeave Ledger Entry`")
employee = get_employee()
leave_type = create_leave_type(
leave_type_name="_Test_CF_leave_expiry",
@@ -523,6 +527,7 @@ class TestLeaveApplication(unittest.TestCase):
leave_type = leave_type.name,
from_date = add_days(nowdate(), -3),
to_date = add_days(nowdate(), 7),
+ description = "_Test Reason",
company = "_Test Company",
docstatus = 1,
status = "Approved"
@@ -558,8 +563,6 @@ def create_carry_forwarded_allocation(employee, leave_type):
leave_allocation.submit()
def make_allocation_record(employee=None, leave_type=None):
- frappe.db.sql("delete from `tabLeave Allocation`")
-
allocation = frappe.get_doc({
"doctype": "Leave Allocation",
"employee": employee or "_T-Employee-00001",
From afa1dc4ffa1e7decadf5937452143e426cf34fec Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Mon, 3 Jun 2019 20:09:22 +0530
Subject: [PATCH 059/484] feat: expire current allocation
---
.../leave_allocation/leave_allocation.js | 23 ++++++++++++
.../leave_allocation/leave_allocation.json | 36 ++++++++++++++++++-
.../leave_allocation/leave_allocation.py | 21 +++++++++--
3 files changed, 76 insertions(+), 4 deletions(-)
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.js b/erpnext/hr/doctype/leave_allocation/leave_allocation.js
index 1fc1d89635..489db67109 100755
--- a/erpnext/hr/doctype/leave_allocation/leave_allocation.js
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.js
@@ -21,6 +21,29 @@ frappe.ui.form.on("Leave Allocation", {
})
},
+ refresh: function(frm) {
+ if(frm.doc.docstatus == 1){
+ frm.add_custom_button('Expire Allocation', function() {
+ frm.trigger("expire_allocation");
+ });
+ }
+ },
+
+ expire_allocation: function(frm) {
+ frappe.call({
+ method: 'erpnext.hr.doctype.leave_application.leave_application.expire_previous_allocation',
+ args: {
+ ref_doc: frm.doc
+ },
+ freeze: true,
+ callback: function(r){
+ if(!r.exc){
+ frappe.msgprint(__("Allocation Expired!"));
+ }
+ }
+ });
+ },
+
employee: function(frm) {
frm.trigger("calculate_total_leaves_allocated");
},
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.json b/erpnext/hr/doctype/leave_allocation/leave_allocation.json
index 568182d3b7..1d6307cbe1 100644
--- a/erpnext/hr/doctype/leave_allocation/leave_allocation.json
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.json
@@ -565,6 +565,40 @@
"translatable": 0,
"unique": 0
},
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_from": "employee.leave_policy",
+ "fieldname": "leave_policy",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 1,
+ "label": "Leave Policy",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Leave Policy",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
@@ -677,7 +711,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2019-05-22 11:28:09.360525",
+ "modified": "2019-05-30 11:28:09.360525",
"modified_by": "Administrator",
"module": "HR",
"name": "Leave Allocation",
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.py b/erpnext/hr/doctype/leave_allocation/leave_allocation.py
index 2a1301d2fd..0b2972e565 100755
--- a/erpnext/hr/doctype/leave_allocation/leave_allocation.py
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.py
@@ -131,7 +131,7 @@ class LeaveAllocation(Document):
def expire_previous_allocation(self):
''' expire previous allocation leaves '''
- leaves = get_remaining_leaves(self.employee, self.leave_type, self.from_date)
+ leaves = get_unused_leaves(self.employee, self.leave_type, self.from_date)
if flt(leaves) > 0:
args = dict(
@@ -171,11 +171,26 @@ def get_carry_forwarded_leaves(employee, leave_type, date, carry_forward=None):
carry_forwarded_leaves = 0
if carry_forward:
validate_carry_forward(leave_type)
- carry_forwarded_leaves = get_remaining_leaves(employee, leave_type, date)
+ carry_forwarded_leaves = get_unused_leaves(employee, leave_type, date)
return carry_forwarded_leaves
-def get_remaining_leaves(employee, leave_type, date):
+@frappe.whitelist()
+def expire_current_allocation(ref_doc):
+ ''' expire previous allocation leaves '''
+ leaves = get_unused_leaves(ref_doc.employee, ref_doc.leave_type, ref_doc.to_date)
+
+ if flt(leaves) > 0:
+ args = dict(
+ leaves=leaves * -1,
+ from_date=ref_doc.from_date,
+ to_date=ref_doc.from_date,
+ is_carry_forward=0,
+ is_expired=1
+ )
+ create_leave_ledger_entry(ref_doc, args)
+
+def get_unused_leaves(employee, leave_type, date):
return frappe.db.get_value("Leave Ledger Entry", filters={
"to_date": ("<=", date),
"employee": employee,
From 62011c9dc40f46cde0b3395452168e5077ba44c9 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Wed, 5 Jun 2019 21:16:27 +0530
Subject: [PATCH 060/484] feat: add link to policy
---
.../leave_allocation/leave_allocation.js | 13 +++++--
.../leave_allocation/leave_allocation.json | 35 ++++++++++++++++++-
.../leave_allocation/leave_allocation.py | 6 ++--
.../leave_policy/leave_policy_dashboard.py | 5 ++-
4 files changed, 53 insertions(+), 6 deletions(-)
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.js b/erpnext/hr/doctype/leave_allocation/leave_allocation.js
index 489db67109..50dbaadec7 100755
--- a/erpnext/hr/doctype/leave_allocation/leave_allocation.js
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.js
@@ -22,10 +22,19 @@ frappe.ui.form.on("Leave Allocation", {
},
refresh: function(frm) {
- if(frm.doc.docstatus == 1){
- frm.add_custom_button('Expire Allocation', function() {
+ if(frm.doc.docstatus === 1 && frm.doc.status === "Active") {
+ // expire current allocation
+ frm.add_custom_button(__('Expire Allocation'), function() {
frm.trigger("expire_allocation");
});
+
+ // opens leave balance report for employee
+ frm.add_custom_button(__('Check Leave Balance'), function() {
+ frappe.route_options = {
+ employee: frm.doc.employee,
+ };
+ frappe.set_route("query-report", "Employee Leave Balance");
+ });
}
},
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.json b/erpnext/hr/doctype/leave_allocation/leave_allocation.json
index 1d6307cbe1..125fb3150b 100644
--- a/erpnext/hr/doctype/leave_allocation/leave_allocation.json
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.json
@@ -599,6 +599,39 @@
"translatable": 0,
"unique": 0
},
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "status",
+ "fieldtype": "Select",
+ "hidden": 1,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 1,
+ "label": "Status",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Active\nExpired",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
@@ -711,7 +744,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2019-05-30 11:28:09.360525",
+ "modified": "2019-05-31 11:28:09.360525",
"modified_by": "Administrator",
"module": "HR",
"name": "Leave Allocation",
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.py b/erpnext/hr/doctype/leave_allocation/leave_allocation.py
index 0b2972e565..b402e908b0 100755
--- a/erpnext/hr/doctype/leave_allocation/leave_allocation.py
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.py
@@ -183,13 +183,15 @@ def expire_current_allocation(ref_doc):
if flt(leaves) > 0:
args = dict(
leaves=leaves * -1,
- from_date=ref_doc.from_date,
- to_date=ref_doc.from_date,
+ from_date=ref_doc.to_date,
+ to_date=ref_doc.to_date,
is_carry_forward=0,
is_expired=1
)
create_leave_ledger_entry(ref_doc, args)
+ frappe.db.set_value("Leave Allocation", ref_doc.name, "status", "Expired")
+
def get_unused_leaves(employee, leave_type, date):
return frappe.db.get_value("Leave Ledger Entry", filters={
"to_date": ("<=", date),
diff --git a/erpnext/hr/doctype/leave_policy/leave_policy_dashboard.py b/erpnext/hr/doctype/leave_policy/leave_policy_dashboard.py
index f97d2855a4..48a204596c 100644
--- a/erpnext/hr/doctype/leave_policy/leave_policy_dashboard.py
+++ b/erpnext/hr/doctype/leave_policy/leave_policy_dashboard.py
@@ -12,6 +12,9 @@ def get_data():
},
{
'items': ['Employee Grade']
- }
+ },
+ {
+ 'items': ['Leave Allocation']
+ },
]
}
\ No newline at end of file
From 351f4d53a05d2513fc7b389590b2f9d6d4906058 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Wed, 5 Jun 2019 21:22:07 +0530
Subject: [PATCH 061/484] feat: add employee filter to employee leave balance
---
.../hr/doctype/leave_allocation/leave_allocation.js | 2 +-
.../hr/doctype/leave_application/leave_application.js | 10 ++++++++++
.../leave_application/test_leave_application.py | 2 +-
.../doctype/leave_ledger_entry/leave_ledger_entry.json | 9 ++++++++-
.../employee_leave_balance/employee_leave_balance.js | 6 ++++++
.../employee_leave_balance/employee_leave_balance.py | 7 ++++---
6 files changed, 30 insertions(+), 6 deletions(-)
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.js b/erpnext/hr/doctype/leave_allocation/leave_allocation.js
index 50dbaadec7..005f45a657 100755
--- a/erpnext/hr/doctype/leave_allocation/leave_allocation.js
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.js
@@ -29,7 +29,7 @@ frappe.ui.form.on("Leave Allocation", {
});
// opens leave balance report for employee
- frm.add_custom_button(__('Check Leave Balance'), function() {
+ frm.add_custom_button(__('Leave Balance'), function() {
frappe.route_options = {
employee: frm.doc.employee,
};
diff --git a/erpnext/hr/doctype/leave_application/leave_application.js b/erpnext/hr/doctype/leave_application/leave_application.js
index 11146abce2..cb1042c5ef 100755
--- a/erpnext/hr/doctype/leave_application/leave_application.js
+++ b/erpnext/hr/doctype/leave_application/leave_application.js
@@ -86,6 +86,16 @@ frappe.ui.form.on("Leave Application", {
frm.set_value('employee', perm['Employee'].map(perm_doc => perm_doc.doc)[0]);
}
}
+
+ if (frm.doc.docstatus === 1) {
+ frm.add_custom_button(__('Leave Balance'), function() {
+ frappe.route_options = {
+ employee: frm.doc.employee,
+ group_by: ""
+ };
+ frappe.set_route("query-report", "Employee Leave Balance");
+ });
+ }
},
employee: function(frm) {
diff --git a/erpnext/hr/doctype/leave_application/test_leave_application.py b/erpnext/hr/doctype/leave_application/test_leave_application.py
index 899ce2ae8d..54216ee3c7 100644
--- a/erpnext/hr/doctype/leave_application/test_leave_application.py
+++ b/erpnext/hr/doctype/leave_application/test_leave_application.py
@@ -50,7 +50,7 @@ _test_records = [
class TestLeaveApplication(unittest.TestCase):
def setUp(self):
for dt in ["Leave Application", "Leave Allocation", "Salary Slip", "Leave Ledger Entry"]:
- frappe.db.sql("DELETE FROM `tab%s`" % dt)
+ frappe.db.sql("DELETE FROM `tab%s`" % dt) #nosec
@classmethod
def setUpClass(cls):
diff --git a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.json b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.json
index 20b64f81aa..4234fc4b40 100644
--- a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.json
+++ b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.json
@@ -14,6 +14,7 @@
"to_date",
"is_carry_forward",
"is_expired",
+ "is_lwp",
"amended_from"
],
"fields": [
@@ -90,11 +91,17 @@
{
"fieldname": "column_break_7",
"fieldtype": "Column Break"
+ },
+ {
+ "default": "0",
+ "fieldname": "is_lwp",
+ "fieldtype": "Check",
+ "label": "Is Leave Without Pay"
}
],
"in_create": 1,
"is_submittable": 1,
- "modified": "2019-05-30 14:45:16.577534",
+ "modified": "2019-06-05 12:56:04.980160",
"modified_by": "Administrator",
"module": "HR",
"name": "Leave Ledger Entry",
diff --git a/erpnext/hr/report/employee_leave_balance/employee_leave_balance.js b/erpnext/hr/report/employee_leave_balance/employee_leave_balance.js
index 68302f6ee4..05728a297b 100644
--- a/erpnext/hr/report/employee_leave_balance/employee_leave_balance.js
+++ b/erpnext/hr/report/employee_leave_balance/employee_leave_balance.js
@@ -30,6 +30,12 @@ frappe.query_reports["Employee Leave Balance"] = {
"label": __("Department"),
"fieldtype": "Link",
"options": "Department",
+ },
+ {
+ "fieldname":"employee",
+ "label": __("Employee"),
+ "fieldtype": "Link",
+ "options": "Employee",
}
]
}
diff --git a/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py b/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py
index e65220ae25..48e9bf5e5d 100644
--- a/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py
+++ b/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py
@@ -37,9 +37,10 @@ def get_conditions(filters):
"company": filters.company,
}
if filters.get("department"):
- conditions.update({
- "department": filters.get("department")
- })
+ conditions.update({"department": filters.get("department")})
+ if filters.get("employee"):
+ conditions.update({"employee": filters.get("employee")})
+
return conditions
def get_data(filters, leave_types):
From 050f65beb44bfed1cabef5dbd51fe543002027df Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Thu, 6 Jun 2019 20:32:01 +0530
Subject: [PATCH 062/484] feat: fetch leave allocation from ledger entry
---
.../employee_leave_balance.py | 24 +++++++++++++++----
1 file changed, 20 insertions(+), 4 deletions(-)
diff --git a/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py b/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py
index 48e9bf5e5d..3c3e6af25c 100644
--- a/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py
+++ b/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py
@@ -6,7 +6,7 @@ import frappe
from frappe import _
from frappe.utils import flt
from erpnext.hr.doctype.leave_application.leave_application \
- import get_leave_allocation_records, get_leave_balance_on, get_approved_leaves_for_period, get_total_allocated_leaves
+ import get_leaves_for_period
def execute(filters=None):
@@ -59,11 +59,11 @@ def get_data(filters, leave_types):
for leave_type in leave_types:
# leaves taken
- leaves_taken = get_approved_leaves_for_period(employee.name, leave_type,
- filters.from_date, filters.to_date)
+ leaves_taken = get_leaves_for_period(employee.name, leave_type,
+ filters.from_date, filters.to_date) * -1
# opening balance
- opening = get_total_allocated_leaves(employee.name, leave_type, filters.to_date)
+ opening = get_total_allocated_leaves(employee.name, leave_type, filters.from_date, filters.to_date)
# closing balance
closing = flt(opening) - flt(leaves_taken)
@@ -91,3 +91,19 @@ def get_approvers(department):
where parent = %s and parentfield = 'leave_approvers'""", (d), as_dict=True)])
return approvers
+
+def get_total_allocated_leaves(employee, leave_type, from_date, to_date):
+ ''' Returns leave allocation between from date and to date '''
+ filters= {
+ 'from_date': ['between', (from_date, to_date)],
+ 'to_date': ['between', (from_date, to_date)],
+ 'docstatus': 1,
+ 'is_expired': 0,
+ 'leave_type': leave_type,
+ 'employee': employee,
+ 'transaction_type': 'Leave Allocation'
+ }
+
+ leave_allocation_records = frappe.db.get_all('Leave Ledger Entry', filters=filters, fields=['SUM(leaves) as leaves'])
+
+ return flt(leave_allocation_records[0].get('leaves')) if leave_allocation_records else flt(0)
\ No newline at end of file
From 3863fc5fb24a76b1f5820cb1da4e1257f537f668 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Thu, 6 Jun 2019 20:34:10 +0530
Subject: [PATCH 063/484] feat: create ledger entry for each earned leave
---
erpnext/hr/utils.py | 60 +++++++++++++++++++++++++++------------------
1 file changed, 36 insertions(+), 24 deletions(-)
diff --git a/erpnext/hr/utils.py b/erpnext/hr/utils.py
index 7357fd0cc1..e8c9dd0c45 100644
--- a/erpnext/hr/utils.py
+++ b/erpnext/hr/utils.py
@@ -270,31 +270,43 @@ def allocate_earned_leaves():
filters={'is_earned_leave' : 1})
today = getdate()
divide_by_frequency = {"Yearly": 1, "Half-Yearly": 6, "Quarterly": 4, "Monthly": 12}
- if e_leave_types:
- for e_leave_type in e_leave_types:
- leave_allocations = frappe.db.sql("""select name, employee, from_date, to_date from `tabLeave Allocation` where '{0}'
- between from_date and to_date and docstatus=1 and leave_type='{1}'"""
- .format(today, e_leave_type.name), as_dict=1)
- for allocation in leave_allocations:
- leave_policy = get_employee_leave_policy(allocation.employee)
- if not leave_policy:
- continue
- if not e_leave_type.earned_leave_frequency == "Monthly":
- if not check_frequency_hit(allocation.from_date, today, e_leave_type.earned_leave_frequency):
- continue
- annual_allocation = frappe.db.sql("""select annual_allocation from `tabLeave Policy Detail`
- where parent=%s and leave_type=%s""", (leave_policy.name, e_leave_type.name))
- if annual_allocation and annual_allocation[0]:
- earned_leaves = flt(annual_allocation[0][0]) / divide_by_frequency[e_leave_type.earned_leave_frequency]
- if e_leave_type.rounding == "0.5":
- earned_leaves = round(earned_leaves * 2) / 2
- else:
- earned_leaves = round(earned_leaves)
- allocated_leaves = frappe.db.get_value('Leave Allocation', allocation.name, 'total_leaves_allocated')
- new_allocation = flt(allocated_leaves) + flt(earned_leaves)
- new_allocation = new_allocation if new_allocation <= e_leave_type.max_leaves_allowed else e_leave_type.max_leaves_allowed
- frappe.db.set_value('Leave Allocation', allocation.name, 'total_leaves_allocated', new_allocation)
+ for e_leave_type in e_leave_types:
+ leave_allocations = frappe.db.sql("""select name, employee, from_date, to_date from `tabLeave Allocation` where '{0}'
+ between from_date and to_date and docstatus=1 and leave_type='{1}'"""
+ .format(today, e_leave_type.name), as_dict=1)
+ for allocation in leave_allocations:
+ leave_policy = get_employee_leave_policy(allocation.employee)
+ if not leave_policy:
+ continue
+ if not e_leave_type.earned_leave_frequency == "Monthly":
+ if not check_frequency_hit(allocation.from_date, today, e_leave_type.earned_leave_frequency):
+ continue
+ annual_allocation = frappe.db.sql("""select annual_allocation from `tabLeave Policy Detail`
+ where parent=%s and leave_type=%s""", (leave_policy.name, e_leave_type.name))
+ if annual_allocation and annual_allocation[0]:
+ earned_leaves = flt(annual_allocation[0][0]) / divide_by_frequency[e_leave_type.earned_leave_frequency]
+ if e_leave_type.rounding == "0.5":
+ earned_leaves = round(earned_leaves * 2) / 2
+ else:
+ earned_leaves = round(earned_leaves)
+
+ allocation = frappe.get_doc('Leave Allocation', allocation.name)
+ new_allocation = flt(allocation.total_leaves_allocated) + flt(earned_leaves)
+ new_allocation = new_allocation if new_allocation <= e_leave_type.max_leaves_allowed else e_leave_type.max_leaves_allowed
+
+ if new_allocation == allocation.total_leaves_allocated:
+ continue
+ allocation.db_set("total_leaves_allocated", new_allocation, update_modified=False)
+ create_earned_leave_ledger_entry(allocation, earned_leaves, today)
+
+
+def create_earned_leave_ledger_entry(allocation, earned_leaves, date):
+ ''' Create leave ledger entry based on the earned leave frequency '''
+ allocation.new_leaves_allocated = earned_leaves
+ allocation.from_date = date
+ allocation.carry_forwarded_leaves = 0
+ allocation.create_leave_ledger_entry()
def check_frequency_hit(from_date, to_date, frequency):
'''Return True if current date matches frequency'''
From f13243a92eba52883aefe645d346ef4a67685958 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Thu, 6 Jun 2019 20:35:10 +0530
Subject: [PATCH 064/484] feat: fetch annual allocation based on leave policy
---
.../hr/doctype/leave_allocation/leave_allocation.js | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.js b/erpnext/hr/doctype/leave_allocation/leave_allocation.js
index 005f45a657..7ecd3d1c91 100755
--- a/erpnext/hr/doctype/leave_allocation/leave_allocation.js
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.js
@@ -58,6 +58,7 @@ frappe.ui.form.on("Leave Allocation", {
},
leave_type: function(frm) {
+ frm.trigger("leave_policy")
frm.trigger("calculate_total_leaves_allocated");
},
@@ -75,6 +76,17 @@ frappe.ui.form.on("Leave Allocation", {
flt(frm.doc.carry_forwarded_leaves) + flt(frm.doc.new_leaves_allocated));
},
+ leave_policy: function(frm) {
+ if(frm.doc.leave_policy && frm.doc.leave_type) {
+ frappe.db.get_value("Leave Policy Detail",
+ {'parent': frm.doc.leave_policy, 'leave_type': frm.doc.leave_type},
+ 'annual_allocation', (r) => {
+ if (!r.exc) {
+ frm.set_value("new_leaves_allocated", flt(r.annual_allocation));
+ }
+ }, "Leave Policy")
+ }
+ },
calculate_total_leaves_allocated: function(frm) {
if (cint(frm.doc.carry_forward) == 1 && frm.doc.leave_type && frm.doc.employee) {
return frappe.call({
From 00c607116bbf8627028290c30e6d1494c4530236 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Thu, 6 Jun 2019 20:37:34 +0530
Subject: [PATCH 065/484] fix: handle negative leaves without allocation
---
erpnext/hr/doctype/leave_allocation/leave_allocation.py | 6 +++---
.../doctype/leave_ledger_entry/leave_ledger_entry.json | 4 ++--
.../hr/doctype/leave_ledger_entry/leave_ledger_entry.py | 8 ++------
erpnext/hr/doctype/leave_type/leave_type.py | 9 +--------
4 files changed, 8 insertions(+), 19 deletions(-)
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.py b/erpnext/hr/doctype/leave_allocation/leave_allocation.py
index b402e908b0..843d3055d5 100755
--- a/erpnext/hr/doctype/leave_allocation/leave_allocation.py
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.py
@@ -7,7 +7,6 @@ from frappe.utils import flt, date_diff, formatdate, add_days
from frappe import _
from frappe.model.document import Document
from erpnext.hr.utils import set_employee_name, get_leave_period
-from erpnext.hr.doctype.leave_application.leave_application import get_approved_leaves_for_period
from erpnext.hr.doctype.leave_ledger_entry.leave_ledger_entry import create_leave_ledger_entry
class OverlapError(frappe.ValidationError): pass
@@ -133,9 +132,9 @@ class LeaveAllocation(Document):
''' expire previous allocation leaves '''
leaves = get_unused_leaves(self.employee, self.leave_type, self.from_date)
- if flt(leaves) > 0:
+ if leaves:
args = dict(
- leaves=leaves * -1,
+ leaves=flt(leaves) * -1,
from_date=self.from_date,
to_date=self.from_date,
is_carry_forward=0,
@@ -198,6 +197,7 @@ def get_unused_leaves(employee, leave_type, date):
"employee": employee,
"docstatus": 1,
"leave_type": leave_type,
+ "is_lwp": 0
}, fieldname=['SUM(leaves)'])
def validate_carry_forward(leave_type):
diff --git a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.json b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.json
index 4234fc4b40..0166e43c0f 100644
--- a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.json
+++ b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.json
@@ -62,7 +62,7 @@
},
{
"fieldname": "leaves",
- "fieldtype": "Int",
+ "fieldtype": "Float",
"in_list_view": 1,
"label": "Leaves"
},
@@ -101,7 +101,7 @@
],
"in_create": 1,
"is_submittable": 1,
- "modified": "2019-06-05 12:56:04.980160",
+ "modified": "2019-06-06 20:33:37.531161",
"modified_by": "Administrator",
"module": "HR",
"name": "Leave Ledger Entry",
diff --git a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
index e85d5cef0a..6142dcf648 100644
--- a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
+++ b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
@@ -9,11 +9,6 @@ from frappe import _
from frappe.utils import add_days, today, flt
class LeaveLedgerEntry(Document):
- def validate_entries(self):
- total_leaves = frappe.get_all('Leave Ledger Entry', ['SUM(leaves)'])
- if total_leaves < 0:
- frappe.throw(_("Invalid Ledger Entry"))
-
def on_cancel(self):
# allow cancellation of expiry leaves
if not self.is_expired:
@@ -43,7 +38,8 @@ def create_leave_ledger_entry(ref_doc, args, submit=True):
transaction_type=ref_doc.doctype,
transaction_name=ref_doc.name,
is_carry_forward=0,
- is_expired=0
+ is_expired=0,
+ is_lwp=0
)
ledger.update(args)
if submit:
diff --git a/erpnext/hr/doctype/leave_type/leave_type.py b/erpnext/hr/doctype/leave_type/leave_type.py
index dcae5fe085..5b13edb684 100644
--- a/erpnext/hr/doctype/leave_type/leave_type.py
+++ b/erpnext/hr/doctype/leave_type/leave_type.py
@@ -10,11 +10,4 @@ from frappe import _
from frappe.model.document import Document
class LeaveType(Document):
- def validate(self):
- if self.is_carry_forward:
- self.validate_carry_forward()
-
- def validate_carry_forward(self):
- max_days = 367 if calendar.isleap(datetime.now().year) else 366
- if not (0 <= self.carry_forward_leave_expiry <= max_days):
- frappe.throw(_('Invalid entry!! Carried forward days need to expire within a year'))
\ No newline at end of file
+ pass
\ No newline at end of file
From b840ba4407c3b0cf124b8bb9f3b32267f04ed821 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Thu, 6 Jun 2019 20:38:23 +0530
Subject: [PATCH 066/484] feat: show dashboard on submit
---
.../leave_application/leave_application.js | 24 ++++++++------
.../leave_application/leave_application.json | 33 ++++++++++++++++++-
2 files changed, 46 insertions(+), 11 deletions(-)
diff --git a/erpnext/hr/doctype/leave_application/leave_application.js b/erpnext/hr/doctype/leave_application/leave_application.js
index cb1042c5ef..2076ccd22a 100755
--- a/erpnext/hr/doctype/leave_application/leave_application.js
+++ b/erpnext/hr/doctype/leave_application/leave_application.js
@@ -53,24 +53,27 @@ frappe.ui.form.on("Leave Application", {
},
callback: function(r) {
if (!r.exc && r.message['leave_allocation']) {
- leave_details = r.message['leave_allocation'];
+ frm.set_value('leave_details', JSON.stringify(r.message['leave_allocation']));
}
if (!r.exc && r.message['leave_approver']) {
frm.set_value('leave_approver', r.message['leave_approver']);
}
}
});
-
- $("div").remove(".form-dashboard-section");
- let section = frm.dashboard.add_section(
- frappe.render_template('leave_application_dashboard', {
- data: leave_details
- })
- );
- frm.dashboard.show();
+ frm.trigger("create_dashboard")
}
},
+ create_dashboard: function(frm) {
+ $("div").remove(".form-dashboard-section");
+ let section = frm.dashboard.add_section(
+ frappe.render_template('leave_application_dashboard', {
+ data: JSON.parse(frm.doc.leave_details)
+ })
+ );
+ frm.dashboard.show();
+ },
+
refresh: function(frm) {
if (frm.is_new()) {
frm.trigger("calculate_total_days");
@@ -95,6 +98,7 @@ frappe.ui.form.on("Leave Application", {
};
frappe.set_route("query-report", "Employee Leave Balance");
});
+ frm.trigger("create_dashboard");
}
},
@@ -148,7 +152,7 @@ frappe.ui.form.on("Leave Application", {
},
get_leave_balance: function(frm) {
- if(frm.doc.docstatus==0 && frm.doc.employee && frm.doc.leave_type && frm.doc.from_date) {
+ if(frm.doc.docstatus==0 && frm.doc.employee && frm.doc.leave_type && frm.doc.from_date && frm.doc.to_date) {
return frappe.call({
method: "erpnext.hr.doctype.leave_application.leave_application.get_leave_balance_on",
args: {
diff --git a/erpnext/hr/doctype/leave_application/leave_application.json b/erpnext/hr/doctype/leave_application/leave_application.json
index 812494c1c0..c59449f850 100644
--- a/erpnext/hr/doctype/leave_application/leave_application.json
+++ b/erpnext/hr/doctype/leave_application/leave_application.json
@@ -653,6 +653,37 @@
"translatable": 0,
"unique": 0
},
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "leave_details",
+ "fieldtype": "Small Text",
+ "hidden": 1,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Leave Details",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "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,
+ "translatable": 0,
+ "unique": 0
+ },
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
@@ -951,7 +982,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 3,
- "modified": "2019-05-30 11:28:14.745572",
+ "modified": "2019-05-31 11:30:14.745572",
"modified_by": "Administrator",
"module": "HR",
"name": "Leave Application",
From c7b9ae9c5e6e0f08004bb7f997eb8909fb9919fb Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Thu, 6 Jun 2019 20:38:59 +0530
Subject: [PATCH 067/484] fix: get leave balance based on the ledger entries
---
.../leave_application/leave_application.py | 157 +++++++++---------
1 file changed, 75 insertions(+), 82 deletions(-)
diff --git a/erpnext/hr/doctype/leave_application/leave_application.py b/erpnext/hr/doctype/leave_application/leave_application.py
index fd13436d8f..fec7cede2f 100755
--- a/erpnext/hr/doctype/leave_application/leave_application.py
+++ b/erpnext/hr/doctype/leave_application/leave_application.py
@@ -5,7 +5,7 @@ from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.utils import cint, cstr, date_diff, flt, formatdate, getdate, get_link_to_form, \
- comma_or, get_fullname, add_days, nowdate
+ comma_or, get_fullname, add_days, nowdate, get_datetime_str
from erpnext.hr.utils import set_employee_name, get_leave_period
from erpnext.hr.doctype.leave_block_list.leave_block_list import get_applicable_block_dates
from erpnext.hr.doctype.employee.employee import get_holiday_list_for_employee
@@ -353,6 +353,8 @@ class LeaveApplication(Document):
expiry_date = get_allocation_expiry(self.employee, self.leave_type,
self.to_date, self.from_date)
+ lwp = frappe.db.get_value("Leave Type", self.leave_type, "is_lwp")
+
if expiry_date:
self.create_ledger_entry_for_intermediate_allocation_expiry(expiry_date, submit)
else:
@@ -360,6 +362,7 @@ class LeaveApplication(Document):
leaves=self.total_leave_days * -1,
from_date=self.from_date,
to_date=self.to_date,
+ is_lwp=lwp
)
create_leave_ledger_entry(self, args, submit)
@@ -407,21 +410,22 @@ def get_number_of_leave_days(employee, leave_type, from_date, to_date, half_day
@frappe.whitelist()
def get_leave_details(employee, date):
- allocation_records = get_leave_allocation_records(date, employee).get(employee, frappe._dict())
+ allocation_records = get_leave_allocation_records(employee, date)
leave_allocation = {}
for d in allocation_records:
allocation = allocation_records.get(d, frappe._dict())
remaining_leaves = get_leave_balance_on(employee, d, date, to_date = allocation.to_date,
consider_all_leaves_in_the_allocation_period=True)
date = allocation.to_date
- leaves_taken = get_leaves_for_period(employee, d, allocation.from_date, date, status="Approved")
- leaves_pending = get_leaves_for_period(employee, d, allocation.from_date, date, status="Open")
+ leaves_taken = get_leaves_for_period(employee, d, allocation.from_date, date) * -1
+ leaves_pending = get_pending_leaves_for_period(employee, d, allocation.from_date, date)
leave_allocation[d] = {
"total_leaves": allocation.total_leaves_allocated,
"leaves_taken": leaves_taken,
"pending_leaves": leaves_pending,
"remaining_leaves": remaining_leaves}
+ leave_details = leave_allocation
ret = {
'leave_allocation': leave_allocation,
@@ -436,17 +440,64 @@ def get_leave_balance_on(employee, leave_type, date, to_date=nowdate(), allocati
''' Returns leave balance till date and fetches expiry date based on to_date
to calculate minimum remaining leave balance '''
- if allocation_records == None:
- allocation_records = get_leave_allocation_records(date, employee).get(employee, frappe._dict())
+ if not allocation_records:
+ allocation_records = get_leave_allocation_records(employee, date, leave_type)
+
allocation = allocation_records.get(leave_type, frappe._dict())
end_date = allocation.to_date if consider_all_leaves_in_the_allocation_period else date
expiry = get_allocation_expiry(employee, leave_type, to_date, date)
- leaves_taken = get_leaves_taken(employee, leave_type, allocation.from_date, end_date)
+ leaves_taken = get_leaves_for_period(employee, leave_type, allocation.from_date, end_date)
return get_remaining_leaves(allocation, leaves_taken, date, expiry)
+def get_leave_allocation_records(employee, date, leave_type=None):
+ ''' returns the total allocated leaves and carry forwarded leaves based on ledger entries '''
+
+ conditions = ("and leave_type='%s'" % leave_type) if leave_type else ""
+ allocation_details = frappe.db.sql("""
+ SELECT
+ SUM(CASE WHEN is_carry_forward = 1 THEN leaves ELSE 0 END) as cf_leaves,
+ SUM(CASE WHEN is_carry_forward = 0 THEN leaves ELSE 0 END) as new_leaves,
+ MIN(from_date) as from_date,
+ MAX(to_date) as to_date,
+ leave_type
+ FROM `tabLeave Ledger Entry`
+ WHERE
+ from_date <= %(date)s
+ AND to_date >= %(date)s
+ AND docstatus=1
+ AND transaction_type="Leave Allocation"
+ AND employee=%(employee)s
+ AND is_expired=0
+ AND is_lwp=0
+ {0}
+ GROUP BY employee, leave_type
+ """.format(conditions), dict(date=date, employee=employee), as_dict=1)
+
+ allocated_leaves = frappe._dict()
+ for d in allocation_details:
+ allocated_leaves.setdefault(d.leave_type, frappe._dict({
+ "from_date": d.from_date,
+ "to_date": d.to_date,
+ "total_leaves_allocated": flt(d.cf_leaves) + flt(d.new_leaves),
+ "carry_forwarded_leaves": d.cf_leaves,
+ "new_leaves_allocated": d.new_leaves,
+ "leave_type": d.leave_type
+ }))
+ return allocated_leaves
+
+def get_pending_leaves_for_period(employee, leave_type, from_date, to_date):
+ ''' Returns leaves that are pending approval '''
+ return frappe.db.get_value("Leave Application",
+ filters={
+ "employee": employee,
+ "leave_type": leave_type,
+ "from_date": ("<=", from_date),
+ "to_date": (">=", to_date),
+ }, fieldname=['SUM(total_leave_days)']) or flt(0)
+
def get_remaining_leaves(allocation, leaves_taken, date, expiry):
''' Returns minimum leaves remaining after comparing with remaining days for allocation expiry '''
def _get_remaining_leaves(allocated_leaves, end_date):
@@ -465,39 +516,14 @@ def get_remaining_leaves(allocation, leaves_taken, date, expiry):
else:
return _get_remaining_leaves(allocation.total_leaves_allocated, allocation.to_date)
-def get_leaves_taken(employee, leave_type, from_date, to_date):
- ''' Returns leaves taken based on leave application/encashment '''
- leaves = frappe.db.get_all("Leave Ledger Entry", filters={
- 'Employee':employee,
- 'leave_type':leave_type,
- 'leaves': ("<", 0),
- 'to_date':("<=", to_date),
- 'from_date': (">=", from_date)},
- or_filters={
- 'is_expired': 0,
- 'is_carry_forward': 1
- }, fields=['SUM(leaves) as leaves'])
- return leaves[0]['leaves'] if leaves else None
-
-def get_total_allocated_leaves(employee, leave_type, date):
- filters= {
- 'from_date': ['<=', date],
- 'to_date': ['>=', date],
- 'docstatus': 1,
- 'leave_type': leave_type,
- 'employee': employee
- }
-
- leave_allocation_records = frappe.db.get_all('Leave Allocation', filters=filters, fields=['total_leaves_allocated'])
-
- return flt(leave_allocation_records[0]['total_leaves_allocated']) if leave_allocation_records else flt(0)
-
-def get_leaves_for_period(employee, leave_type, from_date, to_date, status, docname=None):
- leave_applications = frappe.db.sql("""
- select name, employee, leave_type, from_date, to_date, total_leave_days
- from `tabLeave Application`
+def get_leaves_for_period(employee, leave_type, from_date, to_date):
+ leave_entries = frappe.db.sql("""
+ select employee, leave_type, from_date, to_date, leaves, transaction_type
+ from `tabLeave Ledger Entry`
where employee=%(employee)s and leave_type=%(leave_type)s
- and status = %(status)s and docstatus != 2
+ and docstatus=1
+ and leaves<0
+ and (is_expired=0 or is_carry_forward=1)
and (from_date between %(from_date)s and %(to_date)s
or to_date between %(from_date)s and %(to_date)s
or (from_date < %(from_date)s and to_date > %(to_date)s))
@@ -505,58 +531,25 @@ def get_leaves_for_period(employee, leave_type, from_date, to_date, status, docn
"from_date": from_date,
"to_date": to_date,
"employee": employee,
- "status": status,
"leave_type": leave_type
}, as_dict=1)
leave_days = 0
- for leave_app in leave_applications:
- if docname and leave_app.name == docname:
- continue
- if leave_app.from_date >= getdate(from_date) and leave_app.to_date <= getdate(to_date):
- leave_days += leave_app.total_leave_days
+
+ for leave_entry in leave_entries:
+ if leave_entry.from_date >= getdate(from_date) and \
+ leave_entry.to_date <= getdate(to_date) and leave_entry.transaction_type=='Leave Encashment':
+ leave_days += leave_entry.leaves
else:
- if leave_app.from_date < getdate(from_date):
- leave_app.from_date = from_date
- if leave_app.to_date > getdate(to_date):
- leave_app.to_date = to_date
+ if leave_entry.from_date < getdate(from_date):
+ leave_entry.from_date = from_date
+ if leave_entry.to_date > getdate(to_date):
+ leave_entry.to_date = to_date
leave_days += get_number_of_leave_days(employee, leave_type,
- leave_app.from_date, leave_app.to_date)
+ leave_entry.from_date, leave_entry.to_date) * -1
return leave_days
-def get_leave_allocation_records(date, employee=None):
- conditions = (" and employee='%s'" % employee) if employee else ""
-
- leave_allocation_records = frappe.db.sql("""
- SELECT
- employee,
- leave_type,
- total_leaves_allocated,
- carry_forwarded_leaves,
- new_leaves_allocated,
- carry_forward,
- from_date,
- to_date
- FROM
- `tabLeave Allocation`
- WHERE
- %s between from_date and to_date
- AND docstatus=1 {0}""".format(conditions), (date), as_dict=1) #nosec
-
- allocated_leaves = frappe._dict()
- for d in leave_allocation_records:
- allocated_leaves.setdefault(d.employee, frappe._dict()).setdefault(d.leave_type, frappe._dict({
- "from_date": d.from_date,
- "to_date": d.to_date,
- "total_leaves_allocated": d.total_leaves_allocated,
- "carry_forward": d.carry_forward,
- "carry_forwarded_leaves": d.carry_forwarded_leaves,
- "new_leaves_allocated": d.new_leaves_allocated,
- "leave_type": d.leave_type
- }))
- return allocated_leaves
-
@frappe.whitelist()
def get_holidays(employee, from_date, to_date):
'''get holidays between two dates for the given employee'''
From 368a97436820a35148f8f470b683bed0ed47a381 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Thu, 6 Jun 2019 20:43:32 +0530
Subject: [PATCH 068/484] style: change formatting
---
erpnext/hr/doctype/leave_application/leave_application.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/hr/doctype/leave_application/leave_application.py b/erpnext/hr/doctype/leave_application/leave_application.py
index fec7cede2f..02539a4c3b 100755
--- a/erpnext/hr/doctype/leave_application/leave_application.py
+++ b/erpnext/hr/doctype/leave_application/leave_application.py
@@ -474,7 +474,7 @@ def get_leave_allocation_records(employee, date, leave_type=None):
AND is_lwp=0
{0}
GROUP BY employee, leave_type
- """.format(conditions), dict(date=date, employee=employee), as_dict=1)
+ """.format(conditions), dict(date=date, employee=employee), as_dict=1) #nosec
allocated_leaves = frappe._dict()
for d in allocation_details:
From e4d03bf0d0d9d4a3ca8fb548630ebb7ce30018c1 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Fri, 7 Jun 2019 11:30:27 +0530
Subject: [PATCH 069/484] fix: consider expiry in leaves
---
.../leave_allocation/leave_allocation.js | 19 ++++++----
.../leave_allocation/leave_allocation.py | 36 +++++++------------
.../leave_application/leave_application.py | 5 ++-
3 files changed, 26 insertions(+), 34 deletions(-)
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.js b/erpnext/hr/doctype/leave_allocation/leave_allocation.js
index 7ecd3d1c91..1b3349a1ce 100755
--- a/erpnext/hr/doctype/leave_allocation/leave_allocation.js
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.js
@@ -23,10 +23,13 @@ frappe.ui.form.on("Leave Allocation", {
refresh: function(frm) {
if(frm.doc.docstatus === 1 && frm.doc.status === "Active") {
- // expire current allocation
- frm.add_custom_button(__('Expire Allocation'), function() {
- frm.trigger("expire_allocation");
- });
+ var valid_expiry = moment(frappe.datetime.get_today()).isBetween(frm.doc.from_date, frm.doc.to_date);
+ if(valid_expiry) {
+ // expire current allocation
+ frm.add_custom_button(__('Expire Allocation'), function() {
+ frm.trigger("expire_allocation");
+ });
+ }
// opens leave balance report for employee
frm.add_custom_button(__('Leave Balance'), function() {
@@ -40,15 +43,17 @@ frappe.ui.form.on("Leave Allocation", {
expire_allocation: function(frm) {
frappe.call({
- method: 'erpnext.hr.doctype.leave_application.leave_application.expire_previous_allocation',
+ method: 'expire_allocation',
+ doc: frm.doc,
args: {
- ref_doc: frm.doc
+ current: true
},
freeze: true,
callback: function(r){
if(!r.exc){
frappe.msgprint(__("Allocation Expired!"));
}
+ frm.refresh();
}
});
},
@@ -81,7 +86,7 @@ frappe.ui.form.on("Leave Allocation", {
frappe.db.get_value("Leave Policy Detail",
{'parent': frm.doc.leave_policy, 'leave_type': frm.doc.leave_type},
'annual_allocation', (r) => {
- if (!r.exc) {
+ if (r && !r.exc) {
frm.set_value("new_leaves_allocated", flt(r.annual_allocation));
}
}, "Leave Policy")
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.py b/erpnext/hr/doctype/leave_allocation/leave_allocation.py
index 843d3055d5..72ea2733b0 100755
--- a/erpnext/hr/doctype/leave_allocation/leave_allocation.py
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.py
@@ -3,7 +3,7 @@
from __future__ import unicode_literals
import frappe
-from frappe.utils import flt, date_diff, formatdate, add_days
+from frappe.utils import flt, date_diff, formatdate, add_days, today
from frappe import _
from frappe.model.document import Document
from erpnext.hr.utils import set_employee_name, get_leave_period
@@ -41,8 +41,8 @@ class LeaveAllocation(Document):
.format(self.leave_type, self.employee))
def on_submit(self):
- self.expire_previous_allocation()
self.create_leave_ledger_entry()
+ self.expire_allocation()
def on_cancel(self):
self.create_leave_ledger_entry(submit=False)
@@ -128,20 +128,25 @@ class LeaveAllocation(Document):
)
create_leave_ledger_entry(self, args, submit)
- def expire_previous_allocation(self):
- ''' expire previous allocation leaves '''
- leaves = get_unused_leaves(self.employee, self.leave_type, self.from_date)
+ def expire_allocation(self, current=False):
+ ''' expires allocation '''
+ date = self.to_date if current else self.from_date
+ leaves = get_unused_leaves(self.employee, self.leave_type, date)
if leaves:
+ expiry_date = today() if current else add_days(self.from_date, -1)
args = dict(
leaves=flt(leaves) * -1,
- from_date=self.from_date,
- to_date=self.from_date,
+ from_date=expiry_date,
+ to_date=expiry_date,
is_carry_forward=0,
is_expired=1
)
create_leave_ledger_entry(self, args)
+ if current:
+ frappe.db.set_value("Leave Allocation", self.name, "status", "Expired")
+
def get_leave_allocation_for_period(employee, leave_type, from_date, to_date):
leave_allocated = 0
leave_allocations = frappe.db.sql("""
@@ -174,23 +179,6 @@ def get_carry_forwarded_leaves(employee, leave_type, date, carry_forward=None):
return carry_forwarded_leaves
-@frappe.whitelist()
-def expire_current_allocation(ref_doc):
- ''' expire previous allocation leaves '''
- leaves = get_unused_leaves(ref_doc.employee, ref_doc.leave_type, ref_doc.to_date)
-
- if flt(leaves) > 0:
- args = dict(
- leaves=leaves * -1,
- from_date=ref_doc.to_date,
- to_date=ref_doc.to_date,
- is_carry_forward=0,
- is_expired=1
- )
- create_leave_ledger_entry(ref_doc, args)
-
- frappe.db.set_value("Leave Allocation", ref_doc.name, "status", "Expired")
-
def get_unused_leaves(employee, leave_type, date):
return frappe.db.get_value("Leave Ledger Entry", filters={
"to_date": ("<=", date),
diff --git a/erpnext/hr/doctype/leave_application/leave_application.py b/erpnext/hr/doctype/leave_application/leave_application.py
index 02539a4c3b..a9e4f05ca2 100755
--- a/erpnext/hr/doctype/leave_application/leave_application.py
+++ b/erpnext/hr/doctype/leave_application/leave_application.py
@@ -523,7 +523,6 @@ def get_leaves_for_period(employee, leave_type, from_date, to_date):
where employee=%(employee)s and leave_type=%(leave_type)s
and docstatus=1
and leaves<0
- and (is_expired=0 or is_carry_forward=1)
and (from_date between %(from_date)s and %(to_date)s
or to_date between %(from_date)s and %(to_date)s
or (from_date < %(from_date)s and to_date > %(to_date)s))
@@ -536,8 +535,8 @@ def get_leaves_for_period(employee, leave_type, from_date, to_date):
leave_days = 0
for leave_entry in leave_entries:
- if leave_entry.from_date >= getdate(from_date) and \
- leave_entry.to_date <= getdate(to_date) and leave_entry.transaction_type=='Leave Encashment':
+ if leave_entry.from_date >= getdate(from_date) and leave_entry.to_date <= getdate(to_date) \
+ and leave_entry.transaction_type in ('Leave Encashment', 'Leave Allocation'):
leave_days += leave_entry.leaves
else:
if leave_entry.from_date < getdate(from_date):
From 283d2c5ca24926e5737bc58df12c8164744417d3 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Tue, 11 Jun 2019 16:35:29 +0530
Subject: [PATCH 070/484] fix: only create leave application ledger on
intermediate allocation expiry
---
.../leave_application/leave_application.py | 17 +++++++++--------
1 file changed, 9 insertions(+), 8 deletions(-)
diff --git a/erpnext/hr/doctype/leave_application/leave_application.py b/erpnext/hr/doctype/leave_application/leave_application.py
index a9e4f05ca2..f6550f0dbe 100755
--- a/erpnext/hr/doctype/leave_application/leave_application.py
+++ b/erpnext/hr/doctype/leave_application/leave_application.py
@@ -370,18 +370,19 @@ class LeaveApplication(Document):
''' splits leave application into two ledger entries to consider expiry of allocation '''
args = dict(
from_date=self.from_date,
- to_date=self.to_date,
+ to_date=expiry_date,
leaves=(date_diff(expiry_date, self.from_date) + 1) * -1
)
create_leave_ledger_entry(self, args, submit)
- start_date = add_days(expiry_date, 1)
- args.update(dict(
- from_date=start_date,
- to_date=self.to_date,
- leaves=date_diff(self.to_date, expiry_date) * -1
- ))
- create_leave_ledger_entry(self, args, submit)
+ if expiry_date != self.to_date:
+ start_date = add_days(expiry_date, 1)
+ args.update(dict(
+ from_date=start_date,
+ to_date=self.to_date,
+ leaves=date_diff(self.to_date, expiry_date) * -1
+ ))
+ create_leave_ledger_entry(self, args, submit)
def get_allocation_expiry(employee, leave_type, to_date, from_date):
expiry = frappe.get_all("Leave Ledger Entry",
From 4e1b60d401e9ce5f6f59aa8847985b421dc1aa29 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Fri, 14 Jun 2019 11:15:54 +0530
Subject: [PATCH 071/484] style: change formatting
---
.../doctype/leave_allocation/leave_allocation.js | 15 +++++++--------
.../leave_application/leave_application.js | 2 +-
2 files changed, 8 insertions(+), 9 deletions(-)
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.js b/erpnext/hr/doctype/leave_allocation/leave_allocation.js
index 1b3349a1ce..a620d9e081 100755
--- a/erpnext/hr/doctype/leave_allocation/leave_allocation.js
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.js
@@ -63,7 +63,7 @@ frappe.ui.form.on("Leave Allocation", {
},
leave_type: function(frm) {
- frm.trigger("leave_policy")
+ frm.trigger("leave_policy");
frm.trigger("calculate_total_leaves_allocated");
},
@@ -83,13 +83,12 @@ frappe.ui.form.on("Leave Allocation", {
leave_policy: function(frm) {
if(frm.doc.leave_policy && frm.doc.leave_type) {
- frappe.db.get_value("Leave Policy Detail",
- {'parent': frm.doc.leave_policy, 'leave_type': frm.doc.leave_type},
- 'annual_allocation', (r) => {
- if (r && !r.exc) {
- frm.set_value("new_leaves_allocated", flt(r.annual_allocation));
- }
- }, "Leave Policy")
+ frappe.db.get_value("Leave Policy Detail",{
+ 'parent': frm.doc.leave_policy,
+ 'leave_type': frm.doc.leave_type
+ }, 'annual_allocation', (r) => {
+ if (r && !r.exc) frm.set_value("new_leaves_allocated", flt(r.annual_allocation));
+ }, "Leave Policy");
}
},
calculate_total_leaves_allocated: function(frm) {
diff --git a/erpnext/hr/doctype/leave_application/leave_application.js b/erpnext/hr/doctype/leave_application/leave_application.js
index 2076ccd22a..5534cec061 100755
--- a/erpnext/hr/doctype/leave_application/leave_application.js
+++ b/erpnext/hr/doctype/leave_application/leave_application.js
@@ -60,7 +60,7 @@ frappe.ui.form.on("Leave Application", {
}
}
});
- frm.trigger("create_dashboard")
+ frm.trigger("create_dashboard");
}
},
From 87adaed9336dd2692b185f9ece5df93877990775 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Fri, 14 Jun 2019 15:13:53 +0530
Subject: [PATCH 072/484] fix: generate ledger entries for all leave
transactions
---
.../v12_0/generate_leave_ledger_entries.py | 106 +++++++-----------
1 file changed, 42 insertions(+), 64 deletions(-)
diff --git a/erpnext/patches/v12_0/generate_leave_ledger_entries.py b/erpnext/patches/v12_0/generate_leave_ledger_entries.py
index 065a0137a5..07e53c7450 100644
--- a/erpnext/patches/v12_0/generate_leave_ledger_entries.py
+++ b/erpnext/patches/v12_0/generate_leave_ledger_entries.py
@@ -3,84 +3,70 @@
from __future__ import unicode_literals
import frappe
+from frappe.utils import getdate
def execute():
""" Generates leave ledger entries for leave allocation/application/encashment
for last allocation """
- frappe.reload_doc("HR","doctype", "Leave Ledger Entry")
- frappe.reload_doc("HR","doctype", "Leave Encashment")
+ frappe.reload_doc("HR", "doctype", "Leave Ledger Entry")
+ frappe.reload_doc("HR", "doctype", "Leave Encashment")
if frappe.db.a_row_exists("Leave Ledger Entry"):
return
- allocation_list = get_allocation_records()
- generate_allocation_ledger_entries(allocation_list)
- generate_application_leave_ledger_entries(allocation_list)
- generate_encashment_leave_ledger_entries(allocation_list)
+ generate_allocation_ledger_entries()
+ generate_application_leave_ledger_entries()
+ generate_encashment_leave_ledger_entries()
-def generate_allocation_ledger_entries(allocation_list):
+def generate_allocation_ledger_entries():
''' fix ledger entries for missing leave allocation transaction '''
- from erpnext.hr.doctype.leave_allocation.leave_allocation import LeaveAllocation
+ allocation_list = get_allocation_records()
for allocation in allocation_list:
if not frappe.db.exists("Leave Ledger Entry", {'transaction_type': 'Leave Allocation', 'transaction_name': allocation.name}):
allocation.update(dict(doctype="Leave Allocation"))
- leave_allocation = LeaveAllocation(allocation)
- leave_allocation.create_leave_ledger_entry()
+ allocation_obj = frappe.get_doc(allocation)
+ allocation_obj.create_leave_ledger_entry()
+ if allocation.to_date <= getdate():
+ allocation_obj.expire_allocation()
-def generate_application_leave_ledger_entries(allocation_list):
+
+def generate_application_leave_ledger_entries():
''' fix ledger entries for missing leave application transaction '''
- from erpnext.hr.doctype.leave_application.leave_application import LeaveApplication
+ leave_applications = get_leaves_application_records()
- leave_applications = get_leaves_application_records(allocation_list)
-
- for record in leave_applications:
+ for application in leave_applications:
if not frappe.db.exists("Leave Ledger Entry", {'transaction_type': 'Leave Application', 'transaction_name': record.name}):
- record.update(dict(doctype="Leave Application"))
- leave_application = LeaveApplication(record)
- leave_application.create_leave_ledger_entry()
+ application.update(dict(doctype="Leave Application"))
+ frappe.get_doc(application).create_leave_ledger_entry()
-def generate_encashment_leave_ledger_entries(allocation_list):
+def generate_encashment_leave_ledger_entries():
''' fix ledger entries for missing leave encashment transaction '''
- from erpnext.hr.doctype.leave_encashment.leave_encashment import LeaveEncashment
+ leave_encashments = get_leave_encashment_records()
- leave_encashments = get_leave_encashment_records(allocation_list)
-
- for record in leave_encashments:
+ for encashment in leave_encashments:
if not frappe.db.exists("Leave Ledger Entry", {'transaction_type': 'Leave Encashment', 'transaction_name': record.name}):
- record.update(dict(doctype="Leave Encashment"))
- leave_encashment = LeaveEncashment(record)
- leave_encashment.create_leave_ledger_entry()
+ encashment.update(dict(doctype="Leave Encashment"))
+ frappe.get_doc(encashment).create_leave_ledger_entry()
def get_allocation_records():
return frappe.db.sql("""
- WITH allocation_values AS (
- SELECT
- DISTINCT name,
- employee,
- leave_type,
- new_leaves_allocated,
- carry_forwarded_leaves,
- from_date,
- to_date,
- carry_forward,
- RANK() OVER(
- PARTITION BY employee, leave_type
- ORDER BY to_date DESC
- ) as allocation
- FROM `tabLeave Allocation`
- )
SELECT
- *
- FROM
- `allocation_values`
+ DISTINCT name,
+ employee,
+ leave_type,
+ new_leaves_allocated,
+ carry_forwarded_leaves,
+ from_date,
+ to_date,
+ carry_forward
+ FROM `tabLeave Allocation`
WHERE
- allocation=1
+ docstatus=1
+ ORDER BY to_date ASC
""", as_dict=1)
-def get_leaves_application_records(allocation_list):
- leave_applications = []
- for allocation in allocation_list:
- leave_applications += frappe.db.sql("""
+def get_leaves_application_records():
+ return frappe.db.sql("""
SELECT
DISTINCT name,
employee,
@@ -90,16 +76,11 @@ def get_leaves_application_records(allocation_list):
to_date
FROM `tabLeave Application`
WHERE
- from_date >= %s
- AND leave_type = %s
- AND employee = %s
- """, (allocation.from_date, allocation.leave_type, allocation.employee), as_dict=1)
- return leave_applications
+ docstatus=1
+ """, as_dict=1)
-def get_leave_encashment_records(allocation_list):
- leave_encashments = []
- for allocation in allocation_list:
- leave_encashments += frappe.db.sql("""
+def get_leave_encashment_records():
+ return frappe.db.sql("""
SELECT
DISTINCT name,
employee,
@@ -108,8 +89,5 @@ def get_leave_encashment_records(allocation_list):
encashment_date
FROM `tabLeave Encashment`
WHERE
- leave_type = %s
- AND employee = %s
- AND encashment_date >= %s
- """, (allocation.leave_type, allocation.employee, allocation.from_date), as_dict=1)
- return leave_encashments
\ No newline at end of file
+ AND docstatus=1
+ """, as_dict=1)
\ No newline at end of file
From 24fbe23c8d4c1a9553f2bc3721f98d25600c5785 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Fri, 14 Jun 2019 15:36:26 +0530
Subject: [PATCH 073/484] fix: add indicators for expire in the leave
allocation list
---
.../leave_allocation/leave_allocation_list.js | 12 +++++++
.../leave_application/leave_application.js | 21 +++++-------
.../leave_application/leave_application.json | 33 +------------------
.../leave_application/leave_application.py | 1 -
4 files changed, 21 insertions(+), 46 deletions(-)
create mode 100644 erpnext/hr/doctype/leave_allocation/leave_allocation_list.js
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation_list.js b/erpnext/hr/doctype/leave_allocation/leave_allocation_list.js
new file mode 100644
index 0000000000..946b4f8492
--- /dev/null
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation_list.js
@@ -0,0 +1,12 @@
+// Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors
+// License: GNU General Public License v3. See license.txt
+
+// render
+frappe.listview_settings['Leave Allocation'] = {
+ get_indicator: function(doc) {
+ if(doc.status==="Expired") {
+ return [__("Expired"), "darkgrey", "status, =, Expired"];
+ }
+ },
+ right_column: "grand_total"
+};
diff --git a/erpnext/hr/doctype/leave_application/leave_application.js b/erpnext/hr/doctype/leave_application/leave_application.js
index 5534cec061..b81e615b72 100755
--- a/erpnext/hr/doctype/leave_application/leave_application.js
+++ b/erpnext/hr/doctype/leave_application/leave_application.js
@@ -53,27 +53,23 @@ frappe.ui.form.on("Leave Application", {
},
callback: function(r) {
if (!r.exc && r.message['leave_allocation']) {
- frm.set_value('leave_details', JSON.stringify(r.message['leave_allocation']));
+ leave_details = r.message['leave_allocation'];
}
if (!r.exc && r.message['leave_approver']) {
frm.set_value('leave_approver', r.message['leave_approver']);
}
}
});
- frm.trigger("create_dashboard");
+ $("div").remove(".form-dashboard-section");
+ frm.dashboard.add_section(
+ frappe.render_template('leave_application_dashboard', {
+ data: leave_details
+ })
+ );
+ frm.dashboard.show();
}
},
- create_dashboard: function(frm) {
- $("div").remove(".form-dashboard-section");
- let section = frm.dashboard.add_section(
- frappe.render_template('leave_application_dashboard', {
- data: JSON.parse(frm.doc.leave_details)
- })
- );
- frm.dashboard.show();
- },
-
refresh: function(frm) {
if (frm.is_new()) {
frm.trigger("calculate_total_days");
@@ -98,7 +94,6 @@ frappe.ui.form.on("Leave Application", {
};
frappe.set_route("query-report", "Employee Leave Balance");
});
- frm.trigger("create_dashboard");
}
},
diff --git a/erpnext/hr/doctype/leave_application/leave_application.json b/erpnext/hr/doctype/leave_application/leave_application.json
index c59449f850..60efb33ca4 100644
--- a/erpnext/hr/doctype/leave_application/leave_application.json
+++ b/erpnext/hr/doctype/leave_application/leave_application.json
@@ -653,37 +653,6 @@
"translatable": 0,
"unique": 0
},
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "leave_details",
- "fieldtype": "Small Text",
- "hidden": 1,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Leave Details",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
@@ -982,7 +951,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 3,
- "modified": "2019-05-31 11:30:14.745572",
+ "modified": "2019-06-01 11:30:14.745572",
"modified_by": "Administrator",
"module": "HR",
"name": "Leave Application",
diff --git a/erpnext/hr/doctype/leave_application/leave_application.py b/erpnext/hr/doctype/leave_application/leave_application.py
index f6550f0dbe..f87f7d53ef 100755
--- a/erpnext/hr/doctype/leave_application/leave_application.py
+++ b/erpnext/hr/doctype/leave_application/leave_application.py
@@ -426,7 +426,6 @@ def get_leave_details(employee, date):
"leaves_taken": leaves_taken,
"pending_leaves": leaves_pending,
"remaining_leaves": remaining_leaves}
- leave_details = leave_allocation
ret = {
'leave_allocation': leave_allocation,
From fefdac432ce02d07b24fe3d757ce97db2a8c483a Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Fri, 14 Jun 2019 15:39:50 +0530
Subject: [PATCH 074/484] refactor: add json changes
---
.../leave_allocation/leave_allocation.json | 646 +------------
.../leave_application/leave_application.json | 915 ++----------------
2 files changed, 123 insertions(+), 1438 deletions(-)
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.json b/erpnext/hr/doctype/leave_allocation/leave_allocation.json
index 125fb3150b..41d864d912 100644
--- a/erpnext/hr/doctype/leave_allocation/leave_allocation.json
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.json
@@ -1,750 +1,212 @@
{
- "allow_copy": 0,
- "allow_events_in_timeline": 0,
- "allow_guest_to_view": 0,
"allow_import": 1,
- "allow_rename": 0,
"autoname": "naming_series:",
- "beta": 0,
"creation": "2013-02-20 19:10:38",
- "custom": 0,
- "docstatus": 0,
"doctype": "DocType",
"document_type": "Setup",
- "editable_grid": 0,
"engine": "InnoDB",
+ "field_order": [
+ "naming_series",
+ "employee",
+ "employee_name",
+ "department",
+ "column_break1",
+ "leave_type",
+ "from_date",
+ "to_date",
+ "section_break_6",
+ "new_leaves_allocated",
+ "carry_forward",
+ "carry_forwarded_leaves",
+ "total_leaves_allocated",
+ "total_leaves_encashed",
+ "column_break_10",
+ "compensatory_request",
+ "leave_period",
+ "leave_policy",
+ "status",
+ "amended_from",
+ "notes",
+ "description"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "",
"fieldname": "naming_series",
"fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Series",
- "length": 0,
"no_copy": 1,
"options": "HR-LAL-.YYYY.-",
- "permlevel": 0,
- "precision": "",
"print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
"reqd": 1,
- "search_index": 0,
- "set_only_once": 1,
- "translatable": 0,
- "unique": 0
+ "set_only_once": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "employee",
"fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
"in_global_search": 1,
"in_list_view": 1,
"in_standard_filter": 1,
"label": "Employee",
- "length": 0,
- "no_copy": 0,
"oldfieldname": "employee",
"oldfieldtype": "Link",
"options": "Employee",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
"reqd": 1,
- "search_index": 1,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "search_index": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fetch_from": "employee.employee_name",
"fieldname": "employee_name",
"fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
"in_global_search": 1,
"in_list_view": 1,
- "in_standard_filter": 0,
"label": "Employee Name",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
"read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 1,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "search_index": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fetch_from": "employee.department",
"fieldname": "department",
"fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Department",
- "length": 0,
- "no_copy": 0,
"options": "Department",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "read_only": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "column_break1",
"fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0,
"width": "50%"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "leave_type",
"fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 1,
"label": "Leave Type",
- "length": 0,
- "no_copy": 0,
"oldfieldname": "leave_type",
"oldfieldtype": "Link",
"options": "Leave Type",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
"reqd": 1,
- "search_index": 1,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "search_index": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "from_date",
"fieldtype": "Date",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "From Date",
- "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": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "reqd": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "to_date",
"fieldtype": "Date",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "To Date",
- "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": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "reqd": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "section_break_6",
"fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Allocation",
- "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,
- "translatable": 0,
- "unique": 0
+ "label": "Allocation"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
"bold": 1,
- "collapsible": 0,
- "columns": 0,
"fieldname": "new_leaves_allocated",
"fieldtype": "Float",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "New Leaves Allocated",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
+ "label": "New Leaves Allocated"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "",
+ "default": "0",
"fieldname": "carry_forward",
"fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Add unused leaves from previous allocations",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
+ "label": "Add unused leaves from previous allocations"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"depends_on": "carry_forward",
"fieldname": "carry_forwarded_leaves",
"fieldtype": "Float",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Unused leaves",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "read_only": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
"allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "total_leaves_allocated",
"fieldtype": "Float",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Total Leaves Allocated",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
"read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "reqd": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"depends_on": "eval:doc.total_leaves_encashed>0",
"fieldname": "total_leaves_encashed",
"fieldtype": "Float",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Total Leaves Encashed",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "read_only": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "column_break_10",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 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,
- "translatable": 0,
- "unique": 0
+ "fieldtype": "Column Break"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "compensatory_request",
"fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Compensatory Leave Request",
- "length": 0,
- "no_copy": 0,
"options": "Compensatory Leave Request",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "read_only": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "leave_period",
"fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
"in_standard_filter": 1,
"label": "Leave Period",
- "length": 0,
- "no_copy": 0,
"options": "Leave Period",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "read_only": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fetch_from": "employee.leave_policy",
"fieldname": "leave_policy",
"fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
"in_standard_filter": 1,
"label": "Leave Policy",
- "length": 0,
- "no_copy": 0,
"options": "Leave Policy",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "read_only": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "status",
"fieldtype": "Select",
"hidden": 1,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
"in_standard_filter": 1,
"label": "Status",
- "length": 0,
- "no_copy": 0,
"options": "Active\nExpired",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "read_only": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "amended_from",
"fieldtype": "Link",
- "hidden": 0,
"ignore_user_permissions": 1,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Amended From",
- "length": 0,
"no_copy": 1,
"oldfieldname": "amended_from",
"oldfieldtype": "Data",
"options": "Leave Allocation",
- "permlevel": 0,
"print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "read_only": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
"collapsible": 1,
- "columns": 0,
"fieldname": "notes",
"fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Notes",
- "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,
- "translatable": 0,
- "unique": 0
+ "label": "Notes"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "description",
"fieldtype": "Small Text",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Description",
- "length": 0,
- "no_copy": 0,
"oldfieldname": "reason",
"oldfieldtype": "Small Text",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0,
"width": "300px"
}
],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
"icon": "fa fa-ok",
"idx": 1,
- "image_view": 0,
- "in_create": 0,
"is_submittable": 1,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2019-05-31 11:28:09.360525",
+ "modified": "2019-06-14 15:39:02.898695",
"modified_by": "Administrator",
"module": "HR",
"name": "Leave Allocation",
@@ -756,15 +218,10 @@
"create": 1,
"delete": 1,
"email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "HR User",
- "set_user_permissions": 0,
"share": 1,
"submit": 1,
"write": 1
@@ -776,28 +233,19 @@
"delete": 1,
"email": 1,
"export": 1,
- "if_owner": 0,
"import": 1,
- "permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "HR Manager",
- "set_user_permissions": 0,
"share": 1,
"submit": 1,
"write": 1
}
],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
"search_fields": "employee,employee_name,leave_type,total_leaves_allocated",
"show_name_in_global_search": 1,
"sort_field": "modified",
"sort_order": "DESC",
- "timeline_field": "employee",
- "track_changes": 0,
- "track_seen": 0,
- "track_views": 0
+ "timeline_field": "employee"
}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/leave_application/leave_application.json b/erpnext/hr/doctype/leave_application/leave_application.json
index 60efb33ca4..f8344b53e0 100644
--- a/erpnext/hr/doctype/leave_application/leave_application.json
+++ b/erpnext/hr/doctype/leave_application/leave_application.json
@@ -1,979 +1,274 @@
{
- "allow_copy": 0,
- "allow_events_in_timeline": 0,
- "allow_guest_to_view": 0,
"allow_import": 1,
- "allow_rename": 0,
"autoname": "naming_series:",
- "beta": 0,
"creation": "2013-02-20 11:18:11",
- "custom": 0,
"description": "Apply / Approve Leaves",
- "docstatus": 0,
"doctype": "DocType",
"document_type": "Document",
- "editable_grid": 0,
+ "engine": "InnoDB",
+ "field_order": [
+ "naming_series",
+ "employee",
+ "employee_name",
+ "column_break_4",
+ "leave_type",
+ "department",
+ "leave_balance",
+ "section_break_5",
+ "from_date",
+ "to_date",
+ "half_day",
+ "half_day_date",
+ "total_leave_days",
+ "column_break1",
+ "description",
+ "section_break_7",
+ "leave_approver",
+ "leave_approver_name",
+ "column_break_18",
+ "status",
+ "leave_details",
+ "sb10",
+ "posting_date",
+ "company",
+ "follow_via_email",
+ "column_break_17",
+ "salary_slip",
+ "letter_head",
+ "color",
+ "amended_from"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "",
"fieldname": "naming_series",
"fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Series",
- "length": 0,
"no_copy": 1,
"options": "HR-LAP-.YYYY.-",
- "permlevel": 0,
- "precision": "",
"print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
"reqd": 1,
- "search_index": 0,
- "set_only_once": 1,
- "translatable": 0,
- "unique": 0
+ "set_only_once": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "employee",
"fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
"in_global_search": 1,
- "in_list_view": 0,
"in_standard_filter": 1,
"label": "Employee",
- "length": 0,
- "no_copy": 0,
"options": "Employee",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
"reqd": 1,
- "search_index": 1,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "search_index": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "employee_name",
"fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
"in_global_search": 1,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Employee Name",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "read_only": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "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_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 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,
- "translatable": 0,
- "unique": 0
+ "fieldtype": "Column Break"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "leave_type",
"fieldtype": "Link",
- "hidden": 0,
"ignore_user_permissions": 1,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
"in_standard_filter": 1,
"label": "Leave Type",
- "length": 0,
- "no_copy": 0,
"options": "Leave Type",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
"reqd": 1,
- "search_index": 1,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "search_index": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fetch_from": "employee.department",
"fieldname": "department",
"fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Department",
- "length": 0,
- "no_copy": 0,
"options": "Department",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "read_only": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "leave_balance",
"fieldtype": "Float",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Leave Balance Before Application",
- "length": 0,
"no_copy": 1,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "read_only": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "section_break_5",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 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,
- "translatable": 0,
- "unique": 0
+ "fieldtype": "Section Break"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "from_date",
"fieldtype": "Date",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 1,
"label": "From Date",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
"reqd": 1,
- "search_index": 1,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "search_index": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "to_date",
"fieldtype": "Date",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
"in_standard_filter": 1,
"label": "To Date",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
"reqd": 1,
- "search_index": 1,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "search_index": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
+ "default": "0",
"fieldname": "half_day",
"fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Half Day",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
+ "label": "Half Day"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"depends_on": "eval:doc.half_day && (doc.from_date != doc.to_date)",
"fieldname": "half_day_date",
"fieldtype": "Date",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Half Day Date",
- "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,
- "translatable": 0,
- "unique": 0
+ "label": "Half Day Date"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "total_leave_days",
"fieldtype": "Float",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
"in_list_view": 1,
- "in_standard_filter": 0,
"label": "Total Leave Days",
- "length": 0,
"no_copy": 1,
- "permlevel": 0,
"precision": "1",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "read_only": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "column_break1",
"fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
"print_width": "50%",
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
"width": "50%"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "description",
"fieldtype": "Small Text",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Reason",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "reqd": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "section_break_7",
"fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Approval",
- "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,
- "translatable": 0,
- "unique": 0
+ "label": "Approval"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "leave_approver",
"fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Leave Approver",
- "length": 0,
- "no_copy": 0,
- "options": "User",
- "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,
- "translatable": 0,
- "unique": 0
+ "options": "User"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "leave_approver_name",
"fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Leave Approver Name",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "read_only": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "column_break_18",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 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,
- "translatable": 0,
- "unique": 0
+ "fieldtype": "Column Break"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"default": "Open",
"fieldname": "status",
"fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
"in_standard_filter": 1,
"label": "Status",
- "length": 0,
"no_copy": 1,
- "options": "Open\nApproved\nRejected\nCancelled",
- "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,
- "translatable": 0,
- "unique": 0
+ "options": "Open\nApproved\nRejected\nCancelled"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "sb10",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
+ "fieldtype": "Section Break"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"default": "Today",
"fieldname": "posting_date",
"fieldtype": "Date",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Posting Date",
- "length": 0,
"no_copy": 1,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "reqd": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "company",
"fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Company",
- "length": 0,
- "no_copy": 0,
"options": "Company",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
"remember_last_selected_value": 1,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "reqd": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
"allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"default": "1",
"fieldname": "follow_via_email",
"fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Follow via Email",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
+ "print_hide": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "column_break_17",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
+ "fieldtype": "Column Break"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "salary_slip",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Salary Slip",
- "length": 0,
- "no_copy": 0,
- "options": "Salary Slip",
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "salary_slip",
+ "fieldtype": "Link",
+ "label": "Salary Slip",
+ "options": "Salary Slip",
+ "print_hide": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
"allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "letter_head",
"fieldtype": "Link",
- "hidden": 0,
"ignore_user_permissions": 1,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Letter Head",
- "length": 0,
- "no_copy": 0,
"options": "Letter Head",
- "permlevel": 0,
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
+ "print_hide": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
"allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "color",
"fieldtype": "Color",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Color",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
+ "print_hide": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "amended_from",
"fieldtype": "Link",
- "hidden": 0,
"ignore_user_permissions": 1,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Amended From",
- "length": 0,
"no_copy": 1,
"options": "Leave Application",
- "permlevel": 0,
"print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "read_only": 1
+ },
+ {
+ "fieldname": "leave_details",
+ "fieldtype": "Small Text",
+ "hidden": 1,
+ "label": "Leave Details"
}
],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
"icon": "fa fa-calendar",
"idx": 1,
- "image_view": 0,
- "in_create": 0,
"is_submittable": 1,
- "issingle": 0,
- "istable": 0,
"max_attachments": 3,
- "modified": "2019-06-01 11:30:14.745572",
+ "modified": "2019-06-14 15:37:45.988552",
"modified_by": "Administrator",
"module": "HR",
"name": "Leave Application",
"owner": "Administrator",
"permissions": [
{
- "amend": 0,
- "cancel": 0,
"create": 1,
- "delete": 0,
"email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Employee",
- "set_user_permissions": 0,
"share": 1,
- "submit": 0,
"write": 1
},
{
@@ -983,9 +278,6 @@
"delete": 1,
"email": 1,
"export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
@@ -996,23 +288,9 @@
"write": 1
},
{
- "amend": 0,
- "cancel": 0,
- "create": 0,
- "delete": 0,
- "email": 0,
- "export": 0,
- "if_owner": 0,
- "import": 0,
"permlevel": 1,
- "print": 0,
"read": 1,
- "report": 0,
- "role": "All",
- "set_user_permissions": 0,
- "share": 0,
- "submit": 0,
- "write": 0
+ "role": "All"
},
{
"amend": 1,
@@ -1020,10 +298,6 @@
"create": 1,
"delete": 1,
"email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
@@ -1036,71 +310,34 @@
{
"amend": 1,
"cancel": 1,
- "create": 0,
"delete": 1,
"email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Leave Approver",
- "set_user_permissions": 0,
"share": 1,
"submit": 1,
"write": 1
},
{
- "amend": 0,
- "cancel": 0,
- "create": 0,
- "delete": 0,
- "email": 0,
- "export": 0,
- "if_owner": 0,
- "import": 0,
"permlevel": 1,
- "print": 0,
"read": 1,
"report": 1,
"role": "HR User",
- "set_user_permissions": 0,
- "share": 0,
- "submit": 0,
"write": 1
},
{
- "amend": 0,
- "cancel": 0,
- "create": 0,
- "delete": 0,
- "email": 0,
- "export": 0,
- "if_owner": 0,
- "import": 0,
"permlevel": 1,
- "print": 0,
"read": 1,
"report": 1,
"role": "Leave Approver",
- "set_user_permissions": 0,
- "share": 0,
- "submit": 0,
"write": 1
}
],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
"search_fields": "employee,employee_name,leave_type,from_date,to_date,total_leave_days",
- "show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
"timeline_field": "employee",
- "title_field": "employee_name",
- "track_changes": 0,
- "track_seen": 0,
- "track_views": 0
+ "title_field": "employee_name"
}
\ No newline at end of file
From 1db0fc91a5d6b3d07ddff51877dc80297753327f Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Fri, 14 Jun 2019 15:48:31 +0530
Subject: [PATCH 075/484] fix: check generated ledger entries to avoid overlap
---
erpnext/patches/v12_0/generate_leave_ledger_entries.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/erpnext/patches/v12_0/generate_leave_ledger_entries.py b/erpnext/patches/v12_0/generate_leave_ledger_entries.py
index 07e53c7450..5b71c167b6 100644
--- a/erpnext/patches/v12_0/generate_leave_ledger_entries.py
+++ b/erpnext/patches/v12_0/generate_leave_ledger_entries.py
@@ -35,7 +35,7 @@ def generate_application_leave_ledger_entries():
leave_applications = get_leaves_application_records()
for application in leave_applications:
- if not frappe.db.exists("Leave Ledger Entry", {'transaction_type': 'Leave Application', 'transaction_name': record.name}):
+ if not frappe.db.exists("Leave Ledger Entry", {'transaction_type': 'Leave Application', 'transaction_name': application.name}):
application.update(dict(doctype="Leave Application"))
frappe.get_doc(application).create_leave_ledger_entry()
@@ -44,7 +44,7 @@ def generate_encashment_leave_ledger_entries():
leave_encashments = get_leave_encashment_records()
for encashment in leave_encashments:
- if not frappe.db.exists("Leave Ledger Entry", {'transaction_type': 'Leave Encashment', 'transaction_name': record.name}):
+ if not frappe.db.exists("Leave Ledger Entry", {'transaction_type': 'Leave Encashment', 'transaction_name': encashment.name}):
encashment.update(dict(doctype="Leave Encashment"))
frappe.get_doc(encashment).create_leave_ledger_entry()
From 12a2b21465303b51110cdae94fe1c8c72d1e041a Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Wed, 19 Jun 2019 13:00:52 +0530
Subject: [PATCH 076/484] fix: track status for pending leaves
---
.../hr/doctype/leave_allocation/leave_allocation_list.js | 7 +++----
erpnext/hr/doctype/leave_application/leave_application.py | 1 +
erpnext/patches/v12_0/generate_leave_ledger_entries.py | 2 +-
3 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation_list.js b/erpnext/hr/doctype/leave_allocation/leave_allocation_list.js
index 946b4f8492..3ea0e2403f 100644
--- a/erpnext/hr/doctype/leave_allocation/leave_allocation_list.js
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation_list.js
@@ -4,9 +4,8 @@
// render
frappe.listview_settings['Leave Allocation'] = {
get_indicator: function(doc) {
- if(doc.status==="Expired") {
- return [__("Expired"), "darkgrey", "status, =, Expired"];
- }
+ if(doc.status==="Expired") {
+ return [__("Expired"), "darkgrey", "status, =, Expired"];
+ }
},
- right_column: "grand_total"
};
diff --git a/erpnext/hr/doctype/leave_application/leave_application.py b/erpnext/hr/doctype/leave_application/leave_application.py
index f87f7d53ef..d08c9edb1f 100755
--- a/erpnext/hr/doctype/leave_application/leave_application.py
+++ b/erpnext/hr/doctype/leave_application/leave_application.py
@@ -496,6 +496,7 @@ def get_pending_leaves_for_period(employee, leave_type, from_date, to_date):
"leave_type": leave_type,
"from_date": ("<=", from_date),
"to_date": (">=", to_date),
+ "status": "Open"
}, fieldname=['SUM(total_leave_days)']) or flt(0)
def get_remaining_leaves(allocation, leaves_taken, date, expiry):
diff --git a/erpnext/patches/v12_0/generate_leave_ledger_entries.py b/erpnext/patches/v12_0/generate_leave_ledger_entries.py
index 5b71c167b6..ffb2e3fba5 100644
--- a/erpnext/patches/v12_0/generate_leave_ledger_entries.py
+++ b/erpnext/patches/v12_0/generate_leave_ledger_entries.py
@@ -89,5 +89,5 @@ def get_leave_encashment_records():
encashment_date
FROM `tabLeave Encashment`
WHERE
- AND docstatus=1
+ docstatus=1
""", as_dict=1)
\ No newline at end of file
From bd999b09089c9f5cea8307cfe18a12d8b0f1952a Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Fri, 21 Jun 2019 00:49:48 +0530
Subject: [PATCH 077/484] fix: minor changes
---
.../leave_allocation/leave_allocation.js | 15 +++--------
.../leave_allocation/leave_allocation.py | 15 ++++++++++-
.../leave_application/leave_application.js | 3 ++-
.../leave_application/leave_application.py | 23 +++++++++--------
.../test_leave_application.py | 2 +-
.../leave_ledger_entry.json | 2 +-
.../leave_ledger_entry/leave_ledger_entry.py | 25 ++++++++++++++++---
7 files changed, 55 insertions(+), 30 deletions(-)
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.js b/erpnext/hr/doctype/leave_allocation/leave_allocation.js
index a620d9e081..8f734ac1bc 100755
--- a/erpnext/hr/doctype/leave_allocation/leave_allocation.js
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.js
@@ -94,19 +94,10 @@ frappe.ui.form.on("Leave Allocation", {
calculate_total_leaves_allocated: function(frm) {
if (cint(frm.doc.carry_forward) == 1 && frm.doc.leave_type && frm.doc.employee) {
return frappe.call({
- method: "erpnext.hr.doctype.leave_allocation.leave_allocation.get_carry_forwarded_leaves",
- args: {
- "employee": frm.doc.employee,
- "date": frm.doc.from_date,
- "leave_type": frm.doc.leave_type,
- "carry_forward": frm.doc.carry_forward
- },
+ method: "set_total_leaves_allocated",
+ doc: frm.doc,
callback: function(r) {
- if (!r.exc && r.message) {
- frm.set_value('carry_forwarded_leaves', r.message);
- frm.set_value("total_leaves_allocated",
- flt(r.message) + flt(frm.doc.new_leaves_allocated));
- }
+ frm.refresh_fields();
}
})
} else if (cint(frm.doc.carry_forward) == 0) {
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.py b/erpnext/hr/doctype/leave_allocation/leave_allocation.py
index 72ea2733b0..df479e72e9 100755
--- a/erpnext/hr/doctype/leave_allocation/leave_allocation.py
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.py
@@ -115,7 +115,7 @@ class LeaveAllocation(Document):
args = dict(
leaves=self.carry_forwarded_leaves,
from_date=self.from_date,
- to_date=add_days(self.from_date, expiry_days) if expiry_days else self.to_date,
+ to_date=add_days(self.from_date, expiry_days - 1) if expiry_days else self.to_date,
is_carry_forward=1
)
create_leave_ledger_entry(self, args, submit)
@@ -132,11 +132,13 @@ class LeaveAllocation(Document):
''' expires allocation '''
date = self.to_date if current else self.from_date
leaves = get_unused_leaves(self.employee, self.leave_type, date)
+ ref_name = self.name if current else self.get_previous_allocation()
if leaves:
expiry_date = today() if current else add_days(self.from_date, -1)
args = dict(
leaves=flt(leaves) * -1,
+ transaction_name=ref_name,
from_date=expiry_date,
to_date=expiry_date,
is_carry_forward=0,
@@ -147,6 +149,17 @@ class LeaveAllocation(Document):
if current:
frappe.db.set_value("Leave Allocation", self.name, "status", "Expired")
+ def get_previous_allocation(self):
+ return frappe.db.get_value("Leave Allocation",
+ filters={
+ 'to_date': ("<", self.from_date),
+ 'leave_type': self.leave_type,
+ 'employee': self.employee,
+ 'docstatus': 1
+ },
+ order_by='to_date DESC',
+ fieldname=['name'])
+
def get_leave_allocation_for_period(employee, leave_type, from_date, to_date):
leave_allocated = 0
leave_allocations = frappe.db.sql("""
diff --git a/erpnext/hr/doctype/leave_application/leave_application.js b/erpnext/hr/doctype/leave_application/leave_application.js
index b81e615b72..44a60b0259 100755
--- a/erpnext/hr/doctype/leave_application/leave_application.js
+++ b/erpnext/hr/doctype/leave_application/leave_application.js
@@ -49,7 +49,7 @@ frappe.ui.form.on("Leave Application", {
async: false,
args: {
employee: frm.doc.employee,
- date: frm.doc.posting_date
+ date: frm.doc.from_date? frm.doc.from_date:frm.doc.posting_date
},
callback: function(r) {
if (!r.exc && r.message['leave_allocation']) {
@@ -124,6 +124,7 @@ frappe.ui.form.on("Leave Application", {
},
from_date: function(frm) {
+ frm.trigger("make_dashboard");
frm.trigger("half_day_datepicker");
frm.trigger("calculate_total_days");
},
diff --git a/erpnext/hr/doctype/leave_application/leave_application.py b/erpnext/hr/doctype/leave_application/leave_application.py
index d08c9edb1f..7aa3e95862 100755
--- a/erpnext/hr/doctype/leave_application/leave_application.py
+++ b/erpnext/hr/doctype/leave_application/leave_application.py
@@ -417,9 +417,9 @@ def get_leave_details(employee, date):
allocation = allocation_records.get(d, frappe._dict())
remaining_leaves = get_leave_balance_on(employee, d, date, to_date = allocation.to_date,
consider_all_leaves_in_the_allocation_period=True)
- date = allocation.to_date
- leaves_taken = get_leaves_for_period(employee, d, allocation.from_date, date) * -1
- leaves_pending = get_pending_leaves_for_period(employee, d, allocation.from_date, date)
+ end_date = allocation.to_date
+ leaves_taken = get_leaves_for_period(employee, d, allocation.from_date, end_date) * -1
+ leaves_pending = get_pending_leaves_for_period(employee, d, allocation.from_date, end_date)
leave_allocation[d] = {
"total_leaves": allocation.total_leaves_allocated,
@@ -435,14 +435,17 @@ def get_leave_details(employee, date):
return ret
@frappe.whitelist()
-def get_leave_balance_on(employee, leave_type, date, to_date=nowdate(), allocation_records=None,
- consider_all_leaves_in_the_allocation_period=False):
- ''' Returns leave balance till date and fetches expiry date based on to_date
- to calculate minimum remaining leave balance '''
-
- if not allocation_records:
- allocation_records = get_leave_allocation_records(employee, date, leave_type)
+def get_leave_balance_on(employee, leave_type, date, to_date=nowdate(), consider_all_leaves_in_the_allocation_period=False):
+ '''
+ Returns leave balance on date
+ :param employee: employee name
+ :param leave_type: leave type
+ :param date: date to check balance on
+ :param to_date: future date to check for allocation expiry
+ :param consider_all_leaves_in_the_allocation_period: consider all leaves taken till the allocation end date
+ '''
+ allocation_records = get_leave_allocation_records(employee, date, leave_type)
allocation = allocation_records.get(leave_type, frappe._dict())
end_date = allocation.to_date if consider_all_leaves_in_the_allocation_period else date
diff --git a/erpnext/hr/doctype/leave_application/test_leave_application.py b/erpnext/hr/doctype/leave_application/test_leave_application.py
index 54216ee3c7..ca6b99ca12 100644
--- a/erpnext/hr/doctype/leave_application/test_leave_application.py
+++ b/erpnext/hr/doctype/leave_application/test_leave_application.py
@@ -557,7 +557,7 @@ def create_carry_forwarded_allocation(employee, leave_type):
leave_type="_Test_CF_leave_expiry",
employee=employee.name,
employee_name=employee.employee_name,
- from_date=add_days(nowdate(), -85),
+ from_date=add_days(nowdate(), -84),
to_date=add_days(nowdate(), 100),
carry_forward=1)
leave_allocation.submit()
diff --git a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.json b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.json
index 0166e43c0f..c11422211c 100644
--- a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.json
+++ b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.json
@@ -101,7 +101,7 @@
],
"in_create": 1,
"is_submittable": 1,
- "modified": "2019-06-06 20:33:37.531161",
+ "modified": "2019-06-21 00:37:07.782810",
"modified_by": "Administrator",
"module": "HR",
"name": "Leave Ledger Entry",
diff --git a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
index 6142dcf648..a73f10adb8 100644
--- a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
+++ b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
@@ -6,7 +6,7 @@ from __future__ import unicode_literals
import frappe
from frappe.model.document import Document
from frappe import _
-from frappe.utils import add_days, today, flt
+from frappe.utils import add_days, today, flt, DATE_FORMAT
class LeaveLedgerEntry(Document):
def on_cancel(self):
@@ -49,14 +49,31 @@ def create_leave_ledger_entry(ref_doc, args, submit=True):
def delete_ledger_entry(ledger):
''' Delete ledger entry on cancel of leave application/allocation/encashment '''
-
if ledger.transaction_type == "Leave Allocation":
validate_leave_allocation_against_leave_application(ledger)
+ expired_entry = get_previous_expiry_ledger_entry(ledger)
frappe.db.sql("""DELETE
FROM `tabLeave Ledger Entry`
WHERE
- `transaction_name`=%s""", (ledger.transaction_name))
+ `transaction_name`=%s
+ OR `name`=%s""", (ledger.transaction_name, expired_entry))
+
+def get_previous_expiry_ledger_entry(ledger):
+ ''' Returns the expiry ledger entry having same creation date as the ledger entry to be cancelled '''
+ creation_date = frappe.db.get_value("Leave Ledger Entry", filters={
+ 'transaction_name': ledger.transaction_name,
+ 'is_expired': 0
+ }, fieldname=['creation']).strftime(DATE_FORMAT)
+
+ return frappe.db.get_value("Leave Ledger Entry", filters={
+ 'creation': ('like', creation_date+"%"),
+ 'employee': ledger.employee,
+ 'leave_type': ledger.leave_type,
+ 'is_expired': 1,
+ 'docstatus': 1,
+ 'is_carry_forward': 0
+ }, fieldname=['name'])
def process_expired_allocation():
''' Check if a carry forwarded allocation has expired and create a expiry ledger entry '''
@@ -70,7 +87,7 @@ def process_expired_allocation():
leave_type = [record[0] for record in leave_type_records]
expired_allocation = frappe.get_all("Leave Ledger Entry",
filters={
- 'to_date': today(),
+ 'to_date': add_days(today(), -1),
'transaction_type': 'Leave Allocation',
'is_carry_forward': 1,
'leave_type': ('in', leave_type)
From 0d4db95d9923e433bf51dfca1d6aeb3263cbe1ee Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Wed, 3 Jul 2019 11:35:51 +0530
Subject: [PATCH 078/484] fix: skip expired leaves on allocation end date
---
.../leave_application/leave_application.py | 51 ++++++++++++-------
1 file changed, 33 insertions(+), 18 deletions(-)
diff --git a/erpnext/hr/doctype/leave_application/leave_application.py b/erpnext/hr/doctype/leave_application/leave_application.py
index 7aa3e95862..0dde8e157e 100755
--- a/erpnext/hr/doctype/leave_application/leave_application.py
+++ b/erpnext/hr/doctype/leave_application/leave_application.py
@@ -521,8 +521,39 @@ def get_remaining_leaves(allocation, leaves_taken, date, expiry):
return _get_remaining_leaves(allocation.total_leaves_allocated, allocation.to_date)
def get_leaves_for_period(employee, leave_type, from_date, to_date):
- leave_entries = frappe.db.sql("""
- select employee, leave_type, from_date, to_date, leaves, transaction_type
+ leave_entries = get_leave_entries(employee, leave_type, from_date, to_date)
+ leave_days = 0
+
+ for leave_entry in leave_entries:
+ inclusive_period = leave_entry.from_date >= getdate(from_date) and leave_entry.to_date <= getdate(to_date)
+
+ if inclusive_period and leave_entry.transaction_type == 'Leave Encashment':
+ leave_days += leave_entry.leaves
+
+ elif inclusive_period and leave_entry.transaction_type == 'Leave Allocation' \
+ and not skip_expiry_leaves(leave_entry, to_date):
+ leave_days += leave_entry.leaves
+
+ else:
+ if leave_entry.from_date < getdate(from_date):
+ leave_entry.from_date = from_date
+ if leave_entry.to_date > getdate(to_date):
+ leave_entry.to_date = to_date
+
+ leave_days += get_number_of_leave_days(employee, leave_type,
+ leave_entry.from_date, leave_entry.to_date) * -1
+
+ return leave_days
+
+def skip_expiry_leaves(leave_entry, date):
+ ''' Checks whether the expired leaves coincide with the to_date of leave balance check '''
+ end_date = frappe.db.get_value("Leave Allocation", {'name': leave_entry.transaction_name}, ['to_date'])
+ return True if end_date == date and not leave_entry.is_carry_forward else False
+
+def get_leave_entries(employee, leave_type, from_date, to_date):
+ ''' Returns leave entries between from_date and to_date '''
+ return frappe.db.sql("""
+ select employee, leave_type, from_date, to_date, leaves, transaction_type, is_carry_forward
from `tabLeave Ledger Entry`
where employee=%(employee)s and leave_type=%(leave_type)s
and docstatus=1
@@ -536,22 +567,6 @@ def get_leaves_for_period(employee, leave_type, from_date, to_date):
"employee": employee,
"leave_type": leave_type
}, as_dict=1)
- leave_days = 0
-
- for leave_entry in leave_entries:
- if leave_entry.from_date >= getdate(from_date) and leave_entry.to_date <= getdate(to_date) \
- and leave_entry.transaction_type in ('Leave Encashment', 'Leave Allocation'):
- leave_days += leave_entry.leaves
- else:
- if leave_entry.from_date < getdate(from_date):
- leave_entry.from_date = from_date
- if leave_entry.to_date > getdate(to_date):
- leave_entry.to_date = to_date
-
- leave_days += get_number_of_leave_days(employee, leave_type,
- leave_entry.from_date, leave_entry.to_date) * -1
-
- return leave_days
@frappe.whitelist()
def get_holidays(employee, from_date, to_date):
From 80fb0bf520ea43fa1000601ae27a299e05b31db2 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Wed, 3 Jul 2019 13:06:46 +0530
Subject: [PATCH 079/484] fix: add employee leave balance report to the
dashboard
---
.../doctype/leave_allocation/leave_allocation.js | 8 --------
.../leave_allocation/leave_allocation_dashboard.py | 5 +++++
.../doctype/leave_application/leave_application.js | 10 ----------
.../doctype/leave_application/leave_application.py | 2 +-
.../leave_application_dashboard.py | 14 ++++++++++++++
erpnext/patches.txt | 2 +-
6 files changed, 21 insertions(+), 20 deletions(-)
create mode 100644 erpnext/hr/doctype/leave_application/leave_application_dashboard.py
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.js b/erpnext/hr/doctype/leave_allocation/leave_allocation.js
index 8f734ac1bc..2a26a85fa9 100755
--- a/erpnext/hr/doctype/leave_allocation/leave_allocation.js
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.js
@@ -30,14 +30,6 @@ frappe.ui.form.on("Leave Allocation", {
frm.trigger("expire_allocation");
});
}
-
- // opens leave balance report for employee
- frm.add_custom_button(__('Leave Balance'), function() {
- frappe.route_options = {
- employee: frm.doc.employee,
- };
- frappe.set_route("query-report", "Employee Leave Balance");
- });
}
},
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation_dashboard.py b/erpnext/hr/doctype/leave_allocation/leave_allocation_dashboard.py
index 72a1b7c194..7456aebb45 100644
--- a/erpnext/hr/doctype/leave_allocation/leave_allocation_dashboard.py
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation_dashboard.py
@@ -12,4 +12,9 @@ def get_data():
'items': ['Leave Encashment']
}
],
+ 'reports': [
+ {
+ 'items': ['Employee Leave Balance']
+ }
+ ]
}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/leave_application/leave_application.js b/erpnext/hr/doctype/leave_application/leave_application.js
index 44a60b0259..a755b57608 100755
--- a/erpnext/hr/doctype/leave_application/leave_application.js
+++ b/erpnext/hr/doctype/leave_application/leave_application.js
@@ -85,16 +85,6 @@ frappe.ui.form.on("Leave Application", {
frm.set_value('employee', perm['Employee'].map(perm_doc => perm_doc.doc)[0]);
}
}
-
- if (frm.doc.docstatus === 1) {
- frm.add_custom_button(__('Leave Balance'), function() {
- frappe.route_options = {
- employee: frm.doc.employee,
- group_by: ""
- };
- frappe.set_route("query-report", "Employee Leave Balance");
- });
- }
},
employee: function(frm) {
diff --git a/erpnext/hr/doctype/leave_application/leave_application.py b/erpnext/hr/doctype/leave_application/leave_application.py
index 74862fb011..86d9130aab 100755
--- a/erpnext/hr/doctype/leave_application/leave_application.py
+++ b/erpnext/hr/doctype/leave_application/leave_application.py
@@ -438,7 +438,7 @@ def get_leave_details(employee, date):
@frappe.whitelist()
def get_leave_balance_on(employee, leave_type, date, to_date=nowdate(), consider_all_leaves_in_the_allocation_period=False):
'''
- Returns leave balance on date
+ Returns leave balance till date
:param employee: employee name
:param leave_type: leave type
:param date: date to check balance on
diff --git a/erpnext/hr/doctype/leave_application/leave_application_dashboard.py b/erpnext/hr/doctype/leave_application/leave_application_dashboard.py
new file mode 100644
index 0000000000..8075b7b5c5
--- /dev/null
+++ b/erpnext/hr/doctype/leave_application/leave_application_dashboard.py
@@ -0,0 +1,14 @@
+from __future__ import unicode_literals
+
+from frappe import _
+
+
+def get_data():
+ return {
+ 'reports': [
+ {
+ 'label': _('Reports'),
+ 'items': ['Employee Leave Balance']
+ }
+ ]
+ }
\ No newline at end of file
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 3b4cfd835d..b3aeab68f2 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -606,7 +606,6 @@ execute:frappe.delete_doc_if_exists("Page", "support-analytics")
erpnext.patches.v12_0.make_custom_fields_for_bank_remittance #14-06-2019
execute:frappe.delete_doc_if_exists("Page", "support-analytics")
erpnext.patches.v12_0.make_item_manufacturer
-erpnext.patches.v12_0.generate_leave_ledger_entries
erpnext.patches.v11_1.move_customer_lead_to_dynamic_column
erpnext.patches.v11_1.set_default_action_for_quality_inspection
erpnext.patches.v11_1.delete_bom_browser
@@ -617,3 +616,4 @@ erpnext.patches.v11_1.set_missing_opportunity_from
erpnext.patches.v12_0.set_quotation_status
erpnext.patches.v12_0.set_priority_for_support
erpnext.patches.v12_0.delete_priority_property_setter
+erpnext.patches.v12_0.generate_leave_ledger_entries #
From 32371c87553e10cbac4c503bae33aa2f37f32260 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Fri, 12 Jul 2019 11:56:42 +0530
Subject: [PATCH 080/484] feat: Init Pick Ticket and Pick Ticket Item
---
erpnext/stock/doctype/pick_ticket/__init__.py | 0
.../stock/doctype/pick_ticket/pick_ticket.js | 8 ++
.../doctype/pick_ticket/pick_ticket.json | 79 +++++++++++++++++++
.../stock/doctype/pick_ticket/pick_ticket.py | 10 +++
.../doctype/pick_ticket_item/__init__.py | 0
.../pick_ticket_item/pick_ticket_item.json | 72 +++++++++++++++++
.../pick_ticket_item/pick_ticket_item.py | 10 +++
7 files changed, 179 insertions(+)
create mode 100644 erpnext/stock/doctype/pick_ticket/__init__.py
create mode 100644 erpnext/stock/doctype/pick_ticket/pick_ticket.js
create mode 100644 erpnext/stock/doctype/pick_ticket/pick_ticket.json
create mode 100644 erpnext/stock/doctype/pick_ticket/pick_ticket.py
create mode 100644 erpnext/stock/doctype/pick_ticket_item/__init__.py
create mode 100644 erpnext/stock/doctype/pick_ticket_item/pick_ticket_item.json
create mode 100644 erpnext/stock/doctype/pick_ticket_item/pick_ticket_item.py
diff --git a/erpnext/stock/doctype/pick_ticket/__init__.py b/erpnext/stock/doctype/pick_ticket/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/stock/doctype/pick_ticket/pick_ticket.js b/erpnext/stock/doctype/pick_ticket/pick_ticket.js
new file mode 100644
index 0000000000..f9ae38a3e2
--- /dev/null
+++ b/erpnext/stock/doctype/pick_ticket/pick_ticket.js
@@ -0,0 +1,8 @@
+// Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Pick Ticket', {
+ // onload: function(frm) {
+
+ // }
+});
diff --git a/erpnext/stock/doctype/pick_ticket/pick_ticket.json b/erpnext/stock/doctype/pick_ticket/pick_ticket.json
new file mode 100644
index 0000000000..28aa6997cb
--- /dev/null
+++ b/erpnext/stock/doctype/pick_ticket/pick_ticket.json
@@ -0,0 +1,79 @@
+{
+ "creation": "2019-07-11 16:03:13.681045",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "reference_doctype",
+ "reference_name",
+ "company",
+ "column_break_4",
+ "group_warehouse",
+ "section_break_6",
+ "items"
+ ],
+ "fields": [
+ {
+ "fieldname": "reference_doctype",
+ "fieldtype": "Select",
+ "label": "Reference Document Type",
+ "options": "Sales Order\nWork Order"
+ },
+ {
+ "fieldname": "reference_name",
+ "fieldtype": "Dynamic Link",
+ "label": "Reference Name",
+ "options": "reference_doctype"
+ },
+ {
+ "fieldname": "items",
+ "fieldtype": "Table",
+ "label": "Items",
+ "options": "Pick Ticket Item"
+ },
+ {
+ "description": "Items under this warehouse will be suggested",
+ "fieldname": "group_warehouse",
+ "fieldtype": "Link",
+ "label": "Group Warehouse",
+ "options": "Warehouse"
+ },
+ {
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "label": "Company",
+ "options": "Company"
+ },
+ {
+ "fieldname": "column_break_4",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "section_break_6",
+ "fieldtype": "Section Break"
+ }
+ ],
+ "modified": "2019-07-12 11:42:03.508514",
+ "modified_by": "Administrator",
+ "module": "Stock",
+ "name": "Pick Ticket",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "System Manager",
+ "share": 1,
+ "write": 1
+ }
+ ],
+ "quick_entry": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/stock/doctype/pick_ticket/pick_ticket.py b/erpnext/stock/doctype/pick_ticket/pick_ticket.py
new file mode 100644
index 0000000000..7f2e89bb6c
--- /dev/null
+++ b/erpnext/stock/doctype/pick_ticket/pick_ticket.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+# import frappe
+from frappe.model.document import Document
+
+class PickTicket(Document):
+ pass
diff --git a/erpnext/stock/doctype/pick_ticket_item/__init__.py b/erpnext/stock/doctype/pick_ticket_item/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/stock/doctype/pick_ticket_item/pick_ticket_item.json b/erpnext/stock/doctype/pick_ticket_item/pick_ticket_item.json
new file mode 100644
index 0000000000..705172553e
--- /dev/null
+++ b/erpnext/stock/doctype/pick_ticket_item/pick_ticket_item.json
@@ -0,0 +1,72 @@
+{
+ "creation": "2019-07-11 16:01:22.832885",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "item",
+ "item_name",
+ "description",
+ "reference_document_item",
+ "warehouse",
+ "qty",
+ "picked_qty"
+ ],
+ "fields": [
+ {
+ "fieldname": "item",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Item",
+ "options": "Item"
+ },
+ {
+ "fieldname": "qty",
+ "fieldtype": "Float",
+ "in_list_view": 1,
+ "label": "Qty"
+ },
+ {
+ "fieldname": "picked_qty",
+ "fieldtype": "Float",
+ "in_list_view": 1,
+ "label": "Picked Qty"
+ },
+ {
+ "fieldname": "warehouse",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Warehouse",
+ "options": "Warehouse"
+ },
+ {
+ "fetch_from": "item.item_name",
+ "fieldname": "item_name",
+ "fieldtype": "Data",
+ "label": "Item Name"
+ },
+ {
+ "fetch_from": "item.description",
+ "fieldname": "description",
+ "fieldtype": "Text",
+ "label": "Description"
+ },
+ {
+ "fieldname": "reference_document_item",
+ "fieldtype": "Data",
+ "hidden": 1,
+ "label": "Reference Document Item"
+ }
+ ],
+ "istable": 1,
+ "modified": "2019-07-11 16:34:52.853146",
+ "modified_by": "Administrator",
+ "module": "Stock",
+ "name": "Pick Ticket Item",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/stock/doctype/pick_ticket_item/pick_ticket_item.py b/erpnext/stock/doctype/pick_ticket_item/pick_ticket_item.py
new file mode 100644
index 0000000000..a13666a438
--- /dev/null
+++ b/erpnext/stock/doctype/pick_ticket_item/pick_ticket_item.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+# import frappe
+from frappe.model.document import Document
+
+class PickTicketItem(Document):
+ pass
From 29e9f14f95e967141841c3519946d5b3b7dae7c2 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Mon, 22 Jul 2019 13:54:39 +0530
Subject: [PATCH 081/484] fix: minor changes
---
.../hr/doctype/leave_application/leave_application.py | 9 +++++----
.../hr/doctype/leave_ledger_entry/leave_ledger_entry.py | 4 ++++
erpnext/hr/doctype/leave_type/leave_type.py | 6 +++++-
3 files changed, 14 insertions(+), 5 deletions(-)
diff --git a/erpnext/hr/doctype/leave_application/leave_application.py b/erpnext/hr/doctype/leave_application/leave_application.py
index 86d9130aab..8f02ec0f92 100755
--- a/erpnext/hr/doctype/leave_application/leave_application.py
+++ b/erpnext/hr/doctype/leave_application/leave_application.py
@@ -357,7 +357,7 @@ class LeaveApplication(Document):
lwp = frappe.db.get_value("Leave Type", self.leave_type, "is_lwp")
if expiry_date:
- self.create_ledger_entry_for_intermediate_allocation_expiry(expiry_date, submit)
+ self.create_ledger_entry_for_intermediate_allocation_expiry(expiry_date, submit, lwp)
else:
args = dict(
leaves=self.total_leave_days * -1,
@@ -367,16 +367,17 @@ class LeaveApplication(Document):
)
create_leave_ledger_entry(self, args, submit)
- def create_ledger_entry_for_intermediate_allocation_expiry(self, expiry_date, submit):
+ def create_ledger_entry_for_intermediate_allocation_expiry(self, expiry_date, submit, lwp):
''' splits leave application into two ledger entries to consider expiry of allocation '''
args = dict(
from_date=self.from_date,
to_date=expiry_date,
- leaves=(date_diff(expiry_date, self.from_date) + 1) * -1
+ leaves=(date_diff(expiry_date, self.from_date) + 1) * -1,
+ is_lwp=lwp
)
create_leave_ledger_entry(self, args, submit)
- if expiry_date != self.to_date:
+ if getdate(expiry_date) != getdate(self.to_date):
start_date = add_days(expiry_date, 1)
args.update(dict(
from_date=start_date,
diff --git a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
index a73f10adb8..99a9d0d933 100644
--- a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
+++ b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
@@ -9,6 +9,10 @@ from frappe import _
from frappe.utils import add_days, today, flt, DATE_FORMAT
class LeaveLedgerEntry(Document):
+ def validate(self):
+ if self.from_date > self.to_date:
+ frappe.throw(_("To date needs to be before from date"))
+
def on_cancel(self):
# allow cancellation of expiry leaves
if not self.is_expired:
diff --git a/erpnext/hr/doctype/leave_type/leave_type.py b/erpnext/hr/doctype/leave_type/leave_type.py
index 5b13edb684..cbc6781783 100644
--- a/erpnext/hr/doctype/leave_type/leave_type.py
+++ b/erpnext/hr/doctype/leave_type/leave_type.py
@@ -10,4 +10,8 @@ from frappe import _
from frappe.model.document import Document
class LeaveType(Document):
- pass
\ No newline at end of file
+ def validate(self):
+ if self.is_lwp:
+ leave_allocation = frappe.get_doc("Leave Allocation", {"leave_type": self.name}, ['name'])
+ if leave_allocation:
+ frappe.throw(_("""Leave application is linked with leave allocations {0}. Leave application cannot be set as leave without pay""").format(", ".join(leave_allocation))) #nosec
\ No newline at end of file
From f6cf58fa8c49443b47912639caaa10eb0b065601 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Mon, 22 Jul 2019 15:32:41 +0530
Subject: [PATCH 082/484] fix: change get all to sql list
---
.../leave_ledger_entry/leave_ledger_entry.py | 18 ++++++++++--------
erpnext/hr/doctype/leave_type/leave_type.py | 2 +-
2 files changed, 11 insertions(+), 9 deletions(-)
diff --git a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
index 99a9d0d933..0520b867f2 100644
--- a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
+++ b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
@@ -20,14 +20,16 @@ class LeaveLedgerEntry(Document):
def validate_leave_allocation_against_leave_application(ledger):
''' Checks that leave allocation has no leave application against it '''
- leave_application_records = frappe.get_all("Leave Ledger Entry",
- filters={
- 'employee': ledger.employee,
- 'leave_type': ledger.leave_type,
- 'transaction_type': 'Leave Application',
- 'from_date': (">=", ledger.from_date),
- 'to_date': ('<=', ledger.to_date)
- }, fields=['transaction_name'])
+ leave_application_records = frappe.db.sql_list("""
+ SELECT transaction_name
+ FROM `tabLeave Application`
+ WHERE
+ employee=%s,
+ leave_type=%s,
+ transaction_type='Leave Application',
+ from_date>=%s,
+ to_date<=%s
+ """, (ledger.employee, ledger.leave_type, ledger.from_date, ledger.to_date))
if leave_application_records:
frappe.throw(_("Leave allocation %s is linked with leave application %s"
diff --git a/erpnext/hr/doctype/leave_type/leave_type.py b/erpnext/hr/doctype/leave_type/leave_type.py
index cbc6781783..75336e0c7e 100644
--- a/erpnext/hr/doctype/leave_type/leave_type.py
+++ b/erpnext/hr/doctype/leave_type/leave_type.py
@@ -12,6 +12,6 @@ from frappe.model.document import Document
class LeaveType(Document):
def validate(self):
if self.is_lwp:
- leave_allocation = frappe.get_doc("Leave Allocation", {"leave_type": self.name}, ['name'])
+ leave_allocation = frappe.db.sql_list("""select name from `tabLeave Allocation` where leave_type=%s""", (self.name))
if leave_allocation:
frappe.throw(_("""Leave application is linked with leave allocations {0}. Leave application cannot be set as leave without pay""").format(", ".join(leave_allocation))) #nosec
\ No newline at end of file
From 3e85b4937bb1b197cecffd08cdcf2e698c8f12a7 Mon Sep 17 00:00:00 2001
From: sahil28297 <37302950+sahil28297@users.noreply.github.com>
Date: Mon, 22 Jul 2019 17:31:14 +0530
Subject: [PATCH 083/484] Release Version 12
---
erpnext/__init__.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/__init__.py b/erpnext/__init__.py
index cb88a1122e..020f843c1a 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__ = '11.1.39'
+__version__ = '12.0.0'
def get_default_company(user=None):
'''Get default company for user'''
From 85d88395ba315ede94320861e882f079a564ab64 Mon Sep 17 00:00:00 2001
From: Saurabh
Date: Mon, 22 Jul 2019 17:39:18 +0530
Subject: [PATCH 084/484] changelog: release 12.0.0
---
erpnext/change_log/v12/v12_0_0.md | 41 +++++++++++++++++++++++++++++++
1 file changed, 41 insertions(+)
create mode 100644 erpnext/change_log/v12/v12_0_0.md
diff --git a/erpnext/change_log/v12/v12_0_0.md b/erpnext/change_log/v12/v12_0_0.md
new file mode 100644
index 0000000000..dcbc9a00dd
--- /dev/null
+++ b/erpnext/change_log/v12/v12_0_0.md
@@ -0,0 +1,41 @@
+# Version 12 Release Notes
+
+### Accounting
+1. [Accounting Dimensions](/docs/user/manual/en/accounts/accounting-dimensions)
+1. [Chart of Accounts Importer](/docs/user/manual/en/setting-up/chart-of-accounts-importer)
+1. [Invoice Discounting](/docs/user/manual/en/accounts/invoice_discounting)
+1. [Tally Migrator](https://github.com/frappe/erpnext/pull/17405)
+
+### Stock
+1. [Serialized & Batched Item Reconciliation](/docs/user/manual/en/setting-up/stock-reconciliation#12-for-serialized-items)
+1. [Auto Fetch Serialized Items](/version-12/release-notes/features#new-upload-dialog)
+1. [Item Tax Templates](/docs/user/manual/en/accounts/item-tax-template)
+
+### HR
+1. [Auto Attendance](/docs/user/manual/en/human-resources/auto-attendance)
+1. [Employee Skill Map](/docs/user/manual/en/human-resources/employee_skill_map)
+1. [Encrypted Salary Slips](/docs/user/manual/en/human-resources/hr-settings#24-encrypt-salary-slips-in-emails)
+1. [Leave Ledger](/docs/user/manual/en/human-resources/leave-ledger-entry)
+1. [Staffing Plan](/docs/user/manual/en/human-resources/staffing-plan)
+
+### CRM
+1. [Promotional Scheme](/docs/user/manual/en/accounts/promotional-schemes)
+1. [SLA](/docs/user/manual/en/support/service-level-agreement)
+1. [Exotel Call Integration](/docs/user/manual/en/erpnext_integration/exotel_integration)
+1. [Email Campaign](/docs/user/manual/en/CRM/email-campaign)
+
+### Domain Specific Features
+1. [Learning Management System](/docs/user/manual/en/education/setting-up-lms)
+1. [Quality Management System](/docs/user/manual/en/quality-management)
+1. [Production Planning Enhancements](/docs/user/manual/en/manufacturing/production-plan/planning-for-material-requests)
+1. [Project Template](/docs/user/manual/en/projects/project-template)
+
+### New Reports
+1. [Bank Remittance](/docs/user/manual/en/human-resources/human-resources-reports#bank-remittance-report)
+1. [BOM Explorer](/docs/user/manual/en/stock/articles/bom_explorer)
+1. [Billing Summary Report](/docs/user/manual/en/projects/reports/billing_summary_reports)
+1. [Procurement Tracker Report](docs/user/manual/en/buying/articles/procurement-tracker-report)
+1. [Loan Repayment](/docs/user/manual/en/human-resources/human-resources-reports#loan-repayment-report)
+1. [GSTR-3B](/docs/user/manual/en/regional/india/gst-3b-report)
+1. [Sales Partner](/docs/user/manual/en/selling/sales-partner#sales-partner-reports)
+1. [Sales Partner Target Variance based on Item Group](sales-partner-target-variance-based-on-item-group)
From 08c02287dd3a396d61dd3573f10efbcfe300fca1 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Mon, 22 Jul 2019 17:47:03 +0530
Subject: [PATCH 085/484] fix: expiry allocaton after creating all the
transactions
---
.../v12_0/generate_leave_ledger_entries.py | 146 +++++++++---------
1 file changed, 77 insertions(+), 69 deletions(-)
diff --git a/erpnext/patches/v12_0/generate_leave_ledger_entries.py b/erpnext/patches/v12_0/generate_leave_ledger_entries.py
index ffb2e3fba5..8a92bb3a3d 100644
--- a/erpnext/patches/v12_0/generate_leave_ledger_entries.py
+++ b/erpnext/patches/v12_0/generate_leave_ledger_entries.py
@@ -6,88 +6,96 @@ import frappe
from frappe.utils import getdate
def execute():
- """ Generates leave ledger entries for leave allocation/application/encashment
- for last allocation """
- frappe.reload_doc("HR", "doctype", "Leave Ledger Entry")
- frappe.reload_doc("HR", "doctype", "Leave Encashment")
- if frappe.db.a_row_exists("Leave Ledger Entry"):
- return
+ """ Generates leave ledger entries for leave allocation/application/encashment
+ for last allocation """
+ frappe.reload_doc("HR", "doctype", "Leave Ledger Entry")
+ frappe.reload_doc("HR", "doctype", "Leave Encashment")
+ if frappe.db.a_row_exists("Leave Ledger Entry"):
+ return
- generate_allocation_ledger_entries()
- generate_application_leave_ledger_entries()
- generate_encashment_leave_ledger_entries()
+ generate_allocation_ledger_entries()
+ generate_application_leave_ledger_entries()
+ generate_encashment_leave_ledger_entries()
+ generate_expiry_allocation_ledger_entries()
def generate_allocation_ledger_entries():
- ''' fix ledger entries for missing leave allocation transaction '''
- allocation_list = get_allocation_records()
-
- for allocation in allocation_list:
- if not frappe.db.exists("Leave Ledger Entry", {'transaction_type': 'Leave Allocation', 'transaction_name': allocation.name}):
- allocation.update(dict(doctype="Leave Allocation"))
- allocation_obj = frappe.get_doc(allocation)
- allocation_obj.create_leave_ledger_entry()
- if allocation.to_date <= getdate():
- allocation_obj.expire_allocation()
+ ''' fix ledger entries for missing leave allocation transaction '''
+ allocation_list = get_allocation_records()
+ for allocation in allocation_list:
+ if not frappe.db.exists("Leave Ledger Entry", {'transaction_type': 'Leave Allocation', 'transaction_name': allocation.name}):
+ allocation.update(dict(doctype="Leave Allocation"))
+ allocation_obj = frappe.get_doc(allocation)
+ allocation_obj.create_leave_ledger_entry()
def generate_application_leave_ledger_entries():
- ''' fix ledger entries for missing leave application transaction '''
- leave_applications = get_leaves_application_records()
+ ''' fix ledger entries for missing leave application transaction '''
+ leave_applications = get_leaves_application_records()
- for application in leave_applications:
- if not frappe.db.exists("Leave Ledger Entry", {'transaction_type': 'Leave Application', 'transaction_name': application.name}):
- application.update(dict(doctype="Leave Application"))
- frappe.get_doc(application).create_leave_ledger_entry()
+ for application in leave_applications:
+ if not frappe.db.exists("Leave Ledger Entry", {'transaction_type': 'Leave Application', 'transaction_name': application.name}):
+ application.update(dict(doctype="Leave Application"))
+ frappe.get_doc(application).create_leave_ledger_entry()
def generate_encashment_leave_ledger_entries():
- ''' fix ledger entries for missing leave encashment transaction '''
- leave_encashments = get_leave_encashment_records()
+ ''' fix ledger entries for missing leave encashment transaction '''
+ leave_encashments = get_leave_encashment_records()
- for encashment in leave_encashments:
- if not frappe.db.exists("Leave Ledger Entry", {'transaction_type': 'Leave Encashment', 'transaction_name': encashment.name}):
- encashment.update(dict(doctype="Leave Encashment"))
- frappe.get_doc(encashment).create_leave_ledger_entry()
+ for encashment in leave_encashments:
+ if not frappe.db.exists("Leave Ledger Entry", {'transaction_type': 'Leave Encashment', 'transaction_name': encashment.name}):
+ encashment.update(dict(doctype="Leave Encashment"))
+ frappe.get_doc(encashment).create_leave_ledger_entry()
+
+def generate_expiry_allocation_ledger_entries():
+ ''' fix ledger entries for missing leave allocation transaction '''
+ allocation_list = get_allocation_records()
+
+ for allocation in allocation_list:
+ if not frappe.db.exists("Leave Ledger Entry", {'transaction_type': 'Leave Allocation', 'transaction_name': allocation.name, 'is_expired': 1}):
+ allocation.update(dict(doctype="Leave Allocation"))
+ allocation_obj = frappe.get_doc(allocation)
+ allocation_obj.expire_allocation()
def get_allocation_records():
- return frappe.db.sql("""
- SELECT
- DISTINCT name,
- employee,
- leave_type,
- new_leaves_allocated,
- carry_forwarded_leaves,
- from_date,
- to_date,
- carry_forward
- FROM `tabLeave Allocation`
- WHERE
- docstatus=1
- ORDER BY to_date ASC
- """, as_dict=1)
+ return frappe.db.sql("""
+ SELECT
+ name,
+ employee,
+ leave_type,
+ new_leaves_allocated,
+ carry_forwarded_leaves,
+ from_date,
+ to_date,
+ carry_forward
+ FROM `tabLeave Allocation`
+ WHERE
+ docstatus=1
+ ORDER BY to_date ASC
+ """, as_dict=1)
def get_leaves_application_records():
- return frappe.db.sql("""
- SELECT
- DISTINCT name,
- employee,
- leave_type,
- total_leave_days,
- from_date,
- to_date
- FROM `tabLeave Application`
- WHERE
- docstatus=1
- """, as_dict=1)
+ return frappe.db.sql("""
+ SELECT
+ name,
+ employee,
+ leave_type,
+ total_leave_days,
+ from_date,
+ to_date
+ FROM `tabLeave Application`
+ WHERE
+ docstatus=1
+ """, as_dict=1)
def get_leave_encashment_records():
- return frappe.db.sql("""
- SELECT
- DISTINCT name,
- employee,
- leave_type,
- encashable_days,
- encashment_date
- FROM `tabLeave Encashment`
- WHERE
- docstatus=1
- """, as_dict=1)
\ No newline at end of file
+ return frappe.db.sql("""
+ SELECT
+ name,
+ employee,
+ leave_type,
+ encashable_days,
+ encashment_date
+ FROM `tabLeave Encashment`
+ WHERE
+ docstatus=1
+ """, as_dict=1)
\ No newline at end of file
From fd1d4c2927d6d397965ad12b9792fb609064e6ea Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Mon, 22 Jul 2019 18:05:27 +0530
Subject: [PATCH 086/484] chore: split expire allocation
---
.../leave_allocation/leave_allocation.js | 7 ++--
.../leave_allocation/leave_allocation.json | 22 ++++++-------
.../leave_allocation/leave_allocation.py | 32 +++++++++++++++----
.../leave_allocation/leave_allocation_list.js | 2 +-
.../v12_0/generate_leave_ledger_entries.py | 2 +-
5 files changed, 40 insertions(+), 25 deletions(-)
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.js b/erpnext/hr/doctype/leave_allocation/leave_allocation.js
index 2a26a85fa9..7c3e1e44fa 100755
--- a/erpnext/hr/doctype/leave_allocation/leave_allocation.js
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.js
@@ -22,7 +22,7 @@ frappe.ui.form.on("Leave Allocation", {
},
refresh: function(frm) {
- if(frm.doc.docstatus === 1 && frm.doc.status === "Active") {
+ if(frm.doc.docstatus === 1 && frm.doc.expired) {
var valid_expiry = moment(frappe.datetime.get_today()).isBetween(frm.doc.from_date, frm.doc.to_date);
if(valid_expiry) {
// expire current allocation
@@ -35,11 +35,8 @@ frappe.ui.form.on("Leave Allocation", {
expire_allocation: function(frm) {
frappe.call({
- method: 'expire_allocation',
+ method: 'expire_current_allocation',
doc: frm.doc,
- args: {
- current: true
- },
freeze: true,
callback: function(r){
if(!r.exc){
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.json b/erpnext/hr/doctype/leave_allocation/leave_allocation.json
index 41d864d912..1618c67d3d 100644
--- a/erpnext/hr/doctype/leave_allocation/leave_allocation.json
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.json
@@ -24,7 +24,7 @@
"compensatory_request",
"leave_period",
"leave_policy",
- "status",
+ "expired",
"amended_from",
"notes",
"description"
@@ -167,15 +167,6 @@
"options": "Leave Policy",
"read_only": 1
},
- {
- "fieldname": "status",
- "fieldtype": "Select",
- "hidden": 1,
- "in_standard_filter": 1,
- "label": "Status",
- "options": "Active\nExpired",
- "read_only": 1
- },
{
"fieldname": "amended_from",
"fieldtype": "Link",
@@ -201,12 +192,21 @@
"oldfieldname": "reason",
"oldfieldtype": "Small Text",
"width": "300px"
+ },
+ {
+ "default": "0",
+ "fieldname": "expired",
+ "fieldtype": "Check",
+ "hidden": 1,
+ "in_standard_filter": 1,
+ "label": "Expired",
+ "read_only": 1
}
],
"icon": "fa fa-ok",
"idx": 1,
"is_submittable": 1,
- "modified": "2019-06-14 15:39:02.898695",
+ "modified": "2019-07-22 17:50:39.591195",
"modified_by": "Administrator",
"module": "HR",
"name": "Leave Allocation",
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.py b/erpnext/hr/doctype/leave_allocation/leave_allocation.py
index df479e72e9..494043ff14 100755
--- a/erpnext/hr/doctype/leave_allocation/leave_allocation.py
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.py
@@ -42,7 +42,7 @@ class LeaveAllocation(Document):
def on_submit(self):
self.create_leave_ledger_entry()
- self.expire_allocation()
+ self.expire_previous_allocation()
def on_cancel(self):
self.create_leave_ledger_entry(submit=False)
@@ -128,14 +128,14 @@ class LeaveAllocation(Document):
)
create_leave_ledger_entry(self, args, submit)
- def expire_allocation(self, current=False):
+ def expire_current_allocation(self):
''' expires allocation '''
- date = self.to_date if current else self.from_date
+ date = self.to_date
leaves = get_unused_leaves(self.employee, self.leave_type, date)
- ref_name = self.name if current else self.get_previous_allocation()
+ ref_name = self.name
if leaves:
- expiry_date = today() if current else add_days(self.from_date, -1)
+ expiry_date = today()
args = dict(
leaves=flt(leaves) * -1,
transaction_name=ref_name,
@@ -146,8 +146,26 @@ class LeaveAllocation(Document):
)
create_leave_ledger_entry(self, args)
- if current:
- frappe.db.set_value("Leave Allocation", self.name, "status", "Expired")
+ frappe.db.set_value("Leave Allocation", self.name, "expired", 1)
+
+ def expire_previous_allocation(self):
+ date = self.from_date
+ leaves = get_unused_leaves(self.employee, self.leave_type, date)
+ ref_name = self.get_previous_allocation()
+
+ if leaves:
+ expiry_date = add_days(self.from_date, -1)
+ args = dict(
+ leaves=flt(leaves) * -1,
+ transaction_name=ref_name,
+ from_date=expiry_date,
+ to_date=expiry_date,
+ is_carry_forward=0,
+ is_expired=1
+ )
+ create_leave_ledger_entry(self, args)
+
+ frappe.db.set_value("Leave Allocation", ref_name, "expired", 1)
def get_previous_allocation(self):
return frappe.db.get_value("Leave Allocation",
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation_list.js b/erpnext/hr/doctype/leave_allocation/leave_allocation_list.js
index 3ea0e2403f..93f7b8356b 100644
--- a/erpnext/hr/doctype/leave_allocation/leave_allocation_list.js
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation_list.js
@@ -5,7 +5,7 @@
frappe.listview_settings['Leave Allocation'] = {
get_indicator: function(doc) {
if(doc.status==="Expired") {
- return [__("Expired"), "darkgrey", "status, =, Expired"];
+ return [__("Expired"), "darkgrey", "expired, =, 1"];
}
},
};
diff --git a/erpnext/patches/v12_0/generate_leave_ledger_entries.py b/erpnext/patches/v12_0/generate_leave_ledger_entries.py
index 8a92bb3a3d..f2a798e1f8 100644
--- a/erpnext/patches/v12_0/generate_leave_ledger_entries.py
+++ b/erpnext/patches/v12_0/generate_leave_ledger_entries.py
@@ -54,7 +54,7 @@ def generate_expiry_allocation_ledger_entries():
if not frappe.db.exists("Leave Ledger Entry", {'transaction_type': 'Leave Allocation', 'transaction_name': allocation.name, 'is_expired': 1}):
allocation.update(dict(doctype="Leave Allocation"))
allocation_obj = frappe.get_doc(allocation)
- allocation_obj.expire_allocation()
+ allocation_obj.expire_previous_allocation()
def get_allocation_records():
return frappe.db.sql("""
From bb1be2e2ee4ba2d2f9a688ef88ff51419177ad4d Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Tue, 23 Jul 2019 13:18:40 +0530
Subject: [PATCH 087/484] chore: change fieldname for carried forward leave
expiry
---
erpnext/hr/doctype/leave_allocation/leave_allocation.py | 2 +-
.../hr/doctype/leave_allocation/test_leave_allocation.py | 2 +-
.../hr/doctype/leave_application/test_leave_application.py | 4 ++--
erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py | 2 +-
erpnext/hr/doctype/leave_period/leave_period.py | 2 +-
erpnext/hr/doctype/leave_type/leave_type.json | 6 +++---
erpnext/hr/doctype/leave_type/test_leave_type.py | 2 +-
7 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.py b/erpnext/hr/doctype/leave_allocation/leave_allocation.py
index 494043ff14..67f30b5816 100755
--- a/erpnext/hr/doctype/leave_allocation/leave_allocation.py
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.py
@@ -111,7 +111,7 @@ class LeaveAllocation(Document):
def create_leave_ledger_entry(self, submit=True):
if self.carry_forwarded_leaves:
- expiry_days = frappe.db.get_value("Leave Type", self.leave_type, "carry_forward_leave_expiry")
+ expiry_days = frappe.db.get_value("Leave Type", self.leave_type, "expire_carried_forward_leaves")
args = dict(
leaves=self.carry_forwarded_leaves,
from_date=self.from_date,
diff --git a/erpnext/hr/doctype/leave_allocation/test_leave_allocation.py b/erpnext/hr/doctype/leave_allocation/test_leave_allocation.py
index dfae329da1..dfa64db416 100644
--- a/erpnext/hr/doctype/leave_allocation/test_leave_allocation.py
+++ b/erpnext/hr/doctype/leave_allocation/test_leave_allocation.py
@@ -97,7 +97,7 @@ class TestLeaveAllocation(unittest.TestCase):
leave_type = create_leave_type(
leave_type_name="_Test_CF_leave_expiry",
is_carry_forward=1,
- carry_forward_leave_expiry=90)
+ expire_carried_forward_leaves=90)
leave_type.submit()
# initial leave allocation
diff --git a/erpnext/hr/doctype/leave_application/test_leave_application.py b/erpnext/hr/doctype/leave_application/test_leave_application.py
index ca6b99ca12..709a2f57df 100644
--- a/erpnext/hr/doctype/leave_application/test_leave_application.py
+++ b/erpnext/hr/doctype/leave_application/test_leave_application.py
@@ -415,7 +415,7 @@ class TestLeaveApplication(unittest.TestCase):
leave_type = create_leave_type(
leave_type_name="_Test_CF_leave_expiry",
is_carry_forward=1,
- carry_forward_leave_expiry=90)
+ expire_carried_forward_leaves=90)
leave_type.submit()
create_carry_forwarded_allocation(employee, leave_type)
@@ -516,7 +516,7 @@ class TestLeaveApplication(unittest.TestCase):
leave_type = create_leave_type(
leave_type_name="_Test_CF_leave_expiry",
is_carry_forward=1,
- carry_forward_leave_expiry=90)
+ expire_carried_forward_leaves=90)
leave_type.submit()
create_carry_forwarded_allocation(employee, leave_type)
diff --git a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
index 0520b867f2..135b750bf9 100644
--- a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
+++ b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
@@ -86,7 +86,7 @@ def process_expired_allocation():
# fetch leave type records that has carry forwarded leaves expiry
leave_type_records = frappe.db.get_values("Leave Type", filters={
- 'carry_forward_leave_expiry': (">", 0)
+ 'expire_carried_forward_leaves': (">", 0)
}, fieldname=['name'])
if leave_type_records:
diff --git a/erpnext/hr/doctype/leave_period/leave_period.py b/erpnext/hr/doctype/leave_period/leave_period.py
index 91cc9b8340..f37efeba0b 100644
--- a/erpnext/hr/doctype/leave_period/leave_period.py
+++ b/erpnext/hr/doctype/leave_period/leave_period.py
@@ -95,7 +95,7 @@ def get_existing_allocations(employees, leave_period):
def get_leave_type_details():
leave_type_details = frappe._dict()
leave_types = frappe.get_all("Leave Type",
- fields=["name", "is_lwp", "is_earned_leave", "is_compensatory", "is_carry_forward", "carry_forward_leave_expiry"])
+ fields=["name", "is_lwp", "is_earned_leave", "is_compensatory", "is_carry_forward", "expire_carried_forward_leaves"])
for d in leave_types:
leave_type_details.setdefault(d.name, d)
return leave_type_details
diff --git a/erpnext/hr/doctype/leave_type/leave_type.json b/erpnext/hr/doctype/leave_type/leave_type.json
index 7899c2f1e6..7a279063ce 100644
--- a/erpnext/hr/doctype/leave_type/leave_type.json
+++ b/erpnext/hr/doctype/leave_type/leave_type.json
@@ -419,9 +419,9 @@
"collapsible": 0,
"columns": 0,
"depends_on": "",
- "description": "calculated in days",
+ "description": "Calculated in days",
"fetch_if_empty": 0,
- "fieldname": "carry_forward_leave_expiry",
+ "fieldname": "expire_carried_forward_leaves",
"fieldtype": "Int",
"hidden": 0,
"ignore_user_permissions": 0,
@@ -728,7 +728,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2019-05-30 15:38:39.334283",
+ "modified": "2019-07-22 15:38:39.334283",
"modified_by": "Administrator",
"module": "HR",
"name": "Leave Type",
diff --git a/erpnext/hr/doctype/leave_type/test_leave_type.py b/erpnext/hr/doctype/leave_type/test_leave_type.py
index 1006550de4..d9852be6c9 100644
--- a/erpnext/hr/doctype/leave_type/test_leave_type.py
+++ b/erpnext/hr/doctype/leave_type/test_leave_type.py
@@ -19,7 +19,7 @@ def create_leave_type(**args):
"is_earned_leave": args.is_earned_leave or 0,
"is_lwp": args.is_lwp or 0,
"is_carry_forward": args.is_carry_forward or 0,
- "carry_forward_leave_expiry": args.carry_forward_leave_expiry or 0,
+ "expire_carried_forward_leaves": args.expire_carried_forward_leaves or 0,
"encashment_threshold_days": args.encashment_threshold_days or 5,
"earning_component": "Leave Encashment"
})
From 06c7a7e6601914c36092c4cb1230f39701340ef2 Mon Sep 17 00:00:00 2001
From: Faris Ansari
Date: Tue, 23 Jul 2019 13:40:40 +0530
Subject: [PATCH 088/484] =?UTF-8?q?fix(website):=20Remove=20references=20t?=
=?UTF-8?q?o=20Product=20Settings.products=5Fa=E2=80=A6=20(#18451)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This was accidentally added back in https://github.com/frappe/erpnext/commit/34c551d9a54573e5184bb16831e0baa4e7429dc2#diff-f0a387cdb305471e74e523ecc4e646ac
---
erpnext/setup/doctype/item_group/item_group.py | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/erpnext/setup/doctype/item_group/item_group.py b/erpnext/setup/doctype/item_group/item_group.py
index 8fbeac8138..cab21162c7 100644
--- a/erpnext/setup/doctype/item_group/item_group.py
+++ b/erpnext/setup/doctype/item_group/item_group.py
@@ -69,8 +69,7 @@ class ItemGroup(NestedSet, WebsiteGenerator):
"items": get_product_list_for_group(product_group = self.name, start=start,
limit=context.page_length + 1, search=frappe.form_dict.get("search")),
"parents": get_parent_item_groups(self.parent_item_group),
- "title": self.name,
- "products_as_list": cint(frappe.db.get_single_value('Products Settings', 'products_as_list'))
+ "title": self.name
})
if self.slideshow:
From 05425d414cb20a9b6b52bb4d0708edd81fa5eb14 Mon Sep 17 00:00:00 2001
From: Himanshu Warekar
Date: Tue, 23 Jul 2019 16:58:13 +0530
Subject: [PATCH 089/484] fix: change agreement fulfilled to ongoing
---
erpnext/support/doctype/issue/issue.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/erpnext/support/doctype/issue/issue.py b/erpnext/support/doctype/issue/issue.py
index 98d8c99809..58e2076858 100644
--- a/erpnext/support/doctype/issue/issue.py
+++ b/erpnext/support/doctype/issue/issue.py
@@ -210,6 +210,7 @@ class Issue(Document):
self.service_level_agreement_creation = now_datetime()
self.set_response_and_resolution_time(priority=self.priority, service_level_agreement=self.service_level_agreement)
+ self.agreement_fulfilled = "Ongoing"
self.save()
def get_expected_time_for(parameter, service_level, start_date_time):
From 778b4926bf7852bb04cc9843a1d08bbec271ae31 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Wed, 24 Jul 2019 11:27:32 +0530
Subject: [PATCH 090/484] fix: Fetch warehouse location from Bin
---
.../doctype/sales_order/sales_order.js | 8 ++
.../doctype/sales_order/sales_order.py | 77 +++++++++++++++++++
.../pick_ticket_item/pick_ticket_item.json | 37 ++++++++-
3 files changed, 120 insertions(+), 2 deletions(-)
diff --git a/erpnext/selling/doctype/sales_order/sales_order.js b/erpnext/selling/doctype/sales_order/sales_order.js
index 39dda92e3e..89739cc633 100644
--- a/erpnext/selling/doctype/sales_order/sales_order.js
+++ b/erpnext/selling/doctype/sales_order/sales_order.js
@@ -102,6 +102,7 @@ frappe.ui.form.on("Sales Order Item", {
erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend({
onload: function(doc, dt, dn) {
this._super();
+ this.frm.add_custom_button(__('Pick Ticket'), () => this.make_pick_ticket(), __('Create'));
},
refresh: function(doc, dt, dn) {
@@ -233,6 +234,13 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
this.order_type(doc);
},
+ make_pick_ticket() {
+ frappe.model.open_mapped_doc({
+ method: "erpnext.selling.doctype.sales_order.sales_order.make_pick_ticket",
+ frm: this.frm
+ })
+ },
+
make_work_order() {
var me = this;
this.frm.call({
diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py
index 09dc9a9932..181ac33782 100755
--- a/erpnext/selling/doctype/sales_order/sales_order.py
+++ b/erpnext/selling/doctype/sales_order/sales_order.py
@@ -996,3 +996,80 @@ def make_raw_material_request(items, company, sales_order, project=None):
def make_inter_company_purchase_order(source_name, target_doc=None):
from erpnext.accounts.doctype.sales_invoice.sales_invoice import make_inter_company_transaction
return make_inter_company_transaction("Sales Order", source_name, target_doc)
+
+@frappe.whitelist()
+def make_pick_ticket(source_name, target_doc=None, offset=None):
+
+ doc = get_mapped_doc("Sales Order", source_name, {
+ "Sales Order": {
+ "doctype": "Pick Ticket",
+ "validation": {
+ "docstatus": ["=", 1]
+ },
+ "field_map": {
+ "name": "reference_name",
+ },
+ },
+ "Sales Order Item": {
+ "doctype": 'Pick Ticket Item',
+ "field_map": {
+ 'item_code': 'item'
+ },
+ }
+ }, target_doc, postprocess)
+
+ return doc
+
+def get_available_items(item):
+ # gets all items available in different warehouses
+ # FIFO
+ available_items = frappe.get_all('Bin', filters={
+ 'item_code': item,
+ 'actual_qty': ['>', 0]
+ }, fields=['warehouse', 'actual_qty as qty'], order_by='creation')
+
+ return available_items
+
+def get_items_with_warehouse_and_quantity(item_doc):
+ items = []
+ item_locations = get_available_items(item_doc.item)
+ if not item_locations: return
+
+ remaining_qty = item_doc.qty
+
+ while remaining_qty > 0 and item_locations:
+ item_location = item_locations.pop(0)
+ qty = item_doc.qty if item_location.qty >= item_doc.qty else item_location.qty
+ items.append({
+ 'qty': qty,
+ 'warehouse': item_location.warehouse
+ })
+ remaining_qty -= qty
+
+ return items
+
+def postprocess(source, doc):
+ for item in doc.items:
+ data = get_items_with_warehouse_and_quantity(item)
+ item.delete()
+
+ for item_info in data:
+ print(item_info)
+ pick_item = frappe.new_doc('Pick Ticket Item', doc, 'items')
+ pick_item.update(item_info)
+ print(pick_item.qty)
+
+ for item in doc.items:
+ if item.has_serial_no:
+ serial_nos = frappe.get_all('Serial No', {
+ 'item_code': item.item,
+ 'warehouse': item.warehouse
+ }, limit=item.qty, order_by='purchase_date')
+ item.serial_no = '\n'.join([serial_no.name for serial_no in serial_nos])
+
+ if item.has_batch_no:
+ serial_nos = frappe.get_all('Serial No', {
+ 'item_code': item.item,
+ 'warehouse': item.warehouse
+ }, limit=item.qty, order_by='purchase_date')
+ item.serial_no = '\n'.join([serial_no.name for serial_no in serial_nos])
\ No newline at end of file
diff --git a/erpnext/stock/doctype/pick_ticket_item/pick_ticket_item.json b/erpnext/stock/doctype/pick_ticket_item/pick_ticket_item.json
index 705172553e..cba0743c8a 100644
--- a/erpnext/stock/doctype/pick_ticket_item/pick_ticket_item.json
+++ b/erpnext/stock/doctype/pick_ticket_item/pick_ticket_item.json
@@ -10,7 +10,11 @@
"reference_document_item",
"warehouse",
"qty",
- "picked_qty"
+ "picked_qty",
+ "has_serial_no",
+ "has_batch_no",
+ "serial_no",
+ "batch_no"
],
"fields": [
{
@@ -56,10 +60,39 @@
"fieldtype": "Data",
"hidden": 1,
"label": "Reference Document Item"
+ },
+ {
+ "depends_on": "has_serial_no",
+ "fieldname": "serial_no",
+ "fieldtype": "Small Text",
+ "label": "Serial No"
+ },
+ {
+ "depends_on": "has_batch_no",
+ "fieldname": "batch_no",
+ "fieldtype": "Link",
+ "label": "Batch No",
+ "options": "Batch"
+ },
+ {
+ "default": "0",
+ "fetch_from": "item.has_serial_no",
+ "fieldname": "has_serial_no",
+ "fieldtype": "Check",
+ "label": "Has Serial No",
+ "read_only": 1
+ },
+ {
+ "default": "0",
+ "fetch_from": "item.has_batch_no",
+ "fieldname": "has_batch_no",
+ "fieldtype": "Check",
+ "label": "Has Batch No",
+ "read_only": 1
}
],
"istable": 1,
- "modified": "2019-07-11 16:34:52.853146",
+ "modified": "2019-07-24 11:05:27.407791",
"modified_by": "Administrator",
"module": "Stock",
"name": "Pick Ticket Item",
From 6d0c6a17d971c944b50b7c928f53f08d0eef05ed Mon Sep 17 00:00:00 2001
From: Rohit Waghchaure
Date: Tue, 23 Jul 2019 23:13:33 +0530
Subject: [PATCH 091/484] fix: multi currency bank reco issue
---
.../doctype/bank_transaction/bank_transaction.py | 14 +++++++++++---
.../bank_reconciliation/bank_reconciliation.py | 2 --
2 files changed, 11 insertions(+), 5 deletions(-)
diff --git a/erpnext/accounts/doctype/bank_transaction/bank_transaction.py b/erpnext/accounts/doctype/bank_transaction/bank_transaction.py
index f943b34581..4e5057048f 100644
--- a/erpnext/accounts/doctype/bank_transaction/bank_transaction.py
+++ b/erpnext/accounts/doctype/bank_transaction/bank_transaction.py
@@ -45,7 +45,7 @@ class BankTransaction(StatusUpdater):
def clear_linked_payment_entries(self):
for payment_entry in self.payment_entries:
allocated_amount = get_total_allocated_amount(payment_entry)
- paid_amount = get_paid_amount(payment_entry)
+ paid_amount = get_paid_amount(payment_entry, self.currency)
if paid_amount and allocated_amount:
if flt(allocated_amount[0]["allocated_amount"]) > flt(paid_amount):
@@ -80,9 +80,17 @@ def get_total_allocated_amount(payment_entry):
AND
bt.docstatus = 1""", (payment_entry.payment_document, payment_entry.payment_entry), as_dict=True)
-def get_paid_amount(payment_entry):
+def get_paid_amount(payment_entry, currency):
if payment_entry.payment_document in ["Payment Entry", "Sales Invoice", "Purchase Invoice"]:
- return frappe.db.get_value(payment_entry.payment_document, payment_entry.payment_entry, "paid_amount")
+
+ paid_amount_field = "paid_amount"
+ if payment_entry.payment_document == 'Payment Entry':
+ doc = frappe.get_doc("Payment Entry", payment_entry.payment_entry)
+ paid_amount_field = ("base_paid_amount"
+ if doc.paid_to_account_currency == currency else "paid_amount")
+
+ return frappe.db.get_value(payment_entry.payment_document,
+ payment_entry.payment_entry, paid_amount_field)
elif payment_entry.payment_document == "Journal Entry":
return frappe.db.get_value(payment_entry.payment_document, payment_entry.payment_entry, "total_credit")
diff --git a/erpnext/accounts/page/bank_reconciliation/bank_reconciliation.py b/erpnext/accounts/page/bank_reconciliation/bank_reconciliation.py
index 36c939996f..bd4b4d7e0b 100644
--- a/erpnext/accounts/page/bank_reconciliation/bank_reconciliation.py
+++ b/erpnext/accounts/page/bank_reconciliation/bank_reconciliation.py
@@ -124,8 +124,6 @@ def check_matching_amount(bank_account, company, transaction):
'txt': '%%%s%%' % amount
}, as_dict=True)
- frappe.errprint(journal_entries)
-
if transaction.credit > 0:
sales_invoices = frappe.db.sql("""
SELECT
From 4865eabee5152d43f4b827d1ec03a2cf050b4705 Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Wed, 24 Jul 2019 13:37:54 +0530
Subject: [PATCH 092/484] fix: add Company by default in session defaults
(#18460)
---
erpnext/setup/install.py | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/erpnext/setup/install.py b/erpnext/setup/install.py
index 03da833dec..5e85f7d526 100644
--- a/erpnext/setup/install.py
+++ b/erpnext/setup/install.py
@@ -22,6 +22,7 @@ def after_install():
add_all_roles_to("Administrator")
create_default_cash_flow_mapper_templates()
create_default_success_action()
+ add_company_to_session_defaults()
frappe.db.commit()
@@ -84,3 +85,10 @@ def create_default_success_action():
if not frappe.db.exists('Success Action', success_action.get("ref_doctype")):
doc = frappe.get_doc(success_action)
doc.insert(ignore_permissions=True)
+
+def add_company_to_session_defaults():
+ settings = frappe.get_single("Session Default Settings")
+ settings.append("session_defaults", {
+ "ref_doctype": "Company"
+ })
+ settings.save()
From 0576ad5ef997c9b92ae110b2fca4e012d09d4712 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Wed, 24 Jul 2019 15:16:03 +0530
Subject: [PATCH 093/484] fix: Move pick list creation code to picklist.py file
---
.../doctype/sales_order/sales_order.py | 76 +------------------
.../doctype/pick_ticket/pick_ticket.json | 17 +----
.../stock/doctype/pick_ticket/pick_ticket.py | 67 +++++++++++++++-
.../pick_ticket_item/pick_ticket_item.json | 46 +++++++++--
4 files changed, 109 insertions(+), 97 deletions(-)
diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py
index 181ac33782..1f889ab58c 100755
--- a/erpnext/selling/doctype/sales_order/sales_order.py
+++ b/erpnext/selling/doctype/sales_order/sales_order.py
@@ -999,77 +999,5 @@ def make_inter_company_purchase_order(source_name, target_doc=None):
@frappe.whitelist()
def make_pick_ticket(source_name, target_doc=None, offset=None):
-
- doc = get_mapped_doc("Sales Order", source_name, {
- "Sales Order": {
- "doctype": "Pick Ticket",
- "validation": {
- "docstatus": ["=", 1]
- },
- "field_map": {
- "name": "reference_name",
- },
- },
- "Sales Order Item": {
- "doctype": 'Pick Ticket Item',
- "field_map": {
- 'item_code': 'item'
- },
- }
- }, target_doc, postprocess)
-
- return doc
-
-def get_available_items(item):
- # gets all items available in different warehouses
- # FIFO
- available_items = frappe.get_all('Bin', filters={
- 'item_code': item,
- 'actual_qty': ['>', 0]
- }, fields=['warehouse', 'actual_qty as qty'], order_by='creation')
-
- return available_items
-
-def get_items_with_warehouse_and_quantity(item_doc):
- items = []
- item_locations = get_available_items(item_doc.item)
- if not item_locations: return
-
- remaining_qty = item_doc.qty
-
- while remaining_qty > 0 and item_locations:
- item_location = item_locations.pop(0)
- qty = item_doc.qty if item_location.qty >= item_doc.qty else item_location.qty
- items.append({
- 'qty': qty,
- 'warehouse': item_location.warehouse
- })
- remaining_qty -= qty
-
- return items
-
-def postprocess(source, doc):
- for item in doc.items:
- data = get_items_with_warehouse_and_quantity(item)
- item.delete()
-
- for item_info in data:
- print(item_info)
- pick_item = frappe.new_doc('Pick Ticket Item', doc, 'items')
- pick_item.update(item_info)
- print(pick_item.qty)
-
- for item in doc.items:
- if item.has_serial_no:
- serial_nos = frappe.get_all('Serial No', {
- 'item_code': item.item,
- 'warehouse': item.warehouse
- }, limit=item.qty, order_by='purchase_date')
- item.serial_no = '\n'.join([serial_no.name for serial_no in serial_nos])
-
- if item.has_batch_no:
- serial_nos = frappe.get_all('Serial No', {
- 'item_code': item.item,
- 'warehouse': item.warehouse
- }, limit=item.qty, order_by='purchase_date')
- item.serial_no = '\n'.join([serial_no.name for serial_no in serial_nos])
\ No newline at end of file
+ from erpnext.stock.doctype.pick_ticket.pick_ticket import get_pick_list
+ return get_pick_list('Sales Order', source_name, 'items')
diff --git a/erpnext/stock/doctype/pick_ticket/pick_ticket.json b/erpnext/stock/doctype/pick_ticket/pick_ticket.json
index 28aa6997cb..392786f030 100644
--- a/erpnext/stock/doctype/pick_ticket/pick_ticket.json
+++ b/erpnext/stock/doctype/pick_ticket/pick_ticket.json
@@ -1,11 +1,10 @@
{
+ "autoname": "PICK.####",
"creation": "2019-07-11 16:03:13.681045",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
- "reference_doctype",
- "reference_name",
"company",
"column_break_4",
"group_warehouse",
@@ -13,18 +12,6 @@
"items"
],
"fields": [
- {
- "fieldname": "reference_doctype",
- "fieldtype": "Select",
- "label": "Reference Document Type",
- "options": "Sales Order\nWork Order"
- },
- {
- "fieldname": "reference_name",
- "fieldtype": "Dynamic Link",
- "label": "Reference Name",
- "options": "reference_doctype"
- },
{
"fieldname": "items",
"fieldtype": "Table",
@@ -53,7 +40,7 @@
"fieldtype": "Section Break"
}
],
- "modified": "2019-07-12 11:42:03.508514",
+ "modified": "2019-07-24 14:59:44.542987",
"modified_by": "Administrator",
"module": "Stock",
"name": "Pick Ticket",
diff --git a/erpnext/stock/doctype/pick_ticket/pick_ticket.py b/erpnext/stock/doctype/pick_ticket/pick_ticket.py
index 7f2e89bb6c..8982688451 100644
--- a/erpnext/stock/doctype/pick_ticket/pick_ticket.py
+++ b/erpnext/stock/doctype/pick_ticket/pick_ticket.py
@@ -3,8 +3,73 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-# import frappe
+import frappe
from frappe.model.document import Document
class PickTicket(Document):
pass
+
+def get_pick_list(reference_doctype, reference_name, items_field):
+ doc = frappe.new_doc('Pick Ticket')
+ reference_doc = frappe.get_doc(reference_doctype, reference_name)
+ doc.company = reference_doc.company
+ items = reference_doc.get(items_field)
+
+ add_picklist_items(items, doc, reference_doc)
+
+ doc.insert()
+
+ return doc
+
+def get_available_items(item):
+ # gets all items available in different warehouses
+ # FIFO
+ available_items = frappe.get_all('Bin', filters={
+ 'item_code': item,
+ 'actual_qty': ['>', 0]
+ }, fields=['warehouse', 'actual_qty as qty'], order_by='creation')
+
+ return available_items
+
+def get_items_with_warehouse_and_quantity(item_doc, reference_doc):
+ items = []
+ item_locations = get_available_items(item_doc.item_code)
+ if not item_locations: return items
+
+ remaining_qty = item_doc.qty
+
+ while remaining_qty > 0 and item_locations:
+ item_location = item_locations.pop(0)
+ qty = remaining_qty if item_location.qty >= remaining_qty else item_location.qty
+ items.append({
+ 'item': item_doc.item_code,
+ 'qty': qty,
+ 'warehouse': item_location.warehouse,
+ 'reference_doctype': reference_doc.doctype,
+ 'reference_name': reference_doc.name
+ })
+ remaining_qty -= qty
+
+ return items
+
+def add_picklist_items(reference_items, doc, reference_doc):
+ for item in reference_items:
+ data = get_items_with_warehouse_and_quantity(item, reference_doc)
+
+ for item_info in data:
+ doc.append('items', item_info)
+
+ for item in doc.get('items'):
+ if item.has_serial_no:
+ serial_nos = frappe.get_all('Serial No', {
+ 'item_code': item.item,
+ 'warehouse': item.warehouse
+ }, limit=item.qty, order_by='purchase_date')
+ item.serial_no = '\n'.join([serial_no.name for serial_no in serial_nos])
+
+ # if item.has_batch_no:
+ # serial_nos = frappe.get_all('Batch', {
+ # 'item_code': item.item,
+ # 'warehouse': item.warehouse
+ # }, limit=item.qty, order_by='purchase_date')
+ # item.serial_no = '\n'.join([serial_no.name for serial_no in serial_nos])
\ No newline at end of file
diff --git a/erpnext/stock/doctype/pick_ticket_item/pick_ticket_item.json b/erpnext/stock/doctype/pick_ticket_item/pick_ticket_item.json
index cba0743c8a..33a42737b1 100644
--- a/erpnext/stock/doctype/pick_ticket_item/pick_ticket_item.json
+++ b/erpnext/stock/doctype/pick_ticket_item/pick_ticket_item.json
@@ -6,15 +6,20 @@
"field_order": [
"item",
"item_name",
+ "column_break_2",
"description",
- "reference_document_item",
+ "has_batch_no",
+ "has_serial_no",
+ "section_break_5",
"warehouse",
"qty",
"picked_qty",
- "has_serial_no",
- "has_batch_no",
"serial_no",
- "batch_no"
+ "batch_no",
+ "reference_section",
+ "reference_doctype",
+ "reference_name",
+ "reference_document_item"
],
"fields": [
{
@@ -47,13 +52,15 @@
"fetch_from": "item.item_name",
"fieldname": "item_name",
"fieldtype": "Data",
- "label": "Item Name"
+ "label": "Item Name",
+ "read_only": 1
},
{
"fetch_from": "item.description",
"fieldname": "description",
"fieldtype": "Text",
- "label": "Description"
+ "label": "Description",
+ "read_only": 1
},
{
"fieldname": "reference_document_item",
@@ -89,10 +96,35 @@
"fieldtype": "Check",
"label": "Has Batch No",
"read_only": 1
+ },
+ {
+ "fieldname": "reference_section",
+ "fieldtype": "Section Break",
+ "label": "Reference"
+ },
+ {
+ "fieldname": "reference_doctype",
+ "fieldtype": "Select",
+ "label": "Reference Document Type",
+ "options": "Sales Order\nWork Order"
+ },
+ {
+ "fieldname": "reference_name",
+ "fieldtype": "Dynamic Link",
+ "label": "Reference Document",
+ "options": "reference_doctype"
+ },
+ {
+ "fieldname": "column_break_2",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "section_break_5",
+ "fieldtype": "Section Break"
}
],
"istable": 1,
- "modified": "2019-07-24 11:05:27.407791",
+ "modified": "2019-07-24 15:09:35.712289",
"modified_by": "Administrator",
"module": "Stock",
"name": "Pick Ticket Item",
From cb19ee457c8a1644642ad81b34ef6e7390687115 Mon Sep 17 00:00:00 2001
From: Shivam Mishra
Date: Wed, 24 Jul 2019 16:05:59 +0530
Subject: [PATCH 094/484] fix: urls for changelog
---
erpnext/change_log/v12/v12_0_0.md | 50 +++++++++++++++----------------
1 file changed, 25 insertions(+), 25 deletions(-)
diff --git a/erpnext/change_log/v12/v12_0_0.md b/erpnext/change_log/v12/v12_0_0.md
index dcbc9a00dd..198e3d77d6 100644
--- a/erpnext/change_log/v12/v12_0_0.md
+++ b/erpnext/change_log/v12/v12_0_0.md
@@ -1,41 +1,41 @@
# Version 12 Release Notes
### Accounting
-1. [Accounting Dimensions](/docs/user/manual/en/accounts/accounting-dimensions)
-1. [Chart of Accounts Importer](/docs/user/manual/en/setting-up/chart-of-accounts-importer)
-1. [Invoice Discounting](/docs/user/manual/en/accounts/invoice_discounting)
+1. [Accounting Dimensions](https://erpnext.com/docs/user/manual/en/accounts/accounting-dimensions)
+1. [Chart of Accounts Importer](https://erpnext.com/docs/user/manual/en/setting-up/chart-of-accounts-importer)
+1. [Invoice Discounting](https://erpnext.com/docs/user/manual/en/accounts/invoice_discounting)
1. [Tally Migrator](https://github.com/frappe/erpnext/pull/17405)
### Stock
-1. [Serialized & Batched Item Reconciliation](/docs/user/manual/en/setting-up/stock-reconciliation#12-for-serialized-items)
+1. [Serialized & Batched Item Reconciliation](https://erpnext.com/docs/user/manual/en/setting-up/stock-reconciliation#12-for-serialized-items)
1. [Auto Fetch Serialized Items](/version-12/release-notes/features#new-upload-dialog)
-1. [Item Tax Templates](/docs/user/manual/en/accounts/item-tax-template)
+1. [Item Tax Templates](https://erpnext.com/docs/user/manual/en/accounts/item-tax-template)
### HR
-1. [Auto Attendance](/docs/user/manual/en/human-resources/auto-attendance)
-1. [Employee Skill Map](/docs/user/manual/en/human-resources/employee_skill_map)
-1. [Encrypted Salary Slips](/docs/user/manual/en/human-resources/hr-settings#24-encrypt-salary-slips-in-emails)
-1. [Leave Ledger](/docs/user/manual/en/human-resources/leave-ledger-entry)
-1. [Staffing Plan](/docs/user/manual/en/human-resources/staffing-plan)
+1. [Auto Attendance](https://erpnext.com/docs/user/manual/en/human-resources/auto-attendance)
+1. [Employee Skill Map](https://erpnext.com/docs/user/manual/en/human-resources/employee_skill_map)
+1. [Encrypted Salary Slips](https://erpnext.com/docs/user/manual/en/human-resources/hr-settings#24-encrypt-salary-slips-in-emails)
+1. [Leave Ledger](https://erpnext.com/docs/user/manual/en/human-resources/leave-ledger-entry)
+1. [Staffing Plan](https://erpnext.com/docs/user/manual/en/human-resources/staffing-plan)
### CRM
-1. [Promotional Scheme](/docs/user/manual/en/accounts/promotional-schemes)
-1. [SLA](/docs/user/manual/en/support/service-level-agreement)
-1. [Exotel Call Integration](/docs/user/manual/en/erpnext_integration/exotel_integration)
-1. [Email Campaign](/docs/user/manual/en/CRM/email-campaign)
+1. [Promotional Scheme](https://erpnext.com/docs/user/manual/en/accounts/promotional-schemes)
+1. [SLA](https://erpnext.com/docs/user/manual/en/support/service-level-agreement)
+1. [Exotel Call Integration](https://erpnext.com/docs/user/manual/en/erpnext_integration/exotel_integration)
+1. [Email Campaign](https://erpnext.com/docs/user/manual/en/CRM/email-campaign)
### Domain Specific Features
-1. [Learning Management System](/docs/user/manual/en/education/setting-up-lms)
-1. [Quality Management System](/docs/user/manual/en/quality-management)
-1. [Production Planning Enhancements](/docs/user/manual/en/manufacturing/production-plan/planning-for-material-requests)
-1. [Project Template](/docs/user/manual/en/projects/project-template)
+1. [Learning Management System](https://erpnext.com/docs/user/manual/en/education/setting-up-lms)
+1. [Quality Management System](https://erpnext.com/docs/user/manual/en/quality-management)
+1. [Production Planning Enhancements](https://erpnext.com/docs/user/manual/en/manufacturing/production-plan/planning-for-material-requests)
+1. [Project Template](https://erpnext.com/docs/user/manual/en/projects/project-template)
### New Reports
-1. [Bank Remittance](/docs/user/manual/en/human-resources/human-resources-reports#bank-remittance-report)
-1. [BOM Explorer](/docs/user/manual/en/stock/articles/bom_explorer)
-1. [Billing Summary Report](/docs/user/manual/en/projects/reports/billing_summary_reports)
+1. [Bank Remittance](https://erpnext.com/docs/user/manual/en/human-resources/human-resources-reports#bank-remittance-report)
+1. [BOM Explorer](https://erpnext.com/docs/user/manual/en/stock/articles/bom_explorer)
+1. [Billing Summary Report](https://erpnext.com/docs/user/manual/en/projects/reports/billing_summary_reports)
1. [Procurement Tracker Report](docs/user/manual/en/buying/articles/procurement-tracker-report)
-1. [Loan Repayment](/docs/user/manual/en/human-resources/human-resources-reports#loan-repayment-report)
-1. [GSTR-3B](/docs/user/manual/en/regional/india/gst-3b-report)
-1. [Sales Partner](/docs/user/manual/en/selling/sales-partner#sales-partner-reports)
-1. [Sales Partner Target Variance based on Item Group](sales-partner-target-variance-based-on-item-group)
+1. [Loan Repayment](https://erpnext.com/docs/user/manual/en/human-resources/human-resources-reports#loan-repayment-report)
+1. [GSTR-3B](https://erpnext.com/docs/user/manual/en/regional/india/gst-3b-report)
+1. [Sales Partner](https://erpnext.com/docs/user/manual/en/selling/sales-partner#sales-partner-reports)
+1. [Sales Partner Target Variance based on Item Group](https://erpnext.com/docs/user/manual/en/selling/sales-partner#sales-partner-target-variance-based-on-item-group)
From 8b08684e07a571182108d7c332118a1bfc330bf4 Mon Sep 17 00:00:00 2001
From: Shivam Mishra
Date: Wed, 24 Jul 2019 16:10:34 +0530
Subject: [PATCH 095/484] fix: more url fixes
---
erpnext/change_log/v12/v12_0_0.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/change_log/v12/v12_0_0.md b/erpnext/change_log/v12/v12_0_0.md
index 198e3d77d6..c2f33a8b7a 100644
--- a/erpnext/change_log/v12/v12_0_0.md
+++ b/erpnext/change_log/v12/v12_0_0.md
@@ -8,7 +8,7 @@
### Stock
1. [Serialized & Batched Item Reconciliation](https://erpnext.com/docs/user/manual/en/setting-up/stock-reconciliation#12-for-serialized-items)
-1. [Auto Fetch Serialized Items](/version-12/release-notes/features#new-upload-dialog)
+1. [Auto Fetch Serialized Items](https://erpnext.com/version-12/release-notes/features#new-upload-dialog)
1. [Item Tax Templates](https://erpnext.com/docs/user/manual/en/accounts/item-tax-template)
### HR
From 192db7d6233482434b7b55b05ba94596158308de Mon Sep 17 00:00:00 2001
From: Shivam Mishra
Date: Wed, 24 Jul 2019 16:22:37 +0530
Subject: [PATCH 096/484] fix: url fixes for changelog
---
erpnext/change_log/v12/v12_0_0.md | 52 +++++++++++++++----------------
1 file changed, 26 insertions(+), 26 deletions(-)
diff --git a/erpnext/change_log/v12/v12_0_0.md b/erpnext/change_log/v12/v12_0_0.md
index dcbc9a00dd..c2f33a8b7a 100644
--- a/erpnext/change_log/v12/v12_0_0.md
+++ b/erpnext/change_log/v12/v12_0_0.md
@@ -1,41 +1,41 @@
# Version 12 Release Notes
### Accounting
-1. [Accounting Dimensions](/docs/user/manual/en/accounts/accounting-dimensions)
-1. [Chart of Accounts Importer](/docs/user/manual/en/setting-up/chart-of-accounts-importer)
-1. [Invoice Discounting](/docs/user/manual/en/accounts/invoice_discounting)
+1. [Accounting Dimensions](https://erpnext.com/docs/user/manual/en/accounts/accounting-dimensions)
+1. [Chart of Accounts Importer](https://erpnext.com/docs/user/manual/en/setting-up/chart-of-accounts-importer)
+1. [Invoice Discounting](https://erpnext.com/docs/user/manual/en/accounts/invoice_discounting)
1. [Tally Migrator](https://github.com/frappe/erpnext/pull/17405)
### Stock
-1. [Serialized & Batched Item Reconciliation](/docs/user/manual/en/setting-up/stock-reconciliation#12-for-serialized-items)
-1. [Auto Fetch Serialized Items](/version-12/release-notes/features#new-upload-dialog)
-1. [Item Tax Templates](/docs/user/manual/en/accounts/item-tax-template)
+1. [Serialized & Batched Item Reconciliation](https://erpnext.com/docs/user/manual/en/setting-up/stock-reconciliation#12-for-serialized-items)
+1. [Auto Fetch Serialized Items](https://erpnext.com/version-12/release-notes/features#new-upload-dialog)
+1. [Item Tax Templates](https://erpnext.com/docs/user/manual/en/accounts/item-tax-template)
### HR
-1. [Auto Attendance](/docs/user/manual/en/human-resources/auto-attendance)
-1. [Employee Skill Map](/docs/user/manual/en/human-resources/employee_skill_map)
-1. [Encrypted Salary Slips](/docs/user/manual/en/human-resources/hr-settings#24-encrypt-salary-slips-in-emails)
-1. [Leave Ledger](/docs/user/manual/en/human-resources/leave-ledger-entry)
-1. [Staffing Plan](/docs/user/manual/en/human-resources/staffing-plan)
+1. [Auto Attendance](https://erpnext.com/docs/user/manual/en/human-resources/auto-attendance)
+1. [Employee Skill Map](https://erpnext.com/docs/user/manual/en/human-resources/employee_skill_map)
+1. [Encrypted Salary Slips](https://erpnext.com/docs/user/manual/en/human-resources/hr-settings#24-encrypt-salary-slips-in-emails)
+1. [Leave Ledger](https://erpnext.com/docs/user/manual/en/human-resources/leave-ledger-entry)
+1. [Staffing Plan](https://erpnext.com/docs/user/manual/en/human-resources/staffing-plan)
### CRM
-1. [Promotional Scheme](/docs/user/manual/en/accounts/promotional-schemes)
-1. [SLA](/docs/user/manual/en/support/service-level-agreement)
-1. [Exotel Call Integration](/docs/user/manual/en/erpnext_integration/exotel_integration)
-1. [Email Campaign](/docs/user/manual/en/CRM/email-campaign)
+1. [Promotional Scheme](https://erpnext.com/docs/user/manual/en/accounts/promotional-schemes)
+1. [SLA](https://erpnext.com/docs/user/manual/en/support/service-level-agreement)
+1. [Exotel Call Integration](https://erpnext.com/docs/user/manual/en/erpnext_integration/exotel_integration)
+1. [Email Campaign](https://erpnext.com/docs/user/manual/en/CRM/email-campaign)
### Domain Specific Features
-1. [Learning Management System](/docs/user/manual/en/education/setting-up-lms)
-1. [Quality Management System](/docs/user/manual/en/quality-management)
-1. [Production Planning Enhancements](/docs/user/manual/en/manufacturing/production-plan/planning-for-material-requests)
-1. [Project Template](/docs/user/manual/en/projects/project-template)
+1. [Learning Management System](https://erpnext.com/docs/user/manual/en/education/setting-up-lms)
+1. [Quality Management System](https://erpnext.com/docs/user/manual/en/quality-management)
+1. [Production Planning Enhancements](https://erpnext.com/docs/user/manual/en/manufacturing/production-plan/planning-for-material-requests)
+1. [Project Template](https://erpnext.com/docs/user/manual/en/projects/project-template)
### New Reports
-1. [Bank Remittance](/docs/user/manual/en/human-resources/human-resources-reports#bank-remittance-report)
-1. [BOM Explorer](/docs/user/manual/en/stock/articles/bom_explorer)
-1. [Billing Summary Report](/docs/user/manual/en/projects/reports/billing_summary_reports)
+1. [Bank Remittance](https://erpnext.com/docs/user/manual/en/human-resources/human-resources-reports#bank-remittance-report)
+1. [BOM Explorer](https://erpnext.com/docs/user/manual/en/stock/articles/bom_explorer)
+1. [Billing Summary Report](https://erpnext.com/docs/user/manual/en/projects/reports/billing_summary_reports)
1. [Procurement Tracker Report](docs/user/manual/en/buying/articles/procurement-tracker-report)
-1. [Loan Repayment](/docs/user/manual/en/human-resources/human-resources-reports#loan-repayment-report)
-1. [GSTR-3B](/docs/user/manual/en/regional/india/gst-3b-report)
-1. [Sales Partner](/docs/user/manual/en/selling/sales-partner#sales-partner-reports)
-1. [Sales Partner Target Variance based on Item Group](sales-partner-target-variance-based-on-item-group)
+1. [Loan Repayment](https://erpnext.com/docs/user/manual/en/human-resources/human-resources-reports#loan-repayment-report)
+1. [GSTR-3B](https://erpnext.com/docs/user/manual/en/regional/india/gst-3b-report)
+1. [Sales Partner](https://erpnext.com/docs/user/manual/en/selling/sales-partner#sales-partner-reports)
+1. [Sales Partner Target Variance based on Item Group](https://erpnext.com/docs/user/manual/en/selling/sales-partner#sales-partner-target-variance-based-on-item-group)
From 89339bb80c3ff90b6bf273f1a55a183071c9e4f1 Mon Sep 17 00:00:00 2001
From: deepeshgarg007
Date: Wed, 24 Jul 2019 21:32:55 +0530
Subject: [PATCH 097/484] fix: GSTR-1 query fix
---
erpnext/regional/report/gstr_1/gstr_1.py | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/erpnext/regional/report/gstr_1/gstr_1.py b/erpnext/regional/report/gstr_1/gstr_1.py
index e8c170e721..2da1085732 100644
--- a/erpnext/regional/report/gstr_1/gstr_1.py
+++ b/erpnext/regional/report/gstr_1/gstr_1.py
@@ -161,8 +161,9 @@ class Gstr1Report(object):
"gst_category": ["in", ["Registered Regular", "Deemed Export", "SEZ"]]
})
- conditions += """ and ifnull(gst_category, '') != 'Overseas' and is_return != 1
- and customer in ({0})""".format(", ".join([frappe.db.escape(c.name) for c in customers]))
+ if customers:
+ conditions += """ and ifnull(gst_category, '') != 'Overseas' and is_return != 1
+ and customer in ({0})""".format(", ".join([frappe.db.escape(c.name) for c in customers]))
if self.filters.get("type_of_business") in ("B2C Large", "B2C Small"):
b2c_limit = frappe.db.get_single_value('GST Settings', 'b2c_limit')
@@ -174,11 +175,11 @@ class Gstr1Report(object):
"gst_category": ["in", ["Unregistered"]]
})
- if self.filters.get("type_of_business") == "B2C Large":
+ if self.filters.get("type_of_business") == "B2C Large" and customers:
conditions += """ and SUBSTR(place_of_supply, 1, 2) != SUBSTR(company_gstin, 1, 2)
and grand_total > {0} and is_return != 1 and customer in ({1})""".\
format(flt(b2c_limit), ", ".join([frappe.db.escape(c.name) for c in customers]))
- elif self.filters.get("type_of_business") == "B2C Small":
+ elif self.filters.get("type_of_business") == "B2C Small" and customers:
conditions += """ and (
SUBSTR(place_of_supply, 1, 2) = SUBSTR(company_gstin, 1, 2)
or grand_total <= {0}) and is_return != 1 and customer in ({1})""".\
From 3b318005333472449fdab8eff6cf34d4bc2d8252 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Thu, 25 Jul 2019 11:22:45 +0530
Subject: [PATCH 098/484] fix: Add logic to set batch no [WIP]
- Add pick ticket reference item
---
.../doctype/pick_ticket/pick_ticket.json | 21 +++++++--
.../stock/doctype/pick_ticket/pick_ticket.py | 46 ++++++++++++-------
.../pick_ticket_item/pick_ticket_item.json | 24 ++++++----
.../pick_ticket_reference_item.js | 8 ++++
.../pick_ticket_reference_item.json | 27 +++++++++++
.../pick_ticket_reference_item.py | 10 ++++
6 files changed, 107 insertions(+), 29 deletions(-)
create mode 100644 erpnext/stock/doctype/pick_ticket_reference_item/pick_ticket_reference_item.js
create mode 100644 erpnext/stock/doctype/pick_ticket_reference_item/pick_ticket_reference_item.json
create mode 100644 erpnext/stock/doctype/pick_ticket_reference_item/pick_ticket_reference_item.py
diff --git a/erpnext/stock/doctype/pick_ticket/pick_ticket.json b/erpnext/stock/doctype/pick_ticket/pick_ticket.json
index 392786f030..fe331ac3c4 100644
--- a/erpnext/stock/doctype/pick_ticket/pick_ticket.json
+++ b/erpnext/stock/doctype/pick_ticket/pick_ticket.json
@@ -8,6 +8,8 @@
"company",
"column_break_4",
"group_warehouse",
+ "section_break_4",
+ "reference_document_items",
"section_break_6",
"items"
],
@@ -15,8 +17,9 @@
{
"fieldname": "items",
"fieldtype": "Table",
- "label": "Items",
- "options": "Pick Ticket Item"
+ "label": "Items Locations",
+ "options": "Pick Ticket Item",
+ "read_only": 1
},
{
"description": "Items under this warehouse will be suggested",
@@ -38,9 +41,21 @@
{
"fieldname": "section_break_6",
"fieldtype": "Section Break"
+ },
+ {
+ "collapsible": 1,
+ "fieldname": "section_break_4",
+ "fieldtype": "Section Break",
+ "label": "Reference Items"
+ },
+ {
+ "fieldname": "reference_document_items",
+ "fieldtype": "Table",
+ "label": "Reference Document Items",
+ "options": "Pick Ticket Reference Item"
}
],
- "modified": "2019-07-24 14:59:44.542987",
+ "modified": "2019-07-24 16:13:51.668880",
"modified_by": "Administrator",
"module": "Stock",
"name": "Pick Ticket",
diff --git a/erpnext/stock/doctype/pick_ticket/pick_ticket.py b/erpnext/stock/doctype/pick_ticket/pick_ticket.py
index 8982688451..4c5fdb8297 100644
--- a/erpnext/stock/doctype/pick_ticket/pick_ticket.py
+++ b/erpnext/stock/doctype/pick_ticket/pick_ticket.py
@@ -14,11 +14,8 @@ def get_pick_list(reference_doctype, reference_name, items_field):
reference_doc = frappe.get_doc(reference_doctype, reference_name)
doc.company = reference_doc.company
items = reference_doc.get(items_field)
-
add_picklist_items(items, doc, reference_doc)
-
- doc.insert()
-
+ doc.save()
return doc
def get_available_items(item):
@@ -34,10 +31,12 @@ def get_available_items(item):
def get_items_with_warehouse_and_quantity(item_doc, reference_doc):
items = []
item_locations = get_available_items(item_doc.item_code)
- if not item_locations: return items
-
remaining_qty = item_doc.qty
+ if not item_locations:
+ print('{} qty of {} is out of stock. Skipping...'.format(remaining_qty, item_doc.item))
+ return items
+
while remaining_qty > 0 and item_locations:
item_location = item_locations.pop(0)
qty = remaining_qty if item_location.qty >= remaining_qty else item_location.qty
@@ -59,17 +58,30 @@ def add_picklist_items(reference_items, doc, reference_doc):
for item_info in data:
doc.append('items', item_info)
+ doc.insert()
+
for item in doc.get('items'):
if item.has_serial_no:
- serial_nos = frappe.get_all('Serial No', {
- 'item_code': item.item,
- 'warehouse': item.warehouse
- }, limit=item.qty, order_by='purchase_date')
- item.serial_no = '\n'.join([serial_no.name for serial_no in serial_nos])
+ set_serial_nos(item)
+ elif item.has_batch_no:
+ set_batch_no(item, doc)
- # if item.has_batch_no:
- # serial_nos = frappe.get_all('Batch', {
- # 'item_code': item.item,
- # 'warehouse': item.warehouse
- # }, limit=item.qty, order_by='purchase_date')
- # item.serial_no = '\n'.join([serial_no.name for serial_no in serial_nos])
\ No newline at end of file
+def set_serial_nos(item):
+ serial_nos = frappe.get_all('Serial No', {
+ 'item_code': item.item,
+ 'warehouse': item.warehouse
+ }, limit=item.qty, order_by='purchase_date')
+ item.serial_no = '\n'.join([serial_no.name for serial_no in serial_nos])
+
+def set_batch_no(item, doc):
+ batches = frappe.get_all('Stock Ledger Entry',
+ fields=['batch_no', 'sum(actual_qty) as qty'],
+ filters={
+ 'item_code': item.item,
+ 'warehouse': item.warehouse
+ },
+ group_by='warehouse, batch_no, item_code')
+
+ if batches:
+ # TODO: check expiry and split item if batch is more than 1
+ item.batch_no = batches[0].batch_no
\ No newline at end of file
diff --git a/erpnext/stock/doctype/pick_ticket_item/pick_ticket_item.json b/erpnext/stock/doctype/pick_ticket_item/pick_ticket_item.json
index 33a42737b1..6db32845e7 100644
--- a/erpnext/stock/doctype/pick_ticket_item/pick_ticket_item.json
+++ b/erpnext/stock/doctype/pick_ticket_item/pick_ticket_item.json
@@ -33,7 +33,8 @@
"fieldname": "qty",
"fieldtype": "Float",
"in_list_view": 1,
- "label": "Qty"
+ "label": "Qty",
+ "read_only": 1
},
{
"fieldname": "picked_qty",
@@ -46,7 +47,8 @@
"fieldtype": "Link",
"in_list_view": 1,
"label": "Warehouse",
- "options": "Warehouse"
+ "options": "Warehouse",
+ "read_only": 1
},
{
"fetch_from": "item.item_name",
@@ -66,20 +68,22 @@
"fieldname": "reference_document_item",
"fieldtype": "Data",
"hidden": 1,
- "label": "Reference Document Item"
+ "label": "Reference Document Item",
+ "read_only": 1
},
{
"depends_on": "has_serial_no",
"fieldname": "serial_no",
"fieldtype": "Small Text",
- "label": "Serial No"
+ "label": "Serial No",
+ "read_only": 1
},
{
- "depends_on": "has_batch_no",
"fieldname": "batch_no",
"fieldtype": "Link",
"label": "Batch No",
- "options": "Batch"
+ "options": "Batch",
+ "read_only": 1
},
{
"default": "0",
@@ -106,13 +110,15 @@
"fieldname": "reference_doctype",
"fieldtype": "Select",
"label": "Reference Document Type",
- "options": "Sales Order\nWork Order"
+ "options": "Sales Order\nWork Order",
+ "read_only": 1
},
{
"fieldname": "reference_name",
"fieldtype": "Dynamic Link",
"label": "Reference Document",
- "options": "reference_doctype"
+ "options": "reference_doctype",
+ "read_only": 1
},
{
"fieldname": "column_break_2",
@@ -124,7 +130,7 @@
}
],
"istable": 1,
- "modified": "2019-07-24 15:09:35.712289",
+ "modified": "2019-07-25 11:18:58.478250",
"modified_by": "Administrator",
"module": "Stock",
"name": "Pick Ticket Item",
diff --git a/erpnext/stock/doctype/pick_ticket_reference_item/pick_ticket_reference_item.js b/erpnext/stock/doctype/pick_ticket_reference_item/pick_ticket_reference_item.js
new file mode 100644
index 0000000000..a3f909659b
--- /dev/null
+++ b/erpnext/stock/doctype/pick_ticket_reference_item/pick_ticket_reference_item.js
@@ -0,0 +1,8 @@
+// Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Pick Ticket Reference Item', {
+ // refresh: function(frm) {
+
+ // }
+});
diff --git a/erpnext/stock/doctype/pick_ticket_reference_item/pick_ticket_reference_item.json b/erpnext/stock/doctype/pick_ticket_reference_item/pick_ticket_reference_item.json
new file mode 100644
index 0000000000..446e075686
--- /dev/null
+++ b/erpnext/stock/doctype/pick_ticket_reference_item/pick_ticket_reference_item.json
@@ -0,0 +1,27 @@
+{
+ "creation": "2019-07-24 16:11:07.415562",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "item"
+ ],
+ "fields": [
+ {
+ "fieldname": "item",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Item",
+ "options": "Item"
+ }
+ ],
+ "istable": 1,
+ "modified": "2019-07-24 16:12:58.000378",
+ "modified_by": "Administrator",
+ "module": "Stock",
+ "name": "Pick Ticket Reference Item",
+ "owner": "Administrator",
+ "permissions": [],
+ "sort_field": "modified",
+ "sort_order": "DESC"
+}
\ No newline at end of file
diff --git a/erpnext/stock/doctype/pick_ticket_reference_item/pick_ticket_reference_item.py b/erpnext/stock/doctype/pick_ticket_reference_item/pick_ticket_reference_item.py
new file mode 100644
index 0000000000..412be75f88
--- /dev/null
+++ b/erpnext/stock/doctype/pick_ticket_reference_item/pick_ticket_reference_item.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+# import frappe
+from frappe.model.document import Document
+
+class PickTicketReferenceItem(Document):
+ pass
From 53dc0c52cacf2a53a71cad845b16f28a7776ab91 Mon Sep 17 00:00:00 2001
From: deepeshgarg007
Date: Thu, 25 Jul 2019 12:23:40 +0530
Subject: [PATCH 099/484] Dynamic link issue fix in Bank reconciliation
statement
---
.../bank_reconciliation_statement.py | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/erpnext/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.py b/erpnext/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.py
index 1923f78cf8..63317c52d8 100644
--- a/erpnext/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.py
+++ b/erpnext/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.py
@@ -58,8 +58,7 @@ def get_columns():
{
"fieldname": "payment_document",
"label": _("Payment Document Type"),
- "fieldtype": "Link",
- "options": "DocType",
+ "fieldtype": "Data",
"width": 220
},
{
From 5ca3e83a005827316613c57da92b402fd4ce18c4 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Thu, 25 Jul 2019 14:35:39 +0530
Subject: [PATCH 100/484] feat: add ledger link in hr config
---
erpnext/config/hr.py | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/erpnext/config/hr.py b/erpnext/config/hr.py
index 0367755595..1f597f080d 100644
--- a/erpnext/config/hr.py
+++ b/erpnext/config/hr.py
@@ -134,6 +134,12 @@ def get_data():
"name": "Employee Leave Balance",
"doctype": "Leave Application"
},
+ {
+ "type": "report",
+ "is_query_report": True,
+ "name": "Leave Ledger Entry",
+ "doctype": "Leave Ledger Entry"
+ },
]
},
{
From 029de1a244ccad4ad2dc4c51f7815bd6f5361fd8 Mon Sep 17 00:00:00 2001
From: Aditya Hase
Date: Wed, 24 Jul 2019 15:18:52 +0530
Subject: [PATCH 101/484] fix(travis): Remove unnecessary commands
---
.travis.yml | 6 ------
1 file changed, 6 deletions(-)
diff --git a/.travis.yml b/.travis.yml
index a8a0d82614..ace0bfb243 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -14,12 +14,6 @@ services:
install:
# fix mongodb travis error
- - sudo rm /etc/apt/sources.list.d/mongodb*.list
- - pip install flake8==3.3.0
- - flake8 . --count --select=E901,E999,F821,F822,F823 --show-source --statistics
- - sudo rm /etc/apt/sources.list.d/docker.list
- - sudo apt-get install hhvm && rm -rf /home/travis/.kiex/
- - sudo apt-get purge -y mysql-common mysql-server mysql-client
- nvm install 10
- pip install python-coveralls
- wget https://raw.githubusercontent.com/frappe/bench/master/playbooks/install.py
From e0e78fb0e2407e1fcdf16962c6399705acb70a45 Mon Sep 17 00:00:00 2001
From: Aditya Hase
Date: Thu, 25 Jul 2019 13:42:43 +0530
Subject: [PATCH 102/484] fix(travis): Restructure build matrix
---
.travis.yml | 36 +++++++++++++++++++++++++-----------
travis/run-tests.sh | 12 ------------
2 files changed, 25 insertions(+), 23 deletions(-)
delete mode 100755 travis/run-tests.sh
diff --git a/.travis.yml b/.travis.yml
index ace0bfb243..0660779b2d 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,17 +1,34 @@
-language: python
dist: trusty
-python:
- - "2.7"
- - "3.6"
-
-env:
- - TEST_TYPE="Server Side Test"
- - TEST_TYPE="Patch Test"
+language: python
services:
- mysql
+jobs:
+ include:
+ - name: "Python 2.7 Server Side Test"
+ python: 2.7
+ script: bench run-tests --app erpnext --coverage
+
+ - name: "Python 3.6 Server Side Test"
+ python: 3.6
+ script: bench run-tests --app erpnext --coverage
+
+ - name: "Python 2.7 Patch Test"
+ python: 2.7
+ before_script:
+ - wget http://build.erpnext.com/20171108_190013_955977f8_database.sql.gz
+ - bench --force restore ~/frappe-bench/20171108_190013_955977f8_database.sql.gz --mariadb-root-password travis
+ script: bench migrate
+
+ - name: "Python 3.6 Patch Test"
+ python: 3.6
+ before_script:
+ - wget http://build.erpnext.com/20171108_190013_955977f8_database.sql.gz
+ - bench --force restore ~/frappe-bench/20171108_190013_955977f8_database.sql.gz --mariadb-root-password travis
+ script: bench migrate
+
install:
# fix mongodb travis error
- nvm install 10
@@ -38,8 +55,5 @@ before_script:
- bench start &
- sleep 10
-script:
- - bash $TRAVIS_BUILD_DIR/travis/run-tests.sh
-
after_script:
- coveralls -b apps/erpnext -d ../../sites/.coverage
diff --git a/travis/run-tests.sh b/travis/run-tests.sh
deleted file mode 100755
index 7cfd64833b..0000000000
--- a/travis/run-tests.sh
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/bin/bash
-
-set -e
-
-if [[ $TEST_TYPE == 'Server Side Test' ]]; then
- bench run-tests --app erpnext --coverage
-
-elif [[ $TEST_TYPE == 'Patch Test' ]]; then
- wget http://build.erpnext.com/20171108_190013_955977f8_database.sql.gz
- bench --force restore ~/frappe-bench/20171108_190013_955977f8_database.sql.gz --mariadb-root-password travis
- bench migrate
-fi
From 9b24a4201798d09ee5c79ecb4054c24bb2d989c0 Mon Sep 17 00:00:00 2001
From: Aditya Hase
Date: Thu, 25 Jul 2019 21:09:34 +0530
Subject: [PATCH 103/484] fix(travis): Use MariaDB 10.3
---
.travis.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.travis.yml b/.travis.yml
index 0660779b2d..1561d6ca0f 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -2,8 +2,8 @@ dist: trusty
language: python
-services:
- - mysql
+addons:
+ mariadb: 10.3
jobs:
include:
From 2fb9e8a94d749e38358b80dce70b8feef91fa16b Mon Sep 17 00:00:00 2001
From: Aditya Hase
Date: Thu, 25 Jul 2019 21:10:06 +0530
Subject: [PATCH 104/484] fix(travis): Install coverall after tests
---
.travis.yml | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/.travis.yml b/.travis.yml
index 1561d6ca0f..c51c6b078e 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -30,9 +30,7 @@ jobs:
script: bench migrate
install:
- # fix mongodb travis error
- nvm install 10
- - pip install python-coveralls
- wget https://raw.githubusercontent.com/frappe/bench/master/playbooks/install.py
- sudo python install.py --develop --user travis --without-bench-setup
- sudo pip install -e ~/bench
@@ -56,4 +54,5 @@ before_script:
- sleep 10
after_script:
+ - pip install python-coveralls
- coveralls -b apps/erpnext -d ../../sites/.coverage
From 3f6ac2d993939043685331bb315f26141dac9fde Mon Sep 17 00:00:00 2001
From: Aditya Hase
Date: Thu, 25 Jul 2019 21:11:18 +0530
Subject: [PATCH 105/484] fix(travis): Do not execute install.py
---
.travis.yml | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/.travis.yml b/.travis.yml
index c51c6b078e..047a98640f 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -30,10 +30,11 @@ jobs:
script: bench migrate
install:
+ - cd ~
- nvm install 10
- - wget https://raw.githubusercontent.com/frappe/bench/master/playbooks/install.py
- - sudo python install.py --develop --user travis --without-bench-setup
- - sudo pip install -e ~/bench
+
+ - git clone https://github.com/frappe/bench --depth 1
+ - pip install -e ./bench
- rm $TRAVIS_BUILD_DIR/.git/shallow
- bash $TRAVIS_BUILD_DIR/travis/bench_init.sh
From 23f24d13dd1c37ecbcccff7f8e4a66841324bfd8 Mon Sep 17 00:00:00 2001
From: Aditya Hase
Date: Thu, 25 Jul 2019 21:15:30 +0530
Subject: [PATCH 106/484] fix(travis): Remove travis/bench_init.sh
---
.travis.yml | 5 +++--
travis/bench_init.sh | 8 --------
2 files changed, 3 insertions(+), 10 deletions(-)
delete mode 100755 travis/bench_init.sh
diff --git a/.travis.yml b/.travis.yml
index 047a98640f..e0a2ead3d5 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -36,8 +36,9 @@ install:
- git clone https://github.com/frappe/bench --depth 1
- pip install -e ./bench
- - rm $TRAVIS_BUILD_DIR/.git/shallow
- - bash $TRAVIS_BUILD_DIR/travis/bench_init.sh
+ - git clone https://github.com/frappe/frappe --branch $TRAVIS_BRANCH --depth 1
+ - bench init --frappe-path ~/frappe --python $(which python) frappe-bench
+
- cp -r $TRAVIS_BUILD_DIR/test_sites/test_site ~/frappe-bench/sites/
before_script:
diff --git a/travis/bench_init.sh b/travis/bench_init.sh
deleted file mode 100755
index f96269b919..0000000000
--- a/travis/bench_init.sh
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/bin/bash
-
-cd ~/
-curl -I https://github.com/frappe/frappe/tree/$TRAVIS_BRANCH | head -n 1 | cut -d $' ' -f2 | (
- read response;
- [ $response == '200' ] && branch=$TRAVIS_BRANCH || branch='develop';
- bench init frappe-bench --frappe-path https://github.com/frappe/frappe.git --frappe-branch $branch --python $(which python)
-)
From e2b16e3edbebaae0746d83077eb32c226b6f9f29 Mon Sep 17 00:00:00 2001
From: Aditya Hase
Date: Thu, 25 Jul 2019 21:18:05 +0530
Subject: [PATCH 107/484] fix(travis): Remove unused files
---
.travis.yml | 3 ++-
{test_sites/test_site => .travis}/site_config.json | 3 +--
test_sites/apps.txt | 1 -
3 files changed, 3 insertions(+), 4 deletions(-)
rename {test_sites/test_site => .travis}/site_config.json (81%)
delete mode 100644 test_sites/apps.txt
diff --git a/.travis.yml b/.travis.yml
index e0a2ead3d5..108df91e40 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -39,7 +39,8 @@ install:
- git clone https://github.com/frappe/frappe --branch $TRAVIS_BRANCH --depth 1
- bench init --frappe-path ~/frappe --python $(which python) frappe-bench
- - cp -r $TRAVIS_BUILD_DIR/test_sites/test_site ~/frappe-bench/sites/
+ - mkdir ~/frappe-bench/sites/test_site
+ - cp -r $TRAVIS_BUILD_DIR/.travis/site_config.json ~/frappe-bench/sites/test_site/
before_script:
- mysql -u root -ptravis -e 'create database test_frappe'
diff --git a/test_sites/test_site/site_config.json b/.travis/site_config.json
similarity index 81%
rename from test_sites/test_site/site_config.json
rename to .travis/site_config.json
index 7a4d106508..695f6c3517 100644
--- a/test_sites/test_site/site_config.json
+++ b/.travis/site_config.json
@@ -6,8 +6,7 @@
"mail_login": "test@example.com",
"mail_password": "test",
"admin_password": "admin",
- "run_selenium_tests": 1,
"root_password": "travis",
- "host_name": "http://localhost:8000",
+ "host_name": "http://test_site:8000",
"install_apps": ["erpnext"]
}
\ No newline at end of file
diff --git a/test_sites/apps.txt b/test_sites/apps.txt
deleted file mode 100644
index ee6454915c..0000000000
--- a/test_sites/apps.txt
+++ /dev/null
@@ -1 +0,0 @@
-erpnext
\ No newline at end of file
From 185e2a2fd8926e96e0311cbaff0c95acb57f50d7 Mon Sep 17 00:00:00 2001
From: Aditya Hase
Date: Thu, 25 Jul 2019 21:19:30 +0530
Subject: [PATCH 108/484] fix(travis): Setup MariaDB
---
.travis.yml | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/.travis.yml b/.travis.yml
index 108df91e40..5ecede08e8 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -43,9 +43,15 @@ install:
- cp -r $TRAVIS_BUILD_DIR/.travis/site_config.json ~/frappe-bench/sites/test_site/
before_script:
- - mysql -u root -ptravis -e 'create database test_frappe'
- - echo "USE mysql;\nCREATE USER 'test_frappe'@'localhost' IDENTIFIED BY 'test_frappe';\nFLUSH PRIVILEGES;\n" | mysql -u root -ptravis
- - echo "USE mysql;\nGRANT ALL PRIVILEGES ON \`test_frappe\`.* TO 'test_frappe'@'localhost';\n" | mysql -u root -ptravis
+ - mysql -u root -e "SET GLOBAL character_set_server = 'utf8mb4'"
+ - mysql -u root -e "SET GLOBAL collation_server = 'utf8mb4_unicode_ci'"
+
+ - mysql -u root -e "CREATE DATABASE test_frappe"
+ - mysql -u root -e "CREATE USER 'test_frappe'@'localhost' IDENTIFIED BY 'test_frappe'"
+ - mysql -u root -e "GRANT ALL PRIVILEGES ON \`test_frappe\`.* TO 'test_frappe'@'localhost'"
+
+ - mysql -u root -e "UPDATE mysql.user SET Password=PASSWORD('travis') WHERE User='root'"
+ - mysql -u root -e "FLUSH PRIVILEGES"
- cd ~/frappe-bench
- bench get-app erpnext $TRAVIS_BUILD_DIR
From fb2ec7186da073c79954e4723479258d547e0253 Mon Sep 17 00:00:00 2001
From: Aditya Hase
Date: Thu, 25 Jul 2019 21:21:19 +0530
Subject: [PATCH 109/484] fix(travis): Do not use use_site
---
.travis.yml | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/.travis.yml b/.travis.yml
index 5ecede08e8..9840ad5e15 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -3,31 +3,32 @@ dist: trusty
language: python
addons:
+ hosts: test_site
mariadb: 10.3
jobs:
include:
- name: "Python 2.7 Server Side Test"
python: 2.7
- script: bench run-tests --app erpnext --coverage
+ script: bench --site test_site run-tests --app erpnext --coverage
- name: "Python 3.6 Server Side Test"
python: 3.6
- script: bench run-tests --app erpnext --coverage
+ script: bench --site test_site run-tests --app erpnext --coverage
- name: "Python 2.7 Patch Test"
python: 2.7
before_script:
- wget http://build.erpnext.com/20171108_190013_955977f8_database.sql.gz
- bench --force restore ~/frappe-bench/20171108_190013_955977f8_database.sql.gz --mariadb-root-password travis
- script: bench migrate
+ script: bench --site test_site migrate
- name: "Python 3.6 Patch Test"
python: 3.6
before_script:
- wget http://build.erpnext.com/20171108_190013_955977f8_database.sql.gz
- - bench --force restore ~/frappe-bench/20171108_190013_955977f8_database.sql.gz --mariadb-root-password travis
- script: bench migrate
+ - bench --site test_site --force restore ~/frappe-bench/20171108_190013_955977f8_database.sql.gz --mariadb-root-password travis
+ script: bench --site test_site migrate
install:
- cd ~
@@ -55,9 +56,8 @@ before_script:
- cd ~/frappe-bench
- bench get-app erpnext $TRAVIS_BUILD_DIR
- - bench use test_site
- - bench reinstall --mariadb-root-username root --mariadb-root-password travis --yes
- - bench scheduler disable
+ - bench --site test_site reinstall --mariadb-root-username root --mariadb-root-password travis --yes
+ - bench --site test_site scheduler disable
- sed -i 's/9000/9001/g' sites/common_site_config.json
- bench start &
- sleep 10
From 1e9e471714c04b06cab77353132cfa377dc0eff0 Mon Sep 17 00:00:00 2001
From: Aditya Hase
Date: Thu, 25 Jul 2019 21:21:54 +0530
Subject: [PATCH 110/484] fix(travis): Do not disable scheduler using CLI
---
.travis.yml | 1 -
1 file changed, 1 deletion(-)
diff --git a/.travis.yml b/.travis.yml
index 9840ad5e15..cd593a8aed 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -57,7 +57,6 @@ before_script:
- cd ~/frappe-bench
- bench get-app erpnext $TRAVIS_BUILD_DIR
- bench --site test_site reinstall --mariadb-root-username root --mariadb-root-password travis --yes
- - bench --site test_site scheduler disable
- sed -i 's/9000/9001/g' sites/common_site_config.json
- bench start &
- sleep 10
From 903e87899b6e94bef3cba133271a0a249d8bbc81 Mon Sep 17 00:00:00 2001
From: Aditya Hase
Date: Thu, 25 Jul 2019 21:23:24 +0530
Subject: [PATCH 111/484] fix(travis): Execute get-app and reinstall after
bench start
---
.travis.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.travis.yml b/.travis.yml
index cd593a8aed..d3581e2b8d 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -55,11 +55,11 @@ before_script:
- mysql -u root -e "FLUSH PRIVILEGES"
- cd ~/frappe-bench
- - bench get-app erpnext $TRAVIS_BUILD_DIR
- - bench --site test_site reinstall --mariadb-root-username root --mariadb-root-password travis --yes
- sed -i 's/9000/9001/g' sites/common_site_config.json
- bench start &
- sleep 10
+ - bench get-app erpnext $TRAVIS_BUILD_DIR
+ - bench --site test_site reinstall --mariadb-root-username root --mariadb-root-password travis --yes
after_script:
- pip install python-coveralls
From e4f78a0b6a208de4583bc81281dd9595ed17d8cd Mon Sep 17 00:00:00 2001
From: Aditya Hase
Date: Thu, 25 Jul 2019 21:23:43 +0530
Subject: [PATCH 112/484] perf(travis): Do not waste 10 seconds
---
.travis.yml | 1 -
1 file changed, 1 deletion(-)
diff --git a/.travis.yml b/.travis.yml
index d3581e2b8d..23627f51f0 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -57,7 +57,6 @@ before_script:
- cd ~/frappe-bench
- sed -i 's/9000/9001/g' sites/common_site_config.json
- bench start &
- - sleep 10
- bench get-app erpnext $TRAVIS_BUILD_DIR
- bench --site test_site reinstall --mariadb-root-username root --mariadb-root-password travis --yes
From 7c44adad3eb7c58f2011f5fbeffc11a1c046ffbd Mon Sep 17 00:00:00 2001
From: Aditya Hase
Date: Thu, 25 Jul 2019 21:25:53 +0530
Subject: [PATCH 113/484] fix(travis): Use MariaDB credentials from
site_config.json
---
.travis.yml | 2 +-
.travis/site_config.json | 1 +
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/.travis.yml b/.travis.yml
index 23627f51f0..54d77db7c6 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -58,7 +58,7 @@ before_script:
- sed -i 's/9000/9001/g' sites/common_site_config.json
- bench start &
- bench get-app erpnext $TRAVIS_BUILD_DIR
- - bench --site test_site reinstall --mariadb-root-username root --mariadb-root-password travis --yes
+ - bench --site test_site reinstall --yes
after_script:
- pip install python-coveralls
diff --git a/.travis/site_config.json b/.travis/site_config.json
index 695f6c3517..dae80095d4 100644
--- a/.travis/site_config.json
+++ b/.travis/site_config.json
@@ -6,6 +6,7 @@
"mail_login": "test@example.com",
"mail_password": "test",
"admin_password": "admin",
+ "root_login": "root",
"root_password": "travis",
"host_name": "http://test_site:8000",
"install_apps": ["erpnext"]
From 30628b016b8b7226c38abc17332e47a885e19b5e Mon Sep 17 00:00:00 2001
From: Aditya Hase
Date: Thu, 25 Jul 2019 21:27:20 +0530
Subject: [PATCH 114/484] perf(travis): Remove unnecessary processes from
Procfile
---
.travis.yml | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/.travis.yml b/.travis.yml
index 54d77db7c6..2637d978e4 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -55,7 +55,12 @@ before_script:
- mysql -u root -e "FLUSH PRIVILEGES"
- cd ~/frappe-bench
- - sed -i 's/9000/9001/g' sites/common_site_config.json
+
+ - sed -i 's/watch:/# watch:/g' Procfile
+ - sed -i 's/schedule:/# schedule:/g' Procfile
+ - sed -i 's/socketio:/# socketio:/g' Procfile
+ - sed -i 's/redis_socketio:/# redis_socketio:/g' Procfile
+
- bench start &
- bench get-app erpnext $TRAVIS_BUILD_DIR
- bench --site test_site reinstall --yes
From e31284189f3caa769f94ffea11aaf340ac1ee37e Mon Sep 17 00:00:00 2001
From: Aditya Hase
Date: Thu, 25 Jul 2019 21:28:15 +0530
Subject: [PATCH 115/484] perf(travis): Do not build assets
---
.travis.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.travis.yml b/.travis.yml
index 2637d978e4..e3d432a5ae 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -38,7 +38,7 @@ install:
- pip install -e ./bench
- git clone https://github.com/frappe/frappe --branch $TRAVIS_BRANCH --depth 1
- - bench init --frappe-path ~/frappe --python $(which python) frappe-bench
+ - bench init --skip-assets --frappe-path ~/frappe --python $(which python) frappe-bench
- mkdir ~/frappe-bench/sites/test_site
- cp -r $TRAVIS_BUILD_DIR/.travis/site_config.json ~/frappe-bench/sites/test_site/
From 50e2d4aa6a73d4fd5025d2b737631b8d39cd87f2 Mon Sep 17 00:00:00 2001
From: Aditya Hase
Date: Thu, 25 Jul 2019 21:36:22 +0530
Subject: [PATCH 116/484] perf(travis): Use travis optimizations
---
.travis.yml | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/.travis.yml b/.travis.yml
index e3d432a5ae..ee385d0e08 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -2,6 +2,12 @@ dist: trusty
language: python
+git:
+ depth: 1
+
+cache:
+ - pip
+
addons:
hosts: test_site
mariadb: 10.3
From 6076443b6be47261a1fe784dd34871601afa7b08 Mon Sep 17 00:00:00 2001
From: Aditya Hase
Date: Thu, 25 Jul 2019 21:38:07 +0530
Subject: [PATCH 117/484] fix(travis): Execute get-app before bench start
---
.travis.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.travis.yml b/.travis.yml
index ee385d0e08..2f7637372e 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -67,8 +67,8 @@ before_script:
- sed -i 's/socketio:/# socketio:/g' Procfile
- sed -i 's/redis_socketio:/# redis_socketio:/g' Procfile
- - bench start &
- bench get-app erpnext $TRAVIS_BUILD_DIR
+ - bench start &
- bench --site test_site reinstall --yes
after_script:
From 7b39aa7f91462b6076ca3c89fd0280af10f9b53d Mon Sep 17 00:00:00 2001
From: Aditya Hase
Date: Thu, 25 Jul 2019 21:39:30 +0530
Subject: [PATCH 118/484] fix(travis): Merge install and before_script
---
.travis.yml | 1 -
1 file changed, 1 deletion(-)
diff --git a/.travis.yml b/.travis.yml
index 2f7637372e..fb941f3ff3 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -49,7 +49,6 @@ install:
- mkdir ~/frappe-bench/sites/test_site
- cp -r $TRAVIS_BUILD_DIR/.travis/site_config.json ~/frappe-bench/sites/test_site/
-before_script:
- mysql -u root -e "SET GLOBAL character_set_server = 'utf8mb4'"
- mysql -u root -e "SET GLOBAL collation_server = 'utf8mb4_unicode_ci'"
From ac431c8e333a72b1c8faf9bcbe31c7301557d52a Mon Sep 17 00:00:00 2001
From: Aditya Hase
Date: Thu, 25 Jul 2019 21:50:46 +0530
Subject: [PATCH 119/484] fix(travis): Use --site parameter
---
.travis.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.travis.yml b/.travis.yml
index fb941f3ff3..9b51c85eca 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -26,7 +26,7 @@ jobs:
python: 2.7
before_script:
- wget http://build.erpnext.com/20171108_190013_955977f8_database.sql.gz
- - bench --force restore ~/frappe-bench/20171108_190013_955977f8_database.sql.gz --mariadb-root-password travis
+ - bench --site test_site --force restore ~/frappe-bench/20171108_190013_955977f8_database.sql.gz --mariadb-root-password travis
script: bench --site test_site migrate
- name: "Python 3.6 Patch Test"
From 0046357b864c53cda22ccc0202c1623a24e2bfa0 Mon Sep 17 00:00:00 2001
From: Aditya Hase
Date: Thu, 25 Jul 2019 21:51:12 +0530
Subject: [PATCH 120/484] fix(travis): Remove redundant arguments
---
.travis.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.travis.yml b/.travis.yml
index 9b51c85eca..53c67fe15d 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -26,14 +26,14 @@ jobs:
python: 2.7
before_script:
- wget http://build.erpnext.com/20171108_190013_955977f8_database.sql.gz
- - bench --site test_site --force restore ~/frappe-bench/20171108_190013_955977f8_database.sql.gz --mariadb-root-password travis
+ - bench --site test_site --force restore ~/frappe-bench/20171108_190013_955977f8_database.sql.gz
script: bench --site test_site migrate
- name: "Python 3.6 Patch Test"
python: 3.6
before_script:
- wget http://build.erpnext.com/20171108_190013_955977f8_database.sql.gz
- - bench --site test_site --force restore ~/frappe-bench/20171108_190013_955977f8_database.sql.gz --mariadb-root-password travis
+ - bench --site test_site --force restore ~/frappe-bench/20171108_190013_955977f8_database.sql.gz
script: bench --site test_site migrate
install:
From b6906c58d1ae6d7c6febdf196e1b098eb5dec8f0 Mon Sep 17 00:00:00 2001
From: Aditya Hase
Date: Thu, 25 Jul 2019 22:40:26 +0530
Subject: [PATCH 121/484] fix(travis): Install wkhtmltopdf
---
.travis.yml | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/.travis.yml b/.travis.yml
index 53c67fe15d..40afeee8d4 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -59,6 +59,11 @@ install:
- mysql -u root -e "UPDATE mysql.user SET Password=PASSWORD('travis') WHERE User='root'"
- mysql -u root -e "FLUSH PRIVILEGES"
+ - wget -O /tmp/wkhtmltox.tar.xz https://github.com/frappe/wkhtmltopdf/raw/master/wkhtmltox-0.12.3_linux-generic-amd64.tar.xz
+ - tar -xf /tmp/wkhtmltox.tar.xz -C /tmp
+ - sudo mv /tmp/wkhtmltox/bin/wkhtmltopdf /usr/local/bin/wkhtmltopdf
+ - sudo chmod o+x /usr/local/bin/wkhtmltopdf
+
- cd ~/frappe-bench
- sed -i 's/watch:/# watch:/g' Procfile
From 0d333894c930b96878e374b3bb474a5e2d5329f9 Mon Sep 17 00:00:00 2001
From: Aditya Hase
Date: Thu, 25 Jul 2019 23:37:43 +0530
Subject: [PATCH 122/484] perf(tests): Use setUpClass and tearDownClass instead
of setUp and tearDown
---
.../doctype/purchase_invoice/test_purchase_invoice.py | 7 +++++--
.../accounts/doctype/sales_invoice/test_sales_invoice.py | 7 +++++--
2 files changed, 10 insertions(+), 4 deletions(-)
diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
index b4d584fbde..6deee38148 100644
--- a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
@@ -20,11 +20,13 @@ test_dependencies = ["Item", "Cost Center", "Payment Term", "Payment Terms Templ
test_ignore = ["Serial No"]
class TestPurchaseInvoice(unittest.TestCase):
- def setUp(self):
+ @classmethod
+ def setUpClass(self):
unlink_payment_on_cancel_of_invoice()
frappe.db.set_value("Buying Settings", None, "allow_multiple_items", 1)
- def tearDown(self):
+ @classmethod
+ def tearDownClass(self):
unlink_payment_on_cancel_of_invoice(0)
def test_gl_entries_without_perpetual_inventory(self):
@@ -91,6 +93,7 @@ class TestPurchaseInvoice(unittest.TestCase):
pi_doc = frappe.get_doc('Purchase Invoice', pi_doc.name)
self.assertRaises(frappe.LinkExistsError, pi_doc.cancel)
+ unlink_payment_on_cancel_of_invoice()
def test_purchase_invoice_for_blocked_supplier(self):
supplier = frappe.get_doc('Supplier', '_Test Supplier')
diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
index 52470fde95..dff55947df 100644
--- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
@@ -29,10 +29,12 @@ class TestSalesInvoice(unittest.TestCase):
w.submit()
return w
- def setUp(self):
+ @classmethod
+ def setUpClass(self):
unlink_payment_on_cancel_of_invoice()
- def tearDown(self):
+ @classmethod
+ def tearDownClass(self):
unlink_payment_on_cancel_of_invoice(0)
def test_timestamp_change(self):
@@ -135,6 +137,7 @@ class TestSalesInvoice(unittest.TestCase):
unlink_payment_on_cancel_of_invoice(0)
si = frappe.get_doc('Sales Invoice', si.name)
self.assertRaises(frappe.LinkExistsError, si.cancel)
+ unlink_payment_on_cancel_of_invoice()
def test_sales_invoice_calculation_export_currency(self):
si = frappe.copy_doc(test_records[2])
From 8773d931be206dc702d3b56e3aabc5a5d1ef63f4 Mon Sep 17 00:00:00 2001
From: Aditya Hase
Date: Fri, 26 Jul 2019 00:38:51 +0530
Subject: [PATCH 123/484] perf(tests): Do not unnecessarily create companies
---
erpnext/tests/test_notifications.py | 44 ++++++++++-------------------
1 file changed, 15 insertions(+), 29 deletions(-)
diff --git a/erpnext/tests/test_notifications.py b/erpnext/tests/test_notifications.py
index 596bc80dee..1fd90beef0 100644
--- a/erpnext/tests/test_notifications.py
+++ b/erpnext/tests/test_notifications.py
@@ -2,45 +2,31 @@
# MIT License. See license.txt
from __future__ import unicode_literals
+import frappe
import unittest
from frappe.desk import notifications
from frappe.test_runner import make_test_objects
class TestNotifications(unittest.TestCase):
- def setUp(self):
- test_records_company = [
- {
- "abbr": "_TC6",
- "company_name": "_Test Company 6",
- "country": "India",
- "default_currency": "INR",
- "doctype": "Company",
- "domain": "Manufacturing",
- "monthly_sales_target": 2000,
- "chart_of_accounts": "Standard"
- },
- {
- "abbr": "_TC7",
- "company_name": "_Test Company 7",
- "country": "United States",
- "default_currency": "USD",
- "doctype": "Company",
- "domain": "Retail",
- "monthly_sales_target": 10000,
- "total_monthly_sales": 1000,
- "chart_of_accounts": "Standard"
- },
- ]
-
- make_test_objects('Company', test_records=test_records_company, reset=True)
-
def test_get_notifications_for_targets(self):
'''
Test notification config entries for targets as percentages
'''
+ company = frappe.get_all("Company")[0]
+ frappe.db.set_value("Company", company.name, "monthly_sales_target", 10000)
+ frappe.db.set_value("Company", company.name, "total_monthly_sales", 1000)
+
config = notifications.get_notification_config()
doc_target_percents = notifications.get_notifications_for_targets(config, {})
- self.assertEqual(doc_target_percents['Company']['_Test Company 7'], 10)
- self.assertEqual(doc_target_percents['Company']['_Test Company 6'], 0)
+
+ self.assertEqual(doc_target_percents['Company'][company.name], 10)
+
+ frappe.db.set_value("Company", company.name, "monthly_sales_target", 2000)
+ frappe.db.set_value("Company", company.name, "total_monthly_sales", 0)
+
+ config = notifications.get_notification_config()
+ doc_target_percents = notifications.get_notifications_for_targets(config, {})
+
+ self.assertEqual(doc_target_percents['Company'][company.name], 0)
From d1bb274c22836202bb6aef67ff9a512f4e40e866 Mon Sep 17 00:00:00 2001
From: Aditya Hase
Date: Fri, 26 Jul 2019 01:09:01 +0530
Subject: [PATCH 124/484] perf(tests): Use country with lesser fixtures
---
.../report/procurement_tracker/test_procurement_tracker.py | 2 +-
erpnext/hr/doctype/staffing_plan/test_staffing_plan.py | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/erpnext/buying/report/procurement_tracker/test_procurement_tracker.py b/erpnext/buying/report/procurement_tracker/test_procurement_tracker.py
index 4a13f385bb..bebf0ccec5 100644
--- a/erpnext/buying/report/procurement_tracker/test_procurement_tracker.py
+++ b/erpnext/buying/report/procurement_tracker/test_procurement_tracker.py
@@ -30,7 +30,7 @@ class TestProcurementTracker(unittest.TestCase):
company_name="_Test Procurement Company",
abbr="_TPC",
default_currency="INR",
- country="India"
+ country="Pakistan"
)).insert()
warehouse = create_warehouse("_Test Procurement Warehouse", company="_Test Procurement Company")
mr = make_material_request(company="_Test Procurement Company", warehouse=warehouse)
diff --git a/erpnext/hr/doctype/staffing_plan/test_staffing_plan.py b/erpnext/hr/doctype/staffing_plan/test_staffing_plan.py
index 4a0ce1800a..9ba6d5e63f 100644
--- a/erpnext/hr/doctype/staffing_plan/test_staffing_plan.py
+++ b/erpnext/hr/doctype/staffing_plan/test_staffing_plan.py
@@ -92,5 +92,5 @@ def make_company():
company.abbr = "_TC10"
company.parent_company = "_Test Company"
company.default_currency = "INR"
- company.country = "India"
+ company.country = "Pakistan"
company.insert()
\ No newline at end of file
From bd69f43322455b7a40fe4a30d1076eeda0420c07 Mon Sep 17 00:00:00 2001
From: Aditya Hase
Date: Fri, 26 Jul 2019 03:05:40 +0530
Subject: [PATCH 125/484] fix(stock): Fix travis builds
---
.../stock/doctype/stock_reconciliation/stock_reconciliation.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
index d9e62c7931..98a8c59483 100644
--- a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
+++ b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
@@ -327,7 +327,8 @@ class StockReconciliation(StockController):
if sl_entries:
sl_entries.reverse()
- self.make_sl_entries(sl_entries)
+ allow_negative_stock = frappe.db.get_value("Stock Settings", None, "allow_negative_stock")
+ self.make_sl_entries(sl_entries, allow_negative_stock=allow_negative_stock)
# repost future entries for selected item_code, warehouse
for entries in existing_entries:
From f4314a25b633ca8db9b7ffabd5c957cd09b6a356 Mon Sep 17 00:00:00 2001
From: Aditya Hase
Date: Fri, 26 Jul 2019 03:06:23 +0530
Subject: [PATCH 126/484] perf(travis): Use setUpClass instead of setUp
---
.../test_stock_reconciliation.py | 29 ++++++++++---------
1 file changed, 15 insertions(+), 14 deletions(-)
diff --git a/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py
index f0c71cf39a..ededc4d8b4 100644
--- a/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py
+++ b/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py
@@ -17,10 +17,11 @@ from erpnext.stock.utils import get_stock_balance, get_incoming_rate, get_availa
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
class TestStockReconciliation(unittest.TestCase):
- def setUp(self):
+ @classmethod
+ def setUpClass(self):
create_batch_or_serial_no_items()
frappe.db.set_value("Stock Settings", None, "allow_negative_stock", 1)
- self.insert_existing_sle()
+ insert_existing_sle()
def test_reco_for_fifo(self):
self._test_reco_sle_gle("FIFO")
@@ -97,18 +98,6 @@ class TestStockReconciliation(unittest.TestCase):
self.assertEqual(["_Test Stock Reco Item", "_Test Warehouse Ledger 1 - _TC", 100],
[items[0]["item_code"], items[0]["warehouse"], items[0]["qty"]])
- def insert_existing_sle(self):
- from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
-
- make_stock_entry(posting_date="2012-12-15", posting_time="02:00", item_code="_Test Item",
- target="_Test Warehouse - _TC", qty=10, basic_rate=700)
-
- make_stock_entry(posting_date="2012-12-25", posting_time="03:00", item_code="_Test Item",
- source="_Test Warehouse - _TC", qty=15)
-
- make_stock_entry(posting_date="2013-01-05", posting_time="07:00", item_code="_Test Item",
- target="_Test Warehouse - _TC", qty=15, basic_rate=1200)
-
def test_stock_reco_for_serialized_item(self):
set_perpetual_inventory()
@@ -218,6 +207,18 @@ class TestStockReconciliation(unittest.TestCase):
for d in to_delete_records:
frappe.delete_doc("Stock Reconciliation", d)
+def insert_existing_sle():
+ from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
+
+ make_stock_entry(posting_date="2012-12-15", posting_time="02:00", item_code="_Test Item",
+ target="_Test Warehouse - _TC", qty=10, basic_rate=700)
+
+ make_stock_entry(posting_date="2012-12-25", posting_time="03:00", item_code="_Test Item",
+ source="_Test Warehouse - _TC", qty=15)
+
+ make_stock_entry(posting_date="2013-01-05", posting_time="07:00", item_code="_Test Item",
+ target="_Test Warehouse - _TC", qty=15, basic_rate=1200)
+
def create_batch_or_serial_no_items():
create_warehouse("_Test Warehouse for Stock Reco1",
{"is_group": 0, "parent_warehouse": "_Test Warehouse Group - _TC"})
From f2fb461e40d21ded1fe1ee14f293f4494a338f74 Mon Sep 17 00:00:00 2001
From: Aditya Hase
Date: Fri, 26 Jul 2019 03:51:45 +0530
Subject: [PATCH 127/484] perf(tests): Remove unnecessary tearDown code
---
.../doctype/stock_settings/test_stock_settings.py | 11 +----------
1 file changed, 1 insertion(+), 10 deletions(-)
diff --git a/erpnext/stock/doctype/stock_settings/test_stock_settings.py b/erpnext/stock/doctype/stock_settings/test_stock_settings.py
index 1e83ec2f49..42a78f723d 100644
--- a/erpnext/stock/doctype/stock_settings/test_stock_settings.py
+++ b/erpnext/stock/doctype/stock_settings/test_stock_settings.py
@@ -8,16 +8,7 @@ import unittest
class TestStockSettings(unittest.TestCase):
def setUp(self):
- settings = frappe.get_single('Stock Settings')
- settings.clean_description_html = 0
- settings.save()
-
- frappe.delete_doc('Item', 'Item for description test')
-
- def tearDown(self):
- settings = frappe.get_single('Stock Settings')
- settings.clean_description_html = 1
- settings.save()
+ frappe.db.set_value("Stock Settings", None, "clean_description_html", 0)
def test_settings(self):
item = frappe.get_doc(dict(
From 6998412990b4574e1b737a6e508491f632764a7a Mon Sep 17 00:00:00 2001
From: Faris Ansari
Date: Fri, 26 Jul 2019 08:15:45 +0530
Subject: [PATCH 128/484] fix(Account): Pass parent currency to child currency
In a scenario where Parent Company Account's Currency is different
from it's default currency, the Account Currency of Child would be set
from the default currency of Company which might be wrong
---
erpnext/accounts/doctype/account/account.py | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/erpnext/accounts/doctype/account/account.py b/erpnext/accounts/doctype/account/account.py
index 68efe37719..0e57b3f198 100644
--- a/erpnext/accounts/doctype/account/account.py
+++ b/erpnext/accounts/doctype/account/account.py
@@ -123,7 +123,9 @@ class Account(NestedSet):
doc.flags.ignore_root_company_validation = True
doc.update({
"company": company,
- "account_currency": None,
+ # parent account's currency should be passed down to child account's curreny
+ # if it is None, it picks it up from default company currency, which might be unintended
+ "account_currency": self.account_currency,
"parent_account": parent_acc_name_map[company]
})
doc.save()
From 4d53992b354eebe87b00c250c558eaa163ae2de5 Mon Sep 17 00:00:00 2001
From: deepeshgarg007
Date: Wed, 10 Jul 2019 14:49:25 +0530
Subject: [PATCH 129/484] fix: Changed columns to new dict form
---
.../stock/report/stock_ageing/stock_ageing.py | 79 +++++++++++++++++--
1 file changed, 74 insertions(+), 5 deletions(-)
diff --git a/erpnext/stock/report/stock_ageing/stock_ageing.py b/erpnext/stock/report/stock_ageing/stock_ageing.py
index 969284598c..f81e1c0b91 100644
--- a/erpnext/stock/report/stock_ageing/stock_ageing.py
+++ b/erpnext/stock/report/stock_ageing/stock_ageing.py
@@ -45,14 +45,83 @@ def get_average_age(fifo_queue, to_date):
return (age_qty / total_qty) if total_qty else 0.0
def get_columns(filters):
- columns = [_("Item Code") + ":Link/Item:100", _("Item Name") + "::100", _("Description") + "::200",
- _("Item Group") + ":Link/Item Group:100", _("Brand") + ":Link/Brand:100"]
+ columns = [
+ {
+ "label": _("Item Code"),
+ "fieldname": "item_code",
+ "fieldtype": "Link",
+ "options": "Item",
+ "width": 100
+ },
+ {
+ "label": _("Item Name"),
+ "fieldname": "item_name",
+ "fieldtype": "Data",
+ "width": 100
+ },
+ {
+ "label": _("Description"),
+ "fieldname": "description",
+ "fieldtype": "Data",
+ "width": 200
+ },
+ {
+ "label": _("Item Group"),
+ "fieldname": "item_group",
+ "fieldtype": "Link",
+ "options": "Item Group",
+ "width": 100
+ },
+ {
+ "label": _("Brand"),
+ "fieldname": "brand",
+ "fieldtype": "Link",
+ "options": "Brand",
+ "width": 100
+ }]
if filters.get("show_ageing_warehouse_wise"):
- columns.extend([_("Warehouse") + ":Link/Warehouse:100"])
+ columns +=[{
+ "label": _("Warehouse"),
+ "fieldname": "warehouse",
+ "fieldtype": "Link",
+ "options": "Warehouse",
+ "width": 100
+ }]
- columns.extend([_("Available Qty") + ":Float:100", _("Average Age") + ":Float:100",
- _("Earliest") + ":Int:80", _("Latest") + ":Int:80", _("UOM") + ":Link/UOM:100"])
+ columns.extend([
+ {
+ "label": _("Available Qty"),
+ "fieldname": "qty",
+ "fieldtype": "Float",
+ "width": 100
+ },
+ {
+ "label": _("Average Age"),
+ "fieldname": "average_age",
+ "fieldtype": "Float",
+ "width": 100
+ },
+ {
+ "label": _("Earliest"),
+ "fieldname": "earliest",
+ "fieldtype": "Int",
+ "width": 80
+ },
+ {
+ "label": _("Latest"),
+ "fieldname": "latest",
+ "fieldtype": "Int",
+ "width": 80
+ },
+ {
+ "label": _("UOM"),
+ "fieldname": "uom",
+ "fieldtype": "Link",
+ "options": "UOM",
+ "width": 100
+ }
+ ])
return columns
From f7733be322533f977f6171fd7b002164d3bf13ef Mon Sep 17 00:00:00 2001
From: deepeshgarg007
Date: Sat, 13 Jul 2019 21:58:32 +0530
Subject: [PATCH 130/484] fix: Enhancement in stock ageing report
---
.../stock/report/stock_ageing/stock_ageing.js | 4 +-
.../stock/report/stock_ageing/stock_ageing.py | 37 ++++++++++++++-----
2 files changed, 30 insertions(+), 11 deletions(-)
diff --git a/erpnext/stock/report/stock_ageing/stock_ageing.js b/erpnext/stock/report/stock_ageing/stock_ageing.js
index aad8df426a..ccde61a167 100644
--- a/erpnext/stock/report/stock_ageing/stock_ageing.js
+++ b/erpnext/stock/report/stock_ageing/stock_ageing.js
@@ -37,8 +37,8 @@ frappe.query_reports["Stock Ageing"] = {
"options": "Brand"
},
{
- "fieldname":"show_ageing_warehouse_wise",
- "label": __("Show Ageing Warehouse-wise"),
+ "fieldname":"show_warehouse_wise_stock",
+ "label": __("Show Warehouse-wise Stock"),
"fieldtype": "Check",
"default": 0
}
diff --git a/erpnext/stock/report/stock_ageing/stock_ageing.py b/erpnext/stock/report/stock_ageing/stock_ageing.py
index f81e1c0b91..54498934b3 100644
--- a/erpnext/stock/report/stock_ageing/stock_ageing.py
+++ b/erpnext/stock/report/stock_ageing/stock_ageing.py
@@ -14,7 +14,7 @@ def execute(filters=None):
to_date = filters["to_date"]
data = []
for item, item_dict in iteritems(item_details):
- fifo_queue = item_dict["fifo_queue"]
+ fifo_queue = sorted(item_dict["fifo_queue"], key=lambda x: x[1])
details = item_dict["details"]
if not fifo_queue: continue
@@ -25,7 +25,7 @@ def execute(filters=None):
row = [details.name, details.item_name,
details.description, details.item_group, details.brand]
- if filters.get("show_ageing_warehouse_wise"):
+ if filters.get("show_warehouse_wise_stock"):
row.append(details.warehouse)
row.extend([item_dict.get("total_qty"), average_age,
@@ -80,7 +80,7 @@ def get_columns(filters):
"width": 100
}]
- if filters.get("show_ageing_warehouse_wise"):
+ if filters.get("show_warehouse_wise_stock"):
columns +=[{
"label": _("Warehouse"),
"fieldname": "warehouse",
@@ -127,16 +127,34 @@ def get_columns(filters):
def get_fifo_queue(filters):
item_details = {}
- for d in get_stock_ledger_entries(filters):
- key = (d.name, d.warehouse) if filters.get('show_ageing_warehouse_wise') else d.name
+ transfered_item_details = {}
+
+ sle = get_stock_ledger_entries(filters)
+
+ for d in sle:
+ key = (d.name, d.warehouse) if filters.get('show_warehouse_wise_stock') else d.name
item_details.setdefault(key, {"details": d, "fifo_queue": []})
fifo_queue = item_details[key]["fifo_queue"]
+ transfered_item_details.setdefault((d.voucher_no, d.name), [])
+
if d.voucher_type == "Stock Reconciliation":
d.actual_qty = flt(d.qty_after_transaction) - flt(item_details[key].get("qty_after_transaction", 0))
if d.actual_qty > 0:
- fifo_queue.append([d.actual_qty, d.posting_date])
+ if filters.get('show_warehouse_wise_stock') and transfered_item_details.get((d.voucher_no, d.name)):
+ qty_to_add = d.actual_qty
+ while qty_to_add:
+ batch = transfered_item_details[(d.voucher_no, d.name)][0]
+ if 0 < batch[0] <= qty_to_add:
+ qty_to_add -= batch[0]
+ fifo_queue.append(batch)
+ transfered_item_details[((d.voucher_no, d.name))].pop(0)
+ else:
+ batch[0] -= qty_to_add
+ fifo_queue.append([qty_to_add, batch[1]])
+ else:
+ fifo_queue.append([d.actual_qty, d.posting_date])
else:
qty_to_pop = abs(d.actual_qty)
while qty_to_pop:
@@ -145,10 +163,11 @@ def get_fifo_queue(filters):
# if batch qty > 0
# not enough or exactly same qty in current batch, clear batch
qty_to_pop -= batch[0]
- fifo_queue.pop(0)
+ transfered_item_details[(d.voucher_no, d.name)].append(fifo_queue.pop(0))
else:
# all from current batch
batch[0] -= qty_to_pop
+ transfered_item_details[(d.voucher_no, d.name)].append([qty_to_pop, batch[1]])
qty_to_pop = 0
item_details[key]["qty_after_transaction"] = d.qty_after_transaction
@@ -163,7 +182,7 @@ def get_fifo_queue(filters):
def get_stock_ledger_entries(filters):
return frappe.db.sql("""select
item.name, item.item_name, item_group, brand, description, item.stock_uom,
- actual_qty, posting_date, voucher_type, qty_after_transaction, warehouse
+ actual_qty, posting_date, voucher_type, voucher_no, qty_after_transaction, warehouse
from `tabStock Ledger Entry` sle,
(select name, item_name, description, stock_uom, brand, item_group
from `tabItem` {item_conditions}) item
@@ -171,7 +190,7 @@ def get_stock_ledger_entries(filters):
company = %(company)s and
posting_date <= %(to_date)s
{sle_conditions}
- order by posting_date, posting_time, sle.creation"""\
+ order by posting_date, posting_time, sle.creation, actual_qty"""\
.format(item_conditions=get_item_conditions(filters),
sle_conditions=get_sle_conditions(filters)), filters, as_dict=True)
From e3a2ab184e3e168b15d89543987085fa649407ac Mon Sep 17 00:00:00 2001
From: deepeshgarg007
Date: Tue, 16 Jul 2019 16:08:50 +0530
Subject: [PATCH 131/484] fix: Consider serial no and batches in Stock ageing
report
---
.../stock/report/stock_ageing/stock_ageing.py | 69 +++++++++++++------
1 file changed, 49 insertions(+), 20 deletions(-)
diff --git a/erpnext/stock/report/stock_ageing/stock_ageing.py b/erpnext/stock/report/stock_ageing/stock_ageing.py
index 54498934b3..7529ae6aa7 100644
--- a/erpnext/stock/report/stock_ageing/stock_ageing.py
+++ b/erpnext/stock/report/stock_ageing/stock_ageing.py
@@ -16,8 +16,9 @@ def execute(filters=None):
for item, item_dict in iteritems(item_details):
fifo_queue = sorted(item_dict["fifo_queue"], key=lambda x: x[1])
details = item_dict["details"]
- if not fifo_queue: continue
+ if not fifo_queue or (not item_dict.get("total_qty")): continue
+ print(fifo_queue)
average_age = get_average_age(fifo_queue, to_date)
earliest_age = date_diff(to_date, fifo_queue[0][1])
latest_age = date_diff(to_date, fifo_queue[-1][1])
@@ -39,8 +40,13 @@ def get_average_age(fifo_queue, to_date):
batch_age = age_qty = total_qty = 0.0
for batch in fifo_queue:
batch_age = date_diff(to_date, batch[1])
- age_qty += batch_age * batch[0]
- total_qty += batch[0]
+
+ if type(batch[0]) in ['int', 'float']:
+ age_qty += batch_age * batch[0]
+ total_qty += batch[0]
+ else:
+ age_qty += batch_age * 1
+ total_qty += 1
return (age_qty / total_qty) if total_qty else 0.0
@@ -128,6 +134,7 @@ def get_columns(filters):
def get_fifo_queue(filters):
item_details = {}
transfered_item_details = {}
+ serial_no_batch_purchase_details = {}
sle = get_stock_ledger_entries(filters)
@@ -142,7 +149,7 @@ def get_fifo_queue(filters):
d.actual_qty = flt(d.qty_after_transaction) - flt(item_details[key].get("qty_after_transaction", 0))
if d.actual_qty > 0:
- if filters.get('show_warehouse_wise_stock') and transfered_item_details.get((d.voucher_no, d.name)):
+ if transfered_item_details.get((d.voucher_no, d.name)):
qty_to_add = d.actual_qty
while qty_to_add:
batch = transfered_item_details[(d.voucher_no, d.name)][0]
@@ -154,21 +161,43 @@ def get_fifo_queue(filters):
batch[0] -= qty_to_add
fifo_queue.append([qty_to_add, batch[1]])
else:
- fifo_queue.append([d.actual_qty, d.posting_date])
- else:
- qty_to_pop = abs(d.actual_qty)
- while qty_to_pop:
- batch = fifo_queue[0] if fifo_queue else [0, None]
- if 0 < batch[0] <= qty_to_pop:
- # if batch qty > 0
- # not enough or exactly same qty in current batch, clear batch
- qty_to_pop -= batch[0]
- transfered_item_details[(d.voucher_no, d.name)].append(fifo_queue.pop(0))
+ if d.serial_no or d.batch_no:
+ if d.serial_no:
+ for no in d.serial_no.split("\n"):
+ if serial_no_batch_purchase_details.get(no):
+ fifo_queue.append([no, serial_no_batch_purchase_details.get(no)])
+ else:
+ serial_no_batch_purchase_details.setdefault(no, d.posting_date)
+ fifo_queue.append([no, d.posting_date])
+ else:
+ if serial_no_batch_purchase_details.get(d.batch_no):
+ fifo_queue.append([d.batch_no, serial_no_batch_purchase_details.get(d.batch_no)])
+ else:
+ serial_no_batch_purchase_details.setdefault(d.batch_no, d.posting_date)
+ fifo_queue.append([d.batch_no, d.posting_date])
+
else:
- # all from current batch
- batch[0] -= qty_to_pop
- transfered_item_details[(d.voucher_no, d.name)].append([qty_to_pop, batch[1]])
- qty_to_pop = 0
+ fifo_queue.append([d.actual_qty, d.posting_date])
+ else:
+ if d.serial_no or d.batch_no:
+ serial_no_list = d.serial_no.split("\n")
+ for serial_no in fifo_queue:
+ if serial_no[0] in serial_no_list:
+ fifo_queue.remove(serial_no)
+ else:
+ qty_to_pop = abs(d.actual_qty)
+ while qty_to_pop:
+ batch = fifo_queue[0] if fifo_queue else [0, None]
+ if 0 < batch[0] <= qty_to_pop:
+ # if batch qty > 0
+ # not enough or exactly same qty in current batch, clear batch
+ qty_to_pop -= batch[0]
+ transfered_item_details[(d.voucher_no, d.name)].append(fifo_queue.pop(0))
+ else:
+ # all from current batch
+ batch[0] -= qty_to_pop
+ transfered_item_details[(d.voucher_no, d.name)].append([qty_to_pop, batch[1]])
+ qty_to_pop = 0
item_details[key]["qty_after_transaction"] = d.qty_after_transaction
@@ -182,7 +211,7 @@ def get_fifo_queue(filters):
def get_stock_ledger_entries(filters):
return frappe.db.sql("""select
item.name, item.item_name, item_group, brand, description, item.stock_uom,
- actual_qty, posting_date, voucher_type, voucher_no, qty_after_transaction, warehouse
+ actual_qty, posting_date, voucher_type, voucher_no, serial_no, batch_no, qty_after_transaction, warehouse
from `tabStock Ledger Entry` sle,
(select name, item_name, description, stock_uom, brand, item_group
from `tabItem` {item_conditions}) item
@@ -190,7 +219,7 @@ def get_stock_ledger_entries(filters):
company = %(company)s and
posting_date <= %(to_date)s
{sle_conditions}
- order by posting_date, posting_time, sle.creation, actual_qty"""\
+ order by posting_date, posting_time, sle.creation, actual_qty""" #nosec
.format(item_conditions=get_item_conditions(filters),
sle_conditions=get_sle_conditions(filters)), filters, as_dict=True)
From 1495c9599a22ac51eb7ffc81c4d67b4e9a23d388 Mon Sep 17 00:00:00 2001
From: deepeshgarg007
Date: Mon, 22 Jul 2019 15:30:18 +0530
Subject: [PATCH 132/484] fix: Remove batch
---
.../stock/report/stock_ageing/stock_ageing.py | 34 ++++++-------------
1 file changed, 11 insertions(+), 23 deletions(-)
diff --git a/erpnext/stock/report/stock_ageing/stock_ageing.py b/erpnext/stock/report/stock_ageing/stock_ageing.py
index 7529ae6aa7..790cd8fc26 100644
--- a/erpnext/stock/report/stock_ageing/stock_ageing.py
+++ b/erpnext/stock/report/stock_ageing/stock_ageing.py
@@ -6,6 +6,7 @@ import frappe
from frappe import _
from frappe.utils import date_diff, flt
from six import iteritems
+from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
def execute(filters=None):
@@ -18,7 +19,6 @@ def execute(filters=None):
details = item_dict["details"]
if not fifo_queue or (not item_dict.get("total_qty")): continue
- print(fifo_queue)
average_age = get_average_age(fifo_queue, to_date)
earliest_age = date_diff(to_date, fifo_queue[0][1])
latest_age = date_diff(to_date, fifo_queue[-1][1])
@@ -151,39 +151,27 @@ def get_fifo_queue(filters):
if d.actual_qty > 0:
if transfered_item_details.get((d.voucher_no, d.name)):
qty_to_add = d.actual_qty
- while qty_to_add:
- batch = transfered_item_details[(d.voucher_no, d.name)][0]
- if 0 < batch[0] <= qty_to_add:
- qty_to_add -= batch[0]
- fifo_queue.append(batch)
- transfered_item_details[((d.voucher_no, d.name))].pop(0)
- else:
- batch[0] -= qty_to_add
- fifo_queue.append([qty_to_add, batch[1]])
+ batch = transfered_item_details[(d.voucher_no, d.name)][0]
+ fifo_queue.append(batch)
+ transfered_item_details[((d.voucher_no, d.name))].pop(0)
else:
- if d.serial_no or d.batch_no:
+ if d.serial_no:
if d.serial_no:
- for no in d.serial_no.split("\n"):
+ for no in get_serial_nos(d.serial_no):
if serial_no_batch_purchase_details.get(no):
fifo_queue.append([no, serial_no_batch_purchase_details.get(no)])
else:
serial_no_batch_purchase_details.setdefault(no, d.posting_date)
fifo_queue.append([no, d.posting_date])
- else:
- if serial_no_batch_purchase_details.get(d.batch_no):
- fifo_queue.append([d.batch_no, serial_no_batch_purchase_details.get(d.batch_no)])
- else:
- serial_no_batch_purchase_details.setdefault(d.batch_no, d.posting_date)
- fifo_queue.append([d.batch_no, d.posting_date])
-
else:
fifo_queue.append([d.actual_qty, d.posting_date])
else:
if d.serial_no or d.batch_no:
- serial_no_list = d.serial_no.split("\n")
- for serial_no in fifo_queue:
- if serial_no[0] in serial_no_list:
- fifo_queue.remove(serial_no)
+ if d.serial_no:
+ serial_no_list = d.serial_no.split("\n")
+ for serial_no in fifo_queue:
+ if serial_no[0] in serial_no_list:
+ fifo_queue.remove(serial_no)
else:
qty_to_pop = abs(d.actual_qty)
while qty_to_pop:
From 7fdab021b64790972065df540469f1cb22ec2a24 Mon Sep 17 00:00:00 2001
From: deepeshgarg007
Date: Mon, 22 Jul 2019 15:56:41 +0530
Subject: [PATCH 133/484] fix: Use get_serial_no and remove batch
---
erpnext/stock/report/stock_ageing/stock_ageing.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/erpnext/stock/report/stock_ageing/stock_ageing.py b/erpnext/stock/report/stock_ageing/stock_ageing.py
index 790cd8fc26..91ba463683 100644
--- a/erpnext/stock/report/stock_ageing/stock_ageing.py
+++ b/erpnext/stock/report/stock_ageing/stock_ageing.py
@@ -166,9 +166,9 @@ def get_fifo_queue(filters):
else:
fifo_queue.append([d.actual_qty, d.posting_date])
else:
- if d.serial_no or d.batch_no:
+ if d.serial_no:
if d.serial_no:
- serial_no_list = d.serial_no.split("\n")
+ serial_no_list = get_serial_nos(d.serial_no)
for serial_no in fifo_queue:
if serial_no[0] in serial_no_list:
fifo_queue.remove(serial_no)
From 06f99cae3660824b5dba3605fb4ce1060ecccc3b Mon Sep 17 00:00:00 2001
From: deepeshgarg007
Date: Tue, 23 Jul 2019 08:30:09 +0530
Subject: [PATCH 134/484] fix: Fixes in stock ageing report
---
.../stock/report/stock_ageing/stock_ageing.py | 28 +++++++++----------
1 file changed, 13 insertions(+), 15 deletions(-)
diff --git a/erpnext/stock/report/stock_ageing/stock_ageing.py b/erpnext/stock/report/stock_ageing/stock_ageing.py
index 91ba463683..83a1d7b62b 100644
--- a/erpnext/stock/report/stock_ageing/stock_ageing.py
+++ b/erpnext/stock/report/stock_ageing/stock_ageing.py
@@ -148,30 +148,28 @@ def get_fifo_queue(filters):
if d.voucher_type == "Stock Reconciliation":
d.actual_qty = flt(d.qty_after_transaction) - flt(item_details[key].get("qty_after_transaction", 0))
+ serial_no_list = get_serial_nos(d.serial_no) if d.serial_no else []
+
if d.actual_qty > 0:
if transfered_item_details.get((d.voucher_no, d.name)):
- qty_to_add = d.actual_qty
batch = transfered_item_details[(d.voucher_no, d.name)][0]
fifo_queue.append(batch)
transfered_item_details[((d.voucher_no, d.name))].pop(0)
else:
- if d.serial_no:
- if d.serial_no:
- for no in get_serial_nos(d.serial_no):
- if serial_no_batch_purchase_details.get(no):
- fifo_queue.append([no, serial_no_batch_purchase_details.get(no)])
- else:
- serial_no_batch_purchase_details.setdefault(no, d.posting_date)
- fifo_queue.append([no, d.posting_date])
+ if serial_no_list:
+ for serial_no in serial_no_list:
+ if serial_no_batch_purchase_details.get(serial_no):
+ fifo_queue.append([serial_no, serial_no_batch_purchase_details.get(serial_no)])
+ else:
+ serial_no_batch_purchase_details.setdefault(serial_no, d.posting_date)
+ fifo_queue.append([serial_no, d.posting_date])
else:
fifo_queue.append([d.actual_qty, d.posting_date])
else:
- if d.serial_no:
- if d.serial_no:
- serial_no_list = get_serial_nos(d.serial_no)
- for serial_no in fifo_queue:
- if serial_no[0] in serial_no_list:
- fifo_queue.remove(serial_no)
+ if serial_no_list:
+ for serial_no in fifo_queue:
+ if serial_no[0] in serial_no_list:
+ fifo_queue.remove(serial_no)
else:
qty_to_pop = abs(d.actual_qty)
while qty_to_pop:
From ecd4d3883e77c5a620078b285c6a2726cdee53a2 Mon Sep 17 00:00:00 2001
From: Sahil Khan
Date: Fri, 26 Jul 2019 13:29:14 +0550
Subject: [PATCH 135/484] bumped to version 12.0.1
---
erpnext/__init__.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/__init__.py b/erpnext/__init__.py
index 020f843c1a..a9348c11f4 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__ = '12.0.0'
+__version__ = '12.0.1'
def get_default_company(user=None):
'''Get default company for user'''
From 3844a98c42d464532ceaaa624fba237bc3d5dbdb Mon Sep 17 00:00:00 2001
From: Rohit Waghchaure
Date: Sun, 26 May 2019 18:18:21 +0530
Subject: [PATCH 136/484] fix: Pro rata calculation is not working for WDV
depreciation method
---
erpnext/assets/doctype/asset/asset.js | 15 ++-
erpnext/assets/doctype/asset/asset.py | 109 +++++++-----------
.../asset_settings/asset_settings.json | 71 +-----------
3 files changed, 56 insertions(+), 139 deletions(-)
diff --git a/erpnext/assets/doctype/asset/asset.js b/erpnext/assets/doctype/asset/asset.js
index 2d78d2693d..c5cad73801 100644
--- a/erpnext/assets/doctype/asset/asset.js
+++ b/erpnext/assets/doctype/asset/asset.js
@@ -303,14 +303,17 @@ frappe.ui.form.on('Asset', {
},
set_depreciation_rate: function(frm, row) {
- if (row.total_number_of_depreciations && row.frequency_of_depreciation) {
+ if (row.total_number_of_depreciations && row.frequency_of_depreciation
+ && row.expected_value_after_useful_life) {
frappe.call({
method: "get_depreciation_rate",
doc: frm.doc,
args: row,
callback: function(r) {
if (r.message) {
- frappe.model.set_value(row.doctype, row.name, "rate_of_depreciation", r.message);
+ frappe.flags.dont_change_rate = true;
+ frappe.model.set_value(row.doctype, row.name,
+ "rate_of_depreciation", flt(r.message, precision("rate_of_depreciation", row)));
}
}
});
@@ -338,6 +341,14 @@ frappe.ui.form.on('Asset Finance Book', {
total_number_of_depreciations: function(frm, cdt, cdn) {
const row = locals[cdt][cdn];
frm.events.set_depreciation_rate(frm, row);
+ },
+
+ rate_of_depreciation: function(frm, cdt, cdn) {
+ if(!frappe.flags.dont_change_rate) {
+ frappe.model.set_value(cdt, cdn, "expected_value_after_useful_life", 0);
+ }
+
+ frappe.flags.dont_change_rate = false;
}
});
diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py
index c398a7342a..6475d0c4aa 100644
--- a/erpnext/assets/doctype/asset/asset.py
+++ b/erpnext/assets/doctype/asset/asset.py
@@ -101,7 +101,8 @@ class Asset(AccountsController):
def set_depreciation_rate(self):
for d in self.get("finance_books"):
- d.rate_of_depreciation = self.get_depreciation_rate(d, on_validate=True)
+ d.rate_of_depreciation = flt(self.get_depreciation_rate(d, on_validate=True),
+ d.precision("rate_of_depreciation"))
def make_depreciation_schedule(self):
depreciation_method = [d.depreciation_method for d in self.finance_books]
@@ -110,8 +111,6 @@ class Asset(AccountsController):
self.schedules = []
if not self.get("schedules") and self.available_for_use_date:
- total_depreciations = sum([d.total_number_of_depreciations for d in self.get('finance_books')])
-
for d in self.get('finance_books'):
self.validate_asset_finance_books(d)
@@ -124,74 +123,55 @@ class Asset(AccountsController):
end_date = add_months(d.depreciation_start_date,
no_of_depreciations * cint(d.frequency_of_depreciation))
- total_days = date_diff(end_date, self.available_for_use_date)
- rate_per_day = (value_after_depreciation - d.get("expected_value_after_useful_life")) / total_days
+ if d.depreciation_method in ("Straight Line", "Manual"):
+ total_days = date_diff(end_date, self.available_for_use_date)
+ rate_per_day = (value_after_depreciation - d.get("expected_value_after_useful_life")) / total_days
number_of_pending_depreciations = cint(d.total_number_of_depreciations) - \
cint(self.number_of_depreciations_booked)
from_date = self.available_for_use_date
if number_of_pending_depreciations:
- next_depr_date = getdate(add_months(self.available_for_use_date,
- number_of_pending_depreciations * 12))
- if (cint(frappe.db.get_value("Asset Settings", None, "schedule_based_on_fiscal_year")) == 1
- and getdate(d.depreciation_start_date) < next_depr_date):
+ period_start_date = add_months(d.depreciation_start_date,
+ cint(d.frequency_of_depreciation) * -1)
- number_of_pending_depreciations += 1
- for n in range(number_of_pending_depreciations):
- if n == list(range(number_of_pending_depreciations))[-1]:
- schedule_date = add_months(self.available_for_use_date, n * 12)
- previous_scheduled_date = add_months(d.depreciation_start_date, (n-1) * 12)
- depreciation_amount = \
- self.get_depreciation_amount_prorata_temporis(value_after_depreciation,
- d, previous_scheduled_date, schedule_date)
+ for n in range(number_of_pending_depreciations):
+ schedule_date = add_months(d.depreciation_start_date,
+ n * cint(d.frequency_of_depreciation))
- elif n == list(range(number_of_pending_depreciations))[0]:
- schedule_date = d.depreciation_start_date
- depreciation_amount = \
- self.get_depreciation_amount_prorata_temporis(value_after_depreciation,
- d, self.available_for_use_date, schedule_date)
+ days = date_diff(schedule_date, from_date)
- else:
- schedule_date = add_months(d.depreciation_start_date, n * 12)
- depreciation_amount = \
- self.get_depreciation_amount_prorata_temporis(value_after_depreciation, d)
+ if n == 0: days += 1
- if value_after_depreciation != 0:
- value_after_depreciation -= flt(depreciation_amount)
+ if d.depreciation_method in ("Straight Line", "Manual"):
+ depreciation_amount = days * rate_per_day
+ else:
+ total_days = date_diff(schedule_date, period_start_date)
+ period_start_date = schedule_date
+ depreciation_amount = self.get_depreciation_amount(value_after_depreciation,
+ d.total_number_of_depreciations, d)
- self.append("schedules", {
- "schedule_date": schedule_date,
- "depreciation_amount": depreciation_amount,
- "depreciation_method": d.depreciation_method,
- "finance_book": d.finance_book,
- "finance_book_id": d.idx
- })
- else:
- for n in range(number_of_pending_depreciations):
- schedule_date = add_months(d.depreciation_start_date,
- n * cint(d.frequency_of_depreciation))
+ depreciation_amount = flt((depreciation_amount * days) / total_days,
+ self.precision("gross_purchase_amount"))
- if d.depreciation_method in ("Straight Line", "Manual"):
- days = date_diff(schedule_date, from_date)
- if n == 0: days += 1
+ from_date = schedule_date
- depreciation_amount = days * rate_per_day
- from_date = schedule_date
- else:
- depreciation_amount = self.get_depreciation_amount(value_after_depreciation,
- d.total_number_of_depreciations, d)
+ if depreciation_amount:
+ value_after_depreciation -= flt(depreciation_amount,
+ self.precision("gross_purchase_amount"))
- if depreciation_amount:
- value_after_depreciation -= flt(depreciation_amount)
+ if (n == cint(number_of_pending_depreciations) - 1 and
+ d.expected_value_after_useful_life and
+ value_after_depreciation > d.expected_value_after_useful_life):
+ depreciation_amount += (value_after_depreciation - d.expected_value_after_useful_life)
- self.append("schedules", {
- "schedule_date": schedule_date,
- "depreciation_amount": depreciation_amount,
- "depreciation_method": d.depreciation_method,
- "finance_book": d.finance_book,
- "finance_book_id": d.idx
- })
+ self.append("schedules", {
+ "schedule_date": schedule_date,
+ "depreciation_amount": depreciation_amount,
+ "depreciation_method": d.depreciation_method,
+ "finance_book": d.finance_book,
+ "finance_book_id": d.idx
+ })
def validate_asset_finance_books(self, row):
if flt(row.expected_value_after_useful_life) >= flt(self.gross_purchase_amount):
@@ -261,16 +241,8 @@ class Asset(AccountsController):
return flt(self.get('finance_books')[cint(idx)-1].value_after_depreciation)
def get_depreciation_amount(self, depreciable_value, total_number_of_depreciations, row):
- if row.depreciation_method in ["Straight Line", "Manual"]:
- amt = (flt(self.gross_purchase_amount) - flt(row.expected_value_after_useful_life) -
- flt(self.opening_accumulated_depreciation))
-
- depreciation_amount = amt * row.rate_of_depreciation
- else:
- depreciation_amount = flt(depreciable_value) * (flt(row.rate_of_depreciation) / 100)
- value_after_depreciation = flt(depreciable_value) - depreciation_amount
- if value_after_depreciation < flt(row.expected_value_after_useful_life):
- depreciation_amount = flt(depreciable_value) - flt(row.expected_value_after_useful_life)
+ precision = self.precision("gross_purchase_amount")
+ depreciation_amount = flt(depreciable_value * (flt(row.rate_of_depreciation) / 100), precision)
return depreciation_amount
@@ -301,9 +273,12 @@ class Asset(AccountsController):
flt(accumulated_depreciation_after_full_schedule),
self.precision('gross_purchase_amount'))
- if row.expected_value_after_useful_life < asset_value_after_full_schedule:
+ if (row.expected_value_after_useful_life and
+ row.expected_value_after_useful_life < asset_value_after_full_schedule):
frappe.throw(_("Depreciation Row {0}: Expected value after useful life must be greater than or equal to {1}")
.format(row.idx, asset_value_after_full_schedule))
+ elif not row.expected_value_after_useful_life:
+ row.expected_value_after_useful_life = asset_value_after_full_schedule
def validate_cancellation(self):
if self.status not in ("Submitted", "Partially Depreciated", "Fully Depreciated"):
diff --git a/erpnext/assets/doctype/asset_settings/asset_settings.json b/erpnext/assets/doctype/asset_settings/asset_settings.json
index a3fee96f4e..edc5ce169c 100644
--- a/erpnext/assets/doctype/asset_settings/asset_settings.json
+++ b/erpnext/assets/doctype/asset_settings/asset_settings.json
@@ -46,75 +46,6 @@
"translatable": 0,
"unique": 0
},
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "schedule_based_on_fiscal_year",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Calculate Prorated Depreciation Schedule Based on Fiscal Year",
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "360",
- "depends_on": "eval:doc.schedule_based_on_fiscal_year",
- "description": "This value is used for pro-rata temporis calculation",
- "fetch_if_empty": 0,
- "fieldname": "number_of_days_in_fiscal_year",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Number of Days in Fiscal Year",
- "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,
- "translatable": 0,
- "unique": 0
- },
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
@@ -159,7 +90,7 @@
"issingle": 1,
"istable": 0,
"max_attachments": 0,
- "modified": "2019-03-08 10:44:41.924547",
+ "modified": "2019-05-26 18:31:19.930563",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Settings",
From 53f5e2e0664bf60e06a8c31601329106c6be3a05 Mon Sep 17 00:00:00 2001
From: Rohit Waghchaure
Date: Tue, 28 May 2019 10:33:56 +0530
Subject: [PATCH 137/484] fixed test cases and the logic for pro rata
calculation
---
erpnext/assets/doctype/asset/asset.py | 146 +++++++++++----------
erpnext/assets/doctype/asset/test_asset.py | 137 +++++++++++--------
2 files changed, 160 insertions(+), 123 deletions(-)
diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py
index 6475d0c4aa..45d2ec2c51 100644
--- a/erpnext/assets/doctype/asset/asset.py
+++ b/erpnext/assets/doctype/asset/asset.py
@@ -6,7 +6,7 @@ from __future__ import unicode_literals
import frappe, erpnext, math, json
from frappe import _
from six import string_types
-from frappe.utils import flt, add_months, cint, nowdate, getdate, today, date_diff
+from frappe.utils import flt, add_months, cint, nowdate, getdate, today, date_diff, add_days
from frappe.model.document import Document
from erpnext.assets.doctype.asset_category.asset_category import get_asset_category_account
from erpnext.assets.doctype.asset.depreciation \
@@ -105,73 +105,84 @@ class Asset(AccountsController):
d.precision("rate_of_depreciation"))
def make_depreciation_schedule(self):
- depreciation_method = [d.depreciation_method for d in self.finance_books]
-
- if 'Manual' not in depreciation_method:
+ if 'Manual' not in [d.depreciation_method for d in self.finance_books]:
self.schedules = []
- if not self.get("schedules") and self.available_for_use_date:
- for d in self.get('finance_books'):
- self.validate_asset_finance_books(d)
+ if self.get("schedules") or not self.available_for_use_date:
+ return
- value_after_depreciation = (flt(self.gross_purchase_amount) -
- flt(self.opening_accumulated_depreciation))
+ for d in self.get('finance_books'):
+ self.validate_asset_finance_books(d)
- d.value_after_depreciation = value_after_depreciation
+ value_after_depreciation = (flt(self.gross_purchase_amount) -
+ flt(self.opening_accumulated_depreciation))
- no_of_depreciations = cint(d.total_number_of_depreciations - 1) - cint(self.number_of_depreciations_booked)
- end_date = add_months(d.depreciation_start_date,
- no_of_depreciations * cint(d.frequency_of_depreciation))
+ d.value_after_depreciation = value_after_depreciation
- if d.depreciation_method in ("Straight Line", "Manual"):
- total_days = date_diff(end_date, self.available_for_use_date)
- rate_per_day = (value_after_depreciation - d.get("expected_value_after_useful_life")) / total_days
+ number_of_pending_depreciations = cint(d.total_number_of_depreciations) - \
+ cint(self.number_of_depreciations_booked)
- number_of_pending_depreciations = cint(d.total_number_of_depreciations) - \
- cint(self.number_of_depreciations_booked)
+ has_pro_rata = self.check_is_pro_rata(d)
- from_date = self.available_for_use_date
- if number_of_pending_depreciations:
- period_start_date = add_months(d.depreciation_start_date,
- cint(d.frequency_of_depreciation) * -1)
+ if has_pro_rata:
+ number_of_pending_depreciations += 1
- for n in range(number_of_pending_depreciations):
- schedule_date = add_months(d.depreciation_start_date,
- n * cint(d.frequency_of_depreciation))
+ skip_row = False
+ for n in range(number_of_pending_depreciations):
+ # If depreciation is already completed (for double declining balance)
+ if skip_row: continue
- days = date_diff(schedule_date, from_date)
+ depreciation_amount = self.get_depreciation_amount(value_after_depreciation,
+ d.total_number_of_depreciations, d)
- if n == 0: days += 1
+ if not has_pro_rata or n < cint(number_of_pending_depreciations) - 1:
+ schedule_date = add_months(d.depreciation_start_date,
+ n * cint(d.frequency_of_depreciation))
- if d.depreciation_method in ("Straight Line", "Manual"):
- depreciation_amount = days * rate_per_day
- else:
- total_days = date_diff(schedule_date, period_start_date)
- period_start_date = schedule_date
- depreciation_amount = self.get_depreciation_amount(value_after_depreciation,
- d.total_number_of_depreciations, d)
+ # For first row
+ if has_pro_rata and n==0:
+ depreciation_amount, days = get_pro_rata_amt(d, depreciation_amount,
+ self.available_for_use_date, d.depreciation_start_date)
+ # For last row
+ elif has_pro_rata and n == cint(number_of_pending_depreciations) - 1:
+ to_date = add_months(self.available_for_use_date,
+ n * cint(d.frequency_of_depreciation))
- depreciation_amount = flt((depreciation_amount * days) / total_days,
- self.precision("gross_purchase_amount"))
+ depreciation_amount, days = get_pro_rata_amt(d,
+ depreciation_amount, schedule_date, to_date)
- from_date = schedule_date
+ schedule_date = add_days(schedule_date, days)
- if depreciation_amount:
- value_after_depreciation -= flt(depreciation_amount,
- self.precision("gross_purchase_amount"))
+ if not depreciation_amount: continue
+ value_after_depreciation -= flt(depreciation_amount,
+ self.precision("gross_purchase_amount"))
- if (n == cint(number_of_pending_depreciations) - 1 and
- d.expected_value_after_useful_life and
- value_after_depreciation > d.expected_value_after_useful_life):
- depreciation_amount += (value_after_depreciation - d.expected_value_after_useful_life)
+ # Adjust depreciation amount in the last period based on the expected value after useful life
+ if d.expected_value_after_useful_life and ((n == cint(number_of_pending_depreciations) - 1
+ and value_after_depreciation != d.expected_value_after_useful_life)
+ or value_after_depreciation < d.expected_value_after_useful_life):
+ depreciation_amount += (value_after_depreciation - d.expected_value_after_useful_life)
+ skip_row = True
- self.append("schedules", {
- "schedule_date": schedule_date,
- "depreciation_amount": depreciation_amount,
- "depreciation_method": d.depreciation_method,
- "finance_book": d.finance_book,
- "finance_book_id": d.idx
- })
+ if depreciation_amount > 0:
+ self.append("schedules", {
+ "schedule_date": schedule_date,
+ "depreciation_amount": depreciation_amount,
+ "depreciation_method": d.depreciation_method,
+ "finance_book": d.finance_book,
+ "finance_book_id": d.idx
+ })
+
+ def check_is_pro_rata(self, row):
+ has_pro_rata = False
+
+ days = date_diff(row.depreciation_start_date, self.available_for_use_date) + 1
+ total_days = get_total_days(row.depreciation_start_date, row.frequency_of_depreciation)
+
+ if days < total_days:
+ has_pro_rata = True
+
+ return has_pro_rata
def validate_asset_finance_books(self, row):
if flt(row.expected_value_after_useful_life) >= flt(self.gross_purchase_amount):
@@ -242,22 +253,13 @@ class Asset(AccountsController):
def get_depreciation_amount(self, depreciable_value, total_number_of_depreciations, row):
precision = self.precision("gross_purchase_amount")
- depreciation_amount = flt(depreciable_value * (flt(row.rate_of_depreciation) / 100), precision)
-
- return depreciation_amount
-
- def get_depreciation_amount_prorata_temporis(self, depreciable_value, row, start_date=None, end_date=None):
- if start_date and end_date:
- prorata_temporis = min(abs(flt(date_diff(str(end_date), str(start_date)))) / flt(frappe.db.get_value("Asset Settings", None, "number_of_days_in_fiscal_year")), 1)
- else:
- prorata_temporis = 1
if row.depreciation_method in ("Straight Line", "Manual"):
depreciation_amount = (flt(row.value_after_depreciation) -
flt(row.expected_value_after_useful_life)) / (cint(row.total_number_of_depreciations) -
- cint(self.number_of_depreciations_booked)) * prorata_temporis
+ cint(self.number_of_depreciations_booked))
else:
- depreciation_amount = self.get_depreciation_amount(depreciable_value, row.total_number_of_depreciations, row)
+ depreciation_amount = flt(depreciable_value * (flt(row.rate_of_depreciation) / 100), precision)
return depreciation_amount
@@ -387,15 +389,7 @@ class Asset(AccountsController):
if isinstance(args, string_types):
args = json.loads(args)
- number_of_depreciations_booked = 0
- if self.is_existing_asset:
- number_of_depreciations_booked = self.number_of_depreciations_booked
-
float_precision = cint(frappe.db.get_default("float_precision")) or 2
- tot_no_of_depreciation = flt(args.get("total_number_of_depreciations")) - flt(number_of_depreciations_booked)
-
- if args.get("depreciation_method") in ["Straight Line", "Manual"]:
- return 1.0 / tot_no_of_depreciation
if args.get("depreciation_method") == 'Double Declining Balance':
return 200.0 / args.get("total_number_of_depreciations")
@@ -575,3 +569,15 @@ def make_journal_entry(asset_name):
def is_cwip_accounting_disabled():
return cint(frappe.db.get_single_value("Asset Settings", "disable_cwip_accounting"))
+
+def get_pro_rata_amt(row, depreciation_amount, from_date, to_date):
+ days = date_diff(to_date, from_date)
+ total_days = get_total_days(to_date, row.frequency_of_depreciation)
+
+ return (depreciation_amount * flt(days)) / flt(total_days), days
+
+def get_total_days(date, frequency):
+ period_start_date = add_months(date,
+ cint(frequency) * -1)
+
+ return date_diff(date, period_start_date)
\ No newline at end of file
diff --git a/erpnext/assets/doctype/asset/test_asset.py b/erpnext/assets/doctype/asset/test_asset.py
index fceccfbd1c..481ee7d9f4 100644
--- a/erpnext/assets/doctype/asset/test_asset.py
+++ b/erpnext/assets/doctype/asset/test_asset.py
@@ -88,23 +88,23 @@ class TestAsset(unittest.TestCase):
asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, 'name')
asset = frappe.get_doc('Asset', asset_name)
asset.calculate_depreciation = 1
- asset.available_for_use_date = '2020-06-06'
- asset.purchase_date = '2020-06-06'
+ asset.available_for_use_date = '2030-01-01'
+ asset.purchase_date = '2030-01-01'
asset.append("finance_books", {
"expected_value_after_useful_life": 10000,
- "next_depreciation_date": "2020-12-31",
"depreciation_method": "Straight Line",
"total_number_of_depreciations": 3,
- "frequency_of_depreciation": 10,
- "depreciation_start_date": "2020-06-06"
+ "frequency_of_depreciation": 12,
+ "depreciation_start_date": "2030-12-31"
})
asset.save()
+
self.assertEqual(asset.status, "Draft")
expected_schedules = [
- ["2020-06-06", 147.54, 147.54],
- ["2021-04-06", 44852.46, 45000.0],
- ["2022-02-06", 45000.0, 90000.00]
+ ["2030-12-31", 30000.00, 30000.00],
+ ["2031-12-31", 30000.00, 60000.00],
+ ["2032-12-31", 30000.00, 90000.00]
]
schedules = [[cstr(d.schedule_date), d.depreciation_amount, d.accumulated_depreciation_amount]
@@ -118,20 +118,21 @@ class TestAsset(unittest.TestCase):
asset.calculate_depreciation = 1
asset.number_of_depreciations_booked = 1
asset.opening_accumulated_depreciation = 40000
+ asset.available_for_use_date = "2030-06-06"
asset.append("finance_books", {
"expected_value_after_useful_life": 10000,
- "next_depreciation_date": "2020-12-31",
"depreciation_method": "Straight Line",
"total_number_of_depreciations": 3,
- "frequency_of_depreciation": 10,
- "depreciation_start_date": "2020-06-06"
+ "frequency_of_depreciation": 12,
+ "depreciation_start_date": "2030-12-31"
})
asset.insert()
self.assertEqual(asset.status, "Draft")
asset.save()
expected_schedules = [
- ["2020-06-06", 164.47, 40164.47],
- ["2021-04-06", 49835.53, 90000.00]
+ ["2030-12-31", 14246.58, 54246.58],
+ ["2031-12-31", 25000.00, 79246.58],
+ ["2032-06-06", 10753.42, 90000.00]
]
schedules = [[cstr(d.schedule_date), flt(d.depreciation_amount, 2), d.accumulated_depreciation_amount]
for d in asset.get("schedules")]
@@ -145,24 +146,23 @@ class TestAsset(unittest.TestCase):
asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, 'name')
asset = frappe.get_doc('Asset', asset_name)
asset.calculate_depreciation = 1
- asset.available_for_use_date = '2020-06-06'
- asset.purchase_date = '2020-06-06'
+ asset.available_for_use_date = '2030-01-01'
+ asset.purchase_date = '2030-01-01'
asset.append("finance_books", {
"expected_value_after_useful_life": 10000,
- "next_depreciation_date": "2020-12-31",
"depreciation_method": "Double Declining Balance",
"total_number_of_depreciations": 3,
- "frequency_of_depreciation": 10,
- "depreciation_start_date": "2020-06-06"
+ "frequency_of_depreciation": 12,
+ "depreciation_start_date": '2030-12-31'
})
asset.insert()
self.assertEqual(asset.status, "Draft")
asset.save()
expected_schedules = [
- ["2020-06-06", 66666.67, 66666.67],
- ["2021-04-06", 22222.22, 88888.89],
- ["2022-02-06", 1111.11, 90000.0]
+ ['2030-12-31', 66667.00, 66667.00],
+ ['2031-12-31', 22222.11, 88889.11],
+ ['2032-12-31', 1110.89, 90000.0]
]
schedules = [[cstr(d.schedule_date), d.depreciation_amount, d.accumulated_depreciation_amount]
@@ -177,23 +177,21 @@ class TestAsset(unittest.TestCase):
asset.is_existing_asset = 1
asset.number_of_depreciations_booked = 1
asset.opening_accumulated_depreciation = 50000
+ asset.available_for_use_date = '2030-01-01'
+ asset.purchase_date = '2029-11-30'
asset.append("finance_books", {
"expected_value_after_useful_life": 10000,
- "next_depreciation_date": "2020-12-31",
"depreciation_method": "Double Declining Balance",
"total_number_of_depreciations": 3,
- "frequency_of_depreciation": 10,
- "depreciation_start_date": "2020-06-06"
+ "frequency_of_depreciation": 12,
+ "depreciation_start_date": "2030-12-31"
})
asset.insert()
self.assertEqual(asset.status, "Draft")
- asset.save()
-
- asset.save()
expected_schedules = [
- ["2020-06-06", 33333.33, 83333.33],
- ["2021-04-06", 6666.67, 90000.0]
+ ["2030-12-31", 33333.50, 83333.50],
+ ["2031-12-31", 6666.50, 90000.0]
]
schedules = [[cstr(d.schedule_date), d.depreciation_amount, d.accumulated_depreciation_amount]
@@ -209,25 +207,25 @@ class TestAsset(unittest.TestCase):
asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, 'name')
asset = frappe.get_doc('Asset', asset_name)
asset.calculate_depreciation = 1
- asset.purchase_date = '2020-01-30'
+ asset.purchase_date = '2030-01-30'
asset.is_existing_asset = 0
- asset.available_for_use_date = "2020-01-30"
+ asset.available_for_use_date = "2030-01-30"
asset.append("finance_books", {
"expected_value_after_useful_life": 10000,
"depreciation_method": "Straight Line",
"total_number_of_depreciations": 3,
- "frequency_of_depreciation": 10,
- "depreciation_start_date": "2020-12-31"
+ "frequency_of_depreciation": 12,
+ "depreciation_start_date": "2030-12-31"
})
asset.insert()
asset.save()
expected_schedules = [
- ["2020-12-31", 28000.0, 28000.0],
- ["2021-12-31", 30000.0, 58000.0],
- ["2022-12-31", 30000.0, 88000.0],
- ["2023-01-30", 2000.0, 90000.0]
+ ["2030-12-31", 27534.25, 27534.25],
+ ["2031-12-31", 30000.0, 57534.25],
+ ["2032-12-31", 30000.0, 87534.25],
+ ["2033-01-30", 2465.75, 90000.0]
]
schedules = [[cstr(d.schedule_date), flt(d.depreciation_amount, 2), flt(d.accumulated_depreciation_amount, 2)]
@@ -266,8 +264,8 @@ class TestAsset(unittest.TestCase):
self.assertEqual(asset.get("schedules")[0].journal_entry[:4], "DEPR")
expected_gle = (
- ("_Test Accumulated Depreciations - _TC", 0.0, 32129.24),
- ("_Test Depreciations - _TC", 32129.24, 0.0)
+ ("_Test Accumulated Depreciations - _TC", 0.0, 30000.0),
+ ("_Test Depreciations - _TC", 30000.0, 0.0)
)
gle = frappe.db.sql("""select account, debit, credit from `tabGL Entry`
@@ -277,15 +275,15 @@ class TestAsset(unittest.TestCase):
self.assertEqual(gle, expected_gle)
self.assertEqual(asset.get("value_after_depreciation"), 0)
- def test_depreciation_entry_for_wdv(self):
+ def test_depreciation_entry_for_wdv_without_pro_rata(self):
pr = make_purchase_receipt(item_code="Macbook Pro",
qty=1, rate=8000.0, location="Test Location")
asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, 'name')
asset = frappe.get_doc('Asset', asset_name)
asset.calculate_depreciation = 1
- asset.available_for_use_date = '2030-06-06'
- asset.purchase_date = '2030-06-06'
+ asset.available_for_use_date = '2030-01-01'
+ asset.purchase_date = '2030-01-01'
asset.append("finance_books", {
"expected_value_after_useful_life": 1000,
"depreciation_method": "Written Down Value",
@@ -298,9 +296,41 @@ class TestAsset(unittest.TestCase):
self.assertEqual(asset.finance_books[0].rate_of_depreciation, 50.0)
expected_schedules = [
- ["2030-12-31", 4000.0, 4000.0],
- ["2031-12-31", 2000.0, 6000.0],
- ["2032-12-31", 1000.0, 7000.0],
+ ["2030-12-31", 4000.00, 4000.00],
+ ["2031-12-31", 2000.00, 6000.00],
+ ["2032-12-31", 1000.00, 7000.0],
+ ]
+
+ schedules = [[cstr(d.schedule_date), flt(d.depreciation_amount, 2), flt(d.accumulated_depreciation_amount, 2)]
+ for d in asset.get("schedules")]
+
+ self.assertEqual(schedules, expected_schedules)
+
+ def test_pro_rata_depreciation_entry_for_wdv(self):
+ pr = make_purchase_receipt(item_code="Macbook Pro",
+ qty=1, rate=8000.0, location="Test Location")
+
+ asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, 'name')
+ asset = frappe.get_doc('Asset', asset_name)
+ asset.calculate_depreciation = 1
+ asset.available_for_use_date = '2030-06-06'
+ asset.purchase_date = '2030-01-01'
+ asset.append("finance_books", {
+ "expected_value_after_useful_life": 1000,
+ "depreciation_method": "Written Down Value",
+ "total_number_of_depreciations": 3,
+ "frequency_of_depreciation": 12,
+ "depreciation_start_date": "2030-12-31"
+ })
+ asset.save(ignore_permissions=True)
+
+ self.assertEqual(asset.finance_books[0].rate_of_depreciation, 50.0)
+
+ expected_schedules = [
+ ["2030-12-31", 2279.45, 2279.45],
+ ["2031-12-31", 2860.28, 5139.73],
+ ["2032-12-31", 1430.14, 6569.87],
+ ["2033-06-06", 430.13, 7000.0],
]
schedules = [[cstr(d.schedule_date), flt(d.depreciation_amount, 2), flt(d.accumulated_depreciation_amount, 2)]
@@ -346,18 +376,19 @@ class TestAsset(unittest.TestCase):
asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, 'name')
asset = frappe.get_doc('Asset', asset_name)
asset.calculate_depreciation = 1
- asset.available_for_use_date = '2020-06-06'
- asset.purchase_date = '2020-06-06'
+ asset.available_for_use_date = nowdate()
+ asset.purchase_date = nowdate()
asset.append("finance_books", {
"expected_value_after_useful_life": 10000,
"depreciation_method": "Straight Line",
"total_number_of_depreciations": 3,
"frequency_of_depreciation": 10,
- "depreciation_start_date": "2020-06-06"
+ "depreciation_start_date": nowdate()
})
asset.insert()
asset.submit()
- post_depreciation_entries(date="2021-01-01")
+
+ post_depreciation_entries(date=add_months(nowdate(), 10))
scrap_asset(asset.name)
@@ -366,9 +397,9 @@ class TestAsset(unittest.TestCase):
self.assertTrue(asset.journal_entry_for_scrap)
expected_gle = (
- ("_Test Accumulated Depreciations - _TC", 147.54, 0.0),
+ ("_Test Accumulated Depreciations - _TC", 30000.0, 0.0),
("_Test Fixed Asset - _TC", 0.0, 100000.0),
- ("_Test Gain/Loss on Asset Disposal - _TC", 99852.46, 0.0)
+ ("_Test Gain/Loss on Asset Disposal - _TC", 70000.0, 0.0)
)
gle = frappe.db.sql("""select account, debit, credit from `tabGL Entry`
@@ -412,9 +443,9 @@ class TestAsset(unittest.TestCase):
self.assertEqual(frappe.db.get_value("Asset", asset.name, "status"), "Sold")
expected_gle = (
- ("_Test Accumulated Depreciations - _TC", 23051.47, 0.0),
+ ("_Test Accumulated Depreciations - _TC", 20392.16, 0.0),
("_Test Fixed Asset - _TC", 0.0, 100000.0),
- ("_Test Gain/Loss on Asset Disposal - _TC", 51948.53, 0.0),
+ ("_Test Gain/Loss on Asset Disposal - _TC", 54607.84, 0.0),
("Debtors - _TC", 25000.0, 0.0)
)
From 64f174fcaadc186e9bd9cddad96a007ac1690de8 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Fri, 26 Jul 2019 13:22:05 +0530
Subject: [PATCH 138/484] feat: Get item location from reference items
- Add option to get items from multiple sales order
- Add some required fiels to Pick TIcket Reference Item
---
.../doctype/sales_order/sales_order.py | 22 ++++++--
.../stock/doctype/pick_ticket/pick_ticket.js | 25 ++++++++-
.../doctype/pick_ticket/pick_ticket.json | 3 +-
.../stock/doctype/pick_ticket/pick_ticket.py | 54 ++++++++-----------
.../pick_ticket_reference_item.json | 25 ++++++++-
5 files changed, 88 insertions(+), 41 deletions(-)
diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py
index 1f889ab58c..97a9739e79 100755
--- a/erpnext/selling/doctype/sales_order/sales_order.py
+++ b/erpnext/selling/doctype/sales_order/sales_order.py
@@ -998,6 +998,22 @@ def make_inter_company_purchase_order(source_name, target_doc=None):
return make_inter_company_transaction("Sales Order", source_name, target_doc)
@frappe.whitelist()
-def make_pick_ticket(source_name, target_doc=None, offset=None):
- from erpnext.stock.doctype.pick_ticket.pick_ticket import get_pick_list
- return get_pick_list('Sales Order', source_name, 'items')
+def make_pick_ticket(source_name, target_doc=None):
+ doc = get_mapped_doc("Sales Order", source_name, {
+ "Sales Order": {
+ "doctype": "Pick Ticket",
+ "validation": {
+ "docstatus": ["=", 1]
+ }
+ },
+ "Sales Order Item": {
+ "doctype": "Pick Ticket Reference Item",
+ "field_map": {
+ "item_code": "item",
+ "parenttype": "reference_doctype",
+ "parent": "reference_name"
+ },
+ },
+ }, target_doc)
+
+ return doc
diff --git a/erpnext/stock/doctype/pick_ticket/pick_ticket.js b/erpnext/stock/doctype/pick_ticket/pick_ticket.js
index f9ae38a3e2..a2d6cd71de 100644
--- a/erpnext/stock/doctype/pick_ticket/pick_ticket.js
+++ b/erpnext/stock/doctype/pick_ticket/pick_ticket.js
@@ -2,7 +2,28 @@
// For license information, please see license.txt
frappe.ui.form.on('Pick Ticket', {
- // onload: function(frm) {
+ refresh: (frm) => {
+ this.frm.add_custom_button(__('Sales Order'), function() {
+ erpnext.utils.map_current_doc({
+ method: "erpnext.selling.doctype.sales_order.sales_order.make_pick_ticket",
+ source_doctype: "Sales Order",
+ target: frm,
+ setters: {
+ company: frm.doc.company || undefined,
+ },
+ get_query_filters: {
+ docstatus: 1,
+ }
+ });
+ }, __("Get items from"));
+
+ frm.add_custom_button(__('Get Item Locations'), () => {
+ frm.trigger('set_item_locations');
+ });
+ },
+
+ set_item_locations: (frm) => {
+ frm.call('set_item_locations')
+ }
- // }
});
diff --git a/erpnext/stock/doctype/pick_ticket/pick_ticket.json b/erpnext/stock/doctype/pick_ticket/pick_ticket.json
index fe331ac3c4..935192568e 100644
--- a/erpnext/stock/doctype/pick_ticket/pick_ticket.json
+++ b/erpnext/stock/doctype/pick_ticket/pick_ticket.json
@@ -43,7 +43,6 @@
"fieldtype": "Section Break"
},
{
- "collapsible": 1,
"fieldname": "section_break_4",
"fieldtype": "Section Break",
"label": "Reference Items"
@@ -55,7 +54,7 @@
"options": "Pick Ticket Reference Item"
}
],
- "modified": "2019-07-24 16:13:51.668880",
+ "modified": "2019-07-26 12:06:08.941760",
"modified_by": "Administrator",
"module": "Stock",
"name": "Pick Ticket",
diff --git a/erpnext/stock/doctype/pick_ticket/pick_ticket.py b/erpnext/stock/doctype/pick_ticket/pick_ticket.py
index 4c5fdb8297..eb54730616 100644
--- a/erpnext/stock/doctype/pick_ticket/pick_ticket.py
+++ b/erpnext/stock/doctype/pick_ticket/pick_ticket.py
@@ -7,16 +7,20 @@ import frappe
from frappe.model.document import Document
class PickTicket(Document):
- pass
+ def set_item_locations(self):
+ reference_items = self.reference_document_items
+ self.delete_key('items')
+ for item in reference_items:
+ data = get_items_with_warehouse_and_quantity(item)
-def get_pick_list(reference_doctype, reference_name, items_field):
- doc = frappe.new_doc('Pick Ticket')
- reference_doc = frappe.get_doc(reference_doctype, reference_name)
- doc.company = reference_doc.company
- items = reference_doc.get(items_field)
- add_picklist_items(items, doc, reference_doc)
- doc.save()
- return doc
+ for item_info in data:
+ self.append('items', item_info)
+
+ for item in self.get('items'):
+ if frappe.get_cached_value('Item', item.item, 'has_serial_no'):
+ set_serial_nos(item)
+ elif frappe.get_cached_value('Item', item.item, 'has_batch_no'):
+ set_batch_no(item, self)
def get_available_items(item):
# gets all items available in different warehouses
@@ -28,44 +32,30 @@ def get_available_items(item):
return available_items
-def get_items_with_warehouse_and_quantity(item_doc, reference_doc):
+def get_items_with_warehouse_and_quantity(item_doc):
items = []
- item_locations = get_available_items(item_doc.item_code)
+ item_locations = get_available_items(item_doc.item)
remaining_qty = item_doc.qty
- if not item_locations:
- print('{} qty of {} is out of stock. Skipping...'.format(remaining_qty, item_doc.item))
- return items
while remaining_qty > 0 and item_locations:
item_location = item_locations.pop(0)
qty = remaining_qty if item_location.qty >= remaining_qty else item_location.qty
items.append({
- 'item': item_doc.item_code,
+ 'item': item_doc.item,
'qty': qty,
'warehouse': item_location.warehouse,
- 'reference_doctype': reference_doc.doctype,
- 'reference_name': reference_doc.name
+ 'reference_doctype': item_doc.reference_doctype,
+ 'reference_name': item_doc.reference_name
})
remaining_qty -= qty
+ if remaining_qty:
+ print('---------- {} qty of {} is out of stock. Skipping... -------------'.format(remaining_qty, item_doc.item))
+ return items
+
return items
-def add_picklist_items(reference_items, doc, reference_doc):
- for item in reference_items:
- data = get_items_with_warehouse_and_quantity(item, reference_doc)
-
- for item_info in data:
- doc.append('items', item_info)
-
- doc.insert()
-
- for item in doc.get('items'):
- if item.has_serial_no:
- set_serial_nos(item)
- elif item.has_batch_no:
- set_batch_no(item, doc)
-
def set_serial_nos(item):
serial_nos = frappe.get_all('Serial No', {
'item_code': item.item,
diff --git a/erpnext/stock/doctype/pick_ticket_reference_item/pick_ticket_reference_item.json b/erpnext/stock/doctype/pick_ticket_reference_item/pick_ticket_reference_item.json
index 446e075686..ae7ea3567e 100644
--- a/erpnext/stock/doctype/pick_ticket_reference_item/pick_ticket_reference_item.json
+++ b/erpnext/stock/doctype/pick_ticket_reference_item/pick_ticket_reference_item.json
@@ -4,7 +4,10 @@
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
- "item"
+ "item",
+ "qty",
+ "reference_doctype",
+ "reference_name"
],
"fields": [
{
@@ -13,10 +16,28 @@
"in_list_view": 1,
"label": "Item",
"options": "Item"
+ },
+ {
+ "fieldname": "reference_doctype",
+ "fieldtype": "Link",
+ "label": "Reference Document type",
+ "options": "DocType"
+ },
+ {
+ "fieldname": "reference_name",
+ "fieldtype": "Dynamic Link",
+ "label": "Reference Name",
+ "options": "reference_doctype"
+ },
+ {
+ "fieldname": "qty",
+ "fieldtype": "Float",
+ "in_list_view": 1,
+ "label": "Qty"
}
],
"istable": 1,
- "modified": "2019-07-24 16:12:58.000378",
+ "modified": "2019-07-26 12:17:52.142186",
"modified_by": "Administrator",
"module": "Stock",
"name": "Pick Ticket Reference Item",
From e666b882e731fd52611c46eafcecb41968cd2b9b Mon Sep 17 00:00:00 2001
From: Michelle Alva <50285544+michellealva@users.noreply.github.com>
Date: Sat, 27 Jul 2019 10:03:18 +0530
Subject: [PATCH 139/484] fix: added payroll period in HR module (#18500)
---
erpnext/config/hr.py | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/erpnext/config/hr.py b/erpnext/config/hr.py
index 0367755595..bb055df3a3 100644
--- a/erpnext/config/hr.py
+++ b/erpnext/config/hr.py
@@ -160,6 +160,10 @@ def get_data():
"name": "Salary Slip",
"onboard": 1,
},
+ {
+ "type": "doctype",
+ "name": "Payroll Period",
+ },
{
"type": "doctype",
"name": "Salary Component",
From f0f4dbd5f84bedaa16c53ea488a2f288b16c4f09 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Sat, 27 Jul 2019 10:05:33 +0530
Subject: [PATCH 140/484] fix(payroll-entry): show make bank entry button when
manually submitting salary slip (#18498)
---
erpnext/hr/doctype/payroll_entry/payroll_entry.py | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/erpnext/hr/doctype/payroll_entry/payroll_entry.py b/erpnext/hr/doctype/payroll_entry/payroll_entry.py
index d8dd5c644b..38c36d9461 100644
--- a/erpnext/hr/doctype/payroll_entry/payroll_entry.py
+++ b/erpnext/hr/doctype/payroll_entry/payroll_entry.py
@@ -12,6 +12,16 @@ from erpnext.accounts.utils import get_fiscal_year
from erpnext.hr.doctype.employee.employee import get_holiday_list_for_employee
class PayrollEntry(Document):
+ def onload(self):
+ if not self.docstatus==1:
+ return
+
+ # check if salary slips were manually submitted
+ entries = frappe.db.count("Salary Slip", {'payroll_entry': self.name, 'docstatus': 1}, ['name'])
+ if cint(entries) == len(self.employees) and not self.salary_slips_submitted:
+ self.db_set("salary_slips_submitted", 1)
+ self.reload()
+
def on_submit(self):
self.create_salary_slips()
From 82a9118cb2a3b2d25be7440c65133442fd0ee1de Mon Sep 17 00:00:00 2001
From: Sahil Khan
Date: Sat, 27 Jul 2019 13:14:21 +0550
Subject: [PATCH 141/484] bumped to version 12.0.2
---
erpnext/__init__.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/__init__.py b/erpnext/__init__.py
index a9348c11f4..04f741e14b 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__ = '12.0.1'
+__version__ = '12.0.2'
def get_default_company(user=None):
'''Get default company for user'''
From d43764c8e595d86376131333235177043d434a3c Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Sun, 28 Jul 2019 22:03:28 +0530
Subject: [PATCH 142/484] fix: Use .set method to set serial no.
---
erpnext/stock/doctype/pick_ticket/pick_ticket.py | 2 +-
erpnext/stock/doctype/pick_ticket_item/pick_ticket_item.json | 3 +--
2 files changed, 2 insertions(+), 3 deletions(-)
diff --git a/erpnext/stock/doctype/pick_ticket/pick_ticket.py b/erpnext/stock/doctype/pick_ticket/pick_ticket.py
index eb54730616..18382e6781 100644
--- a/erpnext/stock/doctype/pick_ticket/pick_ticket.py
+++ b/erpnext/stock/doctype/pick_ticket/pick_ticket.py
@@ -61,7 +61,7 @@ def set_serial_nos(item):
'item_code': item.item,
'warehouse': item.warehouse
}, limit=item.qty, order_by='purchase_date')
- item.serial_no = '\n'.join([serial_no.name for serial_no in serial_nos])
+ item.set('serial_no', '\n'.join([serial_no.name for serial_no in serial_nos]))
def set_batch_no(item, doc):
batches = frappe.get_all('Stock Ledger Entry',
diff --git a/erpnext/stock/doctype/pick_ticket_item/pick_ticket_item.json b/erpnext/stock/doctype/pick_ticket_item/pick_ticket_item.json
index 6db32845e7..7095be68f0 100644
--- a/erpnext/stock/doctype/pick_ticket_item/pick_ticket_item.json
+++ b/erpnext/stock/doctype/pick_ticket_item/pick_ticket_item.json
@@ -72,7 +72,6 @@
"read_only": 1
},
{
- "depends_on": "has_serial_no",
"fieldname": "serial_no",
"fieldtype": "Small Text",
"label": "Serial No",
@@ -130,7 +129,7 @@
}
],
"istable": 1,
- "modified": "2019-07-25 11:18:58.478250",
+ "modified": "2019-07-26 14:47:33.965373",
"modified_by": "Administrator",
"module": "Stock",
"name": "Pick Ticket Item",
From 27bdba49d4ff93fac0ddbda72f7b639db4cdffeb Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Sun, 28 Jul 2019 22:04:07 +0530
Subject: [PATCH 143/484] test: Add test case statements
---
.../doctype/pick_ticket/test_pick_ticket.py | 23 +++++++++++++++++++
1 file changed, 23 insertions(+)
create mode 100644 erpnext/stock/doctype/pick_ticket/test_pick_ticket.py
diff --git a/erpnext/stock/doctype/pick_ticket/test_pick_ticket.py b/erpnext/stock/doctype/pick_ticket/test_pick_ticket.py
new file mode 100644
index 0000000000..3fee6db667
--- /dev/null
+++ b/erpnext/stock/doctype/pick_ticket/test_pick_ticket.py
@@ -0,0 +1,23 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+# import frappe
+import unittest
+
+class TestPickTicket(unittest.TestCase):
+ def test_pick_list_picks_warehouse_for_each_item():
+ pass
+
+ def test_pick_list_skips_out_of_warranty_item():
+ pass
+
+ def test_pick_list_skips_items_in_expired_batch():
+ pass
+
+ def test_pick_list_shows_serial_no_for_serialized_item():
+ pass
+
+ def test_pick_list_for_multiple_reference_doctypes():
+ pass
From b590f8931093de81a805bef429292afd90758b44 Mon Sep 17 00:00:00 2001
From: deepeshgarg007
Date: Sun, 14 Jul 2019 19:28:56 +0530
Subject: [PATCH 144/484] fix: Default Accounting Dimensions in doctypes
---
.../accounting_dimension/accounting_dimension.json | 9 ++++++++-
erpnext/public/js/utils.js | 2 +-
erpnext/public/js/utils/dimension_tree_filter.js | 3 +++
3 files changed, 12 insertions(+), 2 deletions(-)
diff --git a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.json b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.json
index 6a4dc5c34f..0fab74d522 100644
--- a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.json
+++ b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.json
@@ -9,6 +9,7 @@
"document_type",
"label",
"fieldname",
+ "default_dimension",
"mandatory_for_bs",
"mandatory_for_pl",
"disabled"
@@ -53,9 +54,15 @@
"fieldname": "mandatory_for_pl",
"fieldtype": "Check",
"label": "Mandatory For Profit and Loss Account"
+ },
+ {
+ "fieldname": "default_dimension",
+ "fieldtype": "Dynamic Link",
+ "label": "Default Dimension",
+ "options": "document_type"
}
],
- "modified": "2019-07-14 17:25:01.307948",
+ "modified": "2019-07-14 19:16:25.405924",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Accounting Dimension",
diff --git a/erpnext/public/js/utils.js b/erpnext/public/js/utils.js
index 0252f38931..1c5e98eb7d 100755
--- a/erpnext/public/js/utils.js
+++ b/erpnext/public/js/utils.js
@@ -69,7 +69,7 @@ $.extend(erpnext, {
return [];
}
let dimensions = await frappe.db.get_list('Accounting Dimension', {
- fields: ['label', 'fieldname', 'document_type'],
+ fields: ['label', 'fieldname', 'document_type', 'default_dimension'],
filters: {
disabled: 0
}
diff --git a/erpnext/public/js/utils/dimension_tree_filter.js b/erpnext/public/js/utils/dimension_tree_filter.js
index 549f95e039..4a82edda69 100644
--- a/erpnext/public/js/utils/dimension_tree_filter.js
+++ b/erpnext/public/js/utils/dimension_tree_filter.js
@@ -14,6 +14,9 @@ erpnext.doctypes_with_dimensions.forEach((doctype) => {
onload: function(frm) {
erpnext.dimension_filters.then((dimensions) => {
dimensions.forEach((dimension) => {
+ if (dimension['default_dimension']) {
+ frm.set_value(dimension['fieldname'], dimension['default_dimension']);
+ }
frappe.model.with_doctype(dimension['document_type'], () => {
if (frappe.meta.has_field(dimension['document_type'], 'is_group')) {
frm.set_query(dimension['fieldname'], {
From 7d270edf799b316832106f478d50d11a23c60d9c Mon Sep 17 00:00:00 2001
From: deepeshgarg007
Date: Wed, 17 Jul 2019 15:38:21 +0530
Subject: [PATCH 145/484] fix: Added default dimension and filter in bootinfo
---
.../accounting_dimension.js | 68 +++++++++++--------
.../accounting_dimension.json | 12 ++--
.../accounting_dimension.py | 8 +++
.../accounting_dimension_detail/__init__.py | 0
.../accounting_dimension_detail.json | 47 +++++++++++++
.../accounting_dimension_detail.py | 10 +++
.../journal_entry_account.json | 4 +-
.../sales_invoice_item.json | 3 +-
.../accounts_payable/accounts_payable.js | 15 ++--
.../accounts_payable_summary.js | 15 ++--
.../accounts_receivable.js | 15 ++--
.../accounts_receivable_summary.js | 14 ++--
.../budget_variance_report.js | 7 +-
.../report/general_ledger/general_ledger.js | 15 ++--
.../profitability_analysis.js | 7 +-
.../report/sales_register/sales_register.js | 15 ++--
.../report/trial_balance/trial_balance.js | 6 +-
erpnext/public/js/financial_statements.js | 14 ++--
erpnext/public/js/utils.js | 14 ----
.../public/js/utils/dimension_tree_filter.js | 41 +++++++----
erpnext/startup/boot.py | 18 +++++
21 files changed, 219 insertions(+), 129 deletions(-)
create mode 100644 erpnext/accounts/doctype/accounting_dimension_detail/__init__.py
create mode 100644 erpnext/accounts/doctype/accounting_dimension_detail/accounting_dimension_detail.json
create mode 100644 erpnext/accounts/doctype/accounting_dimension_detail/accounting_dimension_detail.py
diff --git a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.js b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.js
index ffb6d5e597..bb4d514981 100644
--- a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.js
+++ b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.js
@@ -8,41 +8,48 @@ frappe.ui.form.on('Accounting Dimension', {
frm.add_custom_button(__('Show {0}', [frm.doc.document_type]), function () {
frappe.set_route("List", frm.doc.document_type);
});
- }
- frm.set_query('document_type', () => {
- return {
- filters: {
- name: ['not in', ['Accounting Dimension', 'Project', 'Cost Center']]
- }
- };
- });
-
- let button = frm.doc.disabled ? "Enable" : "Disable";
-
- frm.add_custom_button(__(button), function() {
-
- frm.set_value('disabled', 1 - frm.doc.disabled);
-
- frappe.call({
- method: "erpnext.accounts.doctype.accounting_dimension.accounting_dimension.disable_dimension",
- args: {
- doc: frm.doc
- },
- freeze: true,
- callback: function(r) {
- let message = frm.doc.disabled ? "Dimension Disabled" : "Dimension Enabled";
- frm.save();
- frappe.show_alert({message:__(message), indicator:'green'});
- }
+ frm.set_query('document_type', () => {
+ return {
+ filters: {
+ name: ['not in', ['Accounting Dimension', 'Project', 'Cost Center']]
+ }
+ };
});
- });
+
+ let button = frm.doc.disabled ? "Enable" : "Disable";
+
+ frm.add_custom_button(__(button), function() {
+
+ frm.set_value('disabled', 1 - frm.doc.disabled);
+
+ frappe.call({
+ method: "erpnext.accounts.doctype.accounting_dimension.accounting_dimension.disable_dimension",
+ args: {
+ doc: frm.doc
+ },
+ freeze: true,
+ callback: function(r) {
+ let message = frm.doc.disabled ? "Dimension Disabled" : "Dimension Enabled";
+ frm.save();
+ frappe.show_alert({message:__(message), indicator:'green'});
+ }
+ });
+ });
+ }
},
document_type: function(frm) {
+
frm.set_value('label', frm.doc.document_type);
frm.set_value('fieldname', frappe.model.scrub(frm.doc.document_type));
+ if (frm.is_new()){
+ let row = frappe.model.add_child(frm.doc, "Accounting Dimension Detail", "dimension_defaults");
+ row.reference_document = frm.doc.document_type;
+ frm.refresh_fields("dimension_defaults");
+ }
+
frappe.db.get_value('Accounting Dimension', {'document_type': frm.doc.document_type}, 'document_type', (r) => {
if (r && r.document_type) {
frm.set_df_property('document_type', 'description', "Document type is already set as dimension");
@@ -50,3 +57,10 @@ frappe.ui.form.on('Accounting Dimension', {
});
},
});
+
+frappe.ui.form.on('Accounting Dimension Detail', {
+ dimension_defaults_add: function(frm, cdt, cdn) {
+ let row = locals[cdt][cdn];
+ row.reference_document = frm.doc.document_type;
+ }
+})
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.json b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.json
index 0fab74d522..19fa9bf837 100644
--- a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.json
+++ b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.json
@@ -9,7 +9,7 @@
"document_type",
"label",
"fieldname",
- "default_dimension",
+ "dimension_defaults",
"mandatory_for_bs",
"mandatory_for_pl",
"disabled"
@@ -56,13 +56,13 @@
"label": "Mandatory For Profit and Loss Account"
},
{
- "fieldname": "default_dimension",
- "fieldtype": "Dynamic Link",
- "label": "Default Dimension",
- "options": "document_type"
+ "fieldname": "dimension_defaults",
+ "fieldtype": "Table",
+ "label": "Dimension Defaults",
+ "options": "Accounting Dimension Detail"
}
],
- "modified": "2019-07-14 19:16:25.405924",
+ "modified": "2019-07-16 18:00:11.365510",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Accounting Dimension",
diff --git a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py
index 314849847c..218ab596e3 100644
--- a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py
+++ b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py
@@ -144,6 +144,14 @@ def toggle_disabling(doc):
frappe.clear_cache(doctype=doctype)
+ dimension_filters = frappe.db.sql("""
+ SELECT label, fieldname, document_type
+ FROM `tabAccounting Dimension`
+ WHERE disabled = 0
+ """, as_dict=1)
+
+ return dimension_filters
+
def get_doctypes_with_dimensions():
doclist = ["GL Entry", "Sales Invoice", "Purchase Invoice", "Payment Entry", "Asset",
"Expense Claim", "Stock Entry", "Budget", "Payroll Entry", "Delivery Note", "Sales Invoice Item", "Purchase Invoice Item",
diff --git a/erpnext/accounts/doctype/accounting_dimension_detail/__init__.py b/erpnext/accounts/doctype/accounting_dimension_detail/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/accounts/doctype/accounting_dimension_detail/accounting_dimension_detail.json b/erpnext/accounts/doctype/accounting_dimension_detail/accounting_dimension_detail.json
new file mode 100644
index 0000000000..f46a065271
--- /dev/null
+++ b/erpnext/accounts/doctype/accounting_dimension_detail/accounting_dimension_detail.json
@@ -0,0 +1,47 @@
+{
+ "creation": "2019-07-16 17:53:18.718831",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "company",
+ "reference_document",
+ "default_dimension"
+ ],
+ "fields": [
+ {
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Company",
+ "options": "Company",
+ "reqd": 1
+ },
+ {
+ "fieldname": "reference_document",
+ "fieldtype": "Link",
+ "hidden": 1,
+ "label": "Reference Document",
+ "options": "DocType",
+ "read_only": 1
+ },
+ {
+ "fieldname": "default_dimension",
+ "fieldtype": "Dynamic Link",
+ "in_list_view": 1,
+ "label": "Default Dimension",
+ "options": "reference_document",
+ "reqd": 1
+ }
+ ],
+ "istable": 1,
+ "modified": "2019-07-16 18:54:52.202378",
+ "modified_by": "Administrator",
+ "module": "Accounts",
+ "name": "Accounting Dimension Detail",
+ "owner": "Administrator",
+ "permissions": [],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/accounting_dimension_detail/accounting_dimension_detail.py b/erpnext/accounts/doctype/accounting_dimension_detail/accounting_dimension_detail.py
new file mode 100644
index 0000000000..17cf549fc4
--- /dev/null
+++ b/erpnext/accounts/doctype/accounting_dimension_detail/accounting_dimension_detail.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+# import frappe
+from frappe.model.document import Document
+
+class AccountingDimensionDetail(Document):
+ pass
diff --git a/erpnext/accounts/doctype/journal_entry_account/journal_entry_account.json b/erpnext/accounts/doctype/journal_entry_account/journal_entry_account.json
index e4acf5a03d..8728950286 100644
--- a/erpnext/accounts/doctype/journal_entry_account/journal_entry_account.json
+++ b/erpnext/accounts/doctype/journal_entry_account/journal_entry_account.json
@@ -258,6 +258,7 @@
"print_hide": 1
},
{
+ "collapsible": 1,
"fieldname": "accounting_dimensions_section",
"fieldtype": "Section Break",
"label": "Accounting Dimensions"
@@ -269,12 +270,13 @@
],
"idx": 1,
"istable": 1,
- "modified": "2019-05-25 22:14:02.715509",
+ "modified": "2019-07-16 17:12:08.238334",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Journal Entry Account",
"owner": "Administrator",
"permissions": [],
+ "sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json
index 465df277fd..779ac4f656 100644
--- a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json
+++ b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json
@@ -764,6 +764,7 @@
"label": "Image"
},
{
+ "collapsible": 1,
"fieldname": "accounting_dimensions_section",
"fieldtype": "Section Break",
"label": "Accounting Dimensions"
@@ -782,7 +783,7 @@
],
"idx": 1,
"istable": 1,
- "modified": "2019-06-28 17:30:12.156086",
+ "modified": "2019-07-16 16:36:46.527606",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice Item",
diff --git a/erpnext/accounts/report/accounts_payable/accounts_payable.js b/erpnext/accounts/report/accounts_payable/accounts_payable.js
index cfcc575718..5e07d080fb 100644
--- a/erpnext/accounts/report/accounts_payable/accounts_payable.js
+++ b/erpnext/accounts/report/accounts_payable/accounts_payable.js
@@ -115,13 +115,12 @@ frappe.query_reports["Accounts Payable"] = {
}
}
-erpnext.dimension_filters.then((dimensions) => {
- dimensions.forEach((dimension) => {
- frappe.query_reports["Accounts Payable"].filters.splice(9, 0 ,{
- "fieldname": dimension["fieldname"],
- "label": __(dimension["label"]),
- "fieldtype": "Link",
- "options": dimension["document_type"]
- });
+frappe.boot.dimension_filters.forEach((dimension) => {
+ frappe.query_reports["Accounts Payable"].filters.splice(9, 0 ,{
+ "fieldname": dimension["fieldname"],
+ "label": __(dimension["label"]),
+ "fieldtype": "Link",
+ "options": dimension["document_type"]
});
});
+
diff --git a/erpnext/accounts/report/accounts_payable_summary/accounts_payable_summary.js b/erpnext/accounts/report/accounts_payable_summary/accounts_payable_summary.js
index 006068a266..426de6782d 100644
--- a/erpnext/accounts/report/accounts_payable_summary/accounts_payable_summary.js
+++ b/erpnext/accounts/report/accounts_payable_summary/accounts_payable_summary.js
@@ -99,13 +99,12 @@ frappe.query_reports["Accounts Payable Summary"] = {
}
}
-erpnext.dimension_filters.then((dimensions) => {
- dimensions.forEach((dimension) => {
- frappe.query_reports["Accounts Payable Summary"].filters.splice(9, 0 ,{
- "fieldname": dimension["fieldname"],
- "label": __(dimension["label"]),
- "fieldtype": "Link",
- "options": dimension["document_type"]
- });
+frappe.boot.dimension_filters.forEach((dimension) => {
+ frappe.query_reports["Accounts Payable Summary"].filters.splice(9, 0 ,{
+ "fieldname": dimension["fieldname"],
+ "label": __(dimension["label"]),
+ "fieldtype": "Link",
+ "options": dimension["document_type"]
});
});
+
diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.js b/erpnext/accounts/report/accounts_receivable/accounts_receivable.js
index 2a45454bac..816e43898a 100644
--- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.js
+++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.js
@@ -173,13 +173,12 @@ frappe.query_reports["Accounts Receivable"] = {
}
}
-erpnext.dimension_filters.then((dimensions) => {
- dimensions.forEach((dimension) => {
- frappe.query_reports["Accounts Receivable"].filters.splice(9, 0 ,{
- "fieldname": dimension["fieldname"],
- "label": __(dimension["label"]),
- "fieldtype": "Link",
- "options": dimension["document_type"]
- });
+frappe.boot.dimension_filters.forEach((dimension) => {
+ frappe.query_reports["Accounts Receivable"].filters.splice(9, 0 ,{
+ "fieldname": dimension["fieldname"],
+ "label": __(dimension["label"]),
+ "fieldtype": "Link",
+ "options": dimension["document_type"]
});
});
+
diff --git a/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.js b/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.js
index a7c0787fcd..d63af8b3f3 100644
--- a/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.js
+++ b/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.js
@@ -117,13 +117,11 @@ frappe.query_reports["Accounts Receivable Summary"] = {
}
}
-erpnext.dimension_filters.then((dimensions) => {
- dimensions.forEach((dimension) => {
- frappe.query_reports["Accounts Receivable Summary"].filters.splice(9, 0 ,{
- "fieldname": dimension["fieldname"],
- "label": __(dimension["label"]),
- "fieldtype": "Link",
- "options": dimension["document_type"]
- });
+frappe.boot.dimension_filters.forEach((dimension) => {
+ frappe.query_reports["Accounts Receivable Summary"].filters.splice(9, 0 ,{
+ "fieldname": dimension["fieldname"],
+ "label": __(dimension["label"]),
+ "fieldtype": "Link",
+ "options": dimension["document_type"]
});
});
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 f2a33a83ee..33dc555a95 100644
--- a/erpnext/accounts/report/budget_variance_report/budget_variance_report.js
+++ b/erpnext/accounts/report/budget_variance_report/budget_variance_report.js
@@ -63,8 +63,7 @@ frappe.query_reports["Budget Variance Report"] = {
]
}
-erpnext.dimension_filters.then((dimensions) => {
- dimensions.forEach((dimension) => {
- frappe.query_reports["Budget Variance Report"].filters[4].options.push(dimension["document_type"]);
- });
+frappe.boot.dimension_filters.forEach((dimension) => {
+ frappe.query_reports["Budget Variance Report"].filters[4].options.push(dimension["document_type"]);
});
+
diff --git a/erpnext/accounts/report/general_ledger/general_ledger.js b/erpnext/accounts/report/general_ledger/general_ledger.js
index ea82575b80..74a1ea70ac 100644
--- a/erpnext/accounts/report/general_ledger/general_ledger.js
+++ b/erpnext/accounts/report/general_ledger/general_ledger.js
@@ -159,13 +159,12 @@ frappe.query_reports["General Ledger"] = {
]
}
-erpnext.dimension_filters.then((dimensions) => {
- dimensions.forEach((dimension) => {
- frappe.query_reports["General Ledger"].filters.splice(15, 0 ,{
- "fieldname": dimension["fieldname"],
- "label": __(dimension["label"]),
- "fieldtype": "Link",
- "options": dimension["document_type"]
- });
+frappe.boot.dimension_filters.forEach((dimension) => {
+ frappe.query_reports["General Ledger"].filters.splice(15, 0 ,{
+ "fieldname": dimension["fieldname"],
+ "label": __(dimension["label"]),
+ "fieldtype": "Link",
+ "options": dimension["document_type"]
});
});
+
diff --git a/erpnext/accounts/report/profitability_analysis/profitability_analysis.js b/erpnext/accounts/report/profitability_analysis/profitability_analysis.js
index d6864b54f7..2656a7e7b5 100644
--- a/erpnext/accounts/report/profitability_analysis/profitability_analysis.js
+++ b/erpnext/accounts/report/profitability_analysis/profitability_analysis.js
@@ -105,9 +105,8 @@ frappe.require("assets/erpnext/js/financial_statements.js", function() {
"initial_depth": 3
}
- erpnext.dimension_filters.then((dimensions) => {
- dimensions.forEach((dimension) => {
- frappe.query_reports["Profitability Analysis"].filters[1].options.push(dimension["document_type"]);
- });
+ frappe.boot.dimension_filters.forEach((dimension) => {
+ frappe.query_reports["Profitability Analysis"].filters[1].options.push(dimension["document_type"]);
});
+
});
diff --git a/erpnext/accounts/report/sales_register/sales_register.js b/erpnext/accounts/report/sales_register/sales_register.js
index 442aa1262e..105f5a29c1 100644
--- a/erpnext/accounts/report/sales_register/sales_register.js
+++ b/erpnext/accounts/report/sales_register/sales_register.js
@@ -68,13 +68,12 @@ frappe.query_reports["Sales Register"] = {
]
}
-erpnext.dimension_filters.then((dimensions) => {
- dimensions.forEach((dimension) => {
- frappe.query_reports["Sales Register"].filters.splice(7, 0 ,{
- "fieldname": dimension["fieldname"],
- "label": __(dimension["label"]),
- "fieldtype": "Link",
- "options": dimension["document_type"]
- });
+frappe.boot.dimension_filters.forEach((dimension) => {
+ frappe.query_reports["Sales Register"].filters.splice(7, 0 ,{
+ "fieldname": dimension["fieldname"],
+ "label": __(dimension["label"]),
+ "fieldtype": "Link",
+ "options": dimension["document_type"]
});
});
+
diff --git a/erpnext/accounts/report/trial_balance/trial_balance.js b/erpnext/accounts/report/trial_balance/trial_balance.js
index 73d2ab3898..dc6d07e2bb 100644
--- a/erpnext/accounts/report/trial_balance/trial_balance.js
+++ b/erpnext/accounts/report/trial_balance/trial_balance.js
@@ -94,10 +94,8 @@ frappe.require("assets/erpnext/js/financial_statements.js", function() {
"parent_field": "parent_account",
"initial_depth": 3
}
-});
-erpnext.dimension_filters.then((dimensions) => {
- dimensions.forEach((dimension) => {
+ frappe.boot.dimension_filters.forEach((dimension) => {
frappe.query_reports["Trial Balance"].filters.splice(5, 0 ,{
"fieldname": dimension["fieldname"],
"label": __(dimension["label"]),
@@ -107,3 +105,5 @@ erpnext.dimension_filters.then((dimensions) => {
});
});
+
+
diff --git a/erpnext/public/js/financial_statements.js b/erpnext/public/js/financial_statements.js
index 89cb13d981..5feedd3e15 100644
--- a/erpnext/public/js/financial_statements.js
+++ b/erpnext/public/js/financial_statements.js
@@ -129,14 +129,12 @@ function get_filters(){
}
]
- erpnext.dimension_filters.then((dimensions) => {
- dimensions.forEach((dimension) => {
- filters.push({
- "fieldname": dimension["fieldname"],
- "label": __(dimension["label"]),
- "fieldtype": "Link",
- "options": dimension["document_type"]
- });
+ frappe.boot.dimension_filters.forEach((dimension) => {
+ filters.push({
+ "fieldname": dimension["fieldname"],
+ "label": __(dimension["label"]),
+ "fieldtype": "Link",
+ "options": dimension["document_type"]
});
});
diff --git a/erpnext/public/js/utils.js b/erpnext/public/js/utils.js
index 1c5e98eb7d..0a363a04fd 100755
--- a/erpnext/public/js/utils.js
+++ b/erpnext/public/js/utils.js
@@ -63,20 +63,6 @@ $.extend(erpnext, {
me.show_serial_batch_selector(grid_row.frm, grid_row.doc);
});
},
-
- get_dimension_filters: async function() {
- if (!frappe.model.can_read('Accounting Dimension')) {
- return [];
- }
- let dimensions = await frappe.db.get_list('Accounting Dimension', {
- fields: ['label', 'fieldname', 'document_type', 'default_dimension'],
- filters: {
- disabled: 0
- }
- });
-
- return dimensions;
- }
});
diff --git a/erpnext/public/js/utils/dimension_tree_filter.js b/erpnext/public/js/utils/dimension_tree_filter.js
index 4a82edda69..22b4834dfb 100644
--- a/erpnext/public/js/utils/dimension_tree_filter.js
+++ b/erpnext/public/js/utils/dimension_tree_filter.js
@@ -7,25 +7,40 @@ erpnext.doctypes_with_dimensions = ["GL Entry", "Sales Invoice", "Purchase Invoi
"Landed Cost Item", "Asset Value Adjustment", "Loyalty Program", "Fee Schedule", "Fee Structure", "Stock Reconciliation",
"Travel Request", "Fees", "POS Profile"];
-erpnext.dimension_filters = erpnext.get_dimension_filters();
-
erpnext.doctypes_with_dimensions.forEach((doctype) => {
frappe.ui.form.on(doctype, {
onload: function(frm) {
- erpnext.dimension_filters.then((dimensions) => {
- dimensions.forEach((dimension) => {
- if (dimension['default_dimension']) {
- frm.set_value(dimension['fieldname'], dimension['default_dimension']);
+ frappe.boot.dimension_filters.forEach((dimension) => {
+ frappe.model.with_doctype(dimension['document_type'], () => {
+ if (frappe.meta.has_field(dimension['document_type'], 'is_group')) {
+ frm.set_query(dimension['fieldname'], {
+ "is_group": 0
+ });
}
- frappe.model.with_doctype(dimension['document_type'], () => {
- if (frappe.meta.has_field(dimension['document_type'], 'is_group')) {
- frm.set_query(dimension['fieldname'], {
- "is_group": 0
- });
- }
- });
});
});
+ },
+
+ company: function(frm) {
+ if(frm.doc.company) {
+ frappe.boot.dimension_filters.forEach((dimension) => {
+ frm.set_value(dimension['fieldname'], frappe.boot.default_dimensions[frm.doc.company][dimension['document_type']]);
+ });
+ }
+ },
+
+ items_add: function(frm, cdt, cdn) {
+ frappe.boot.dimension_filters.forEach((dimension) => {
+ var row = frappe.get_doc(cdt, cdn);
+ frm.script_manager.copy_from_first_row("items", row, [dimension['fieldname']]);
+ });
+ },
+
+ accounts_add: function(frm, cdt, cdn) {
+ frappe.boot.dimension_filters.forEach((dimension) => {
+ var row = frappe.get_doc(cdt, cdn);
+ frm.script_manager.copy_from_first_row("accounts", row, [dimension['fieldname']]);
+ });
}
});
});
\ No newline at end of file
diff --git a/erpnext/startup/boot.py b/erpnext/startup/boot.py
index 4ca43a89b8..7d70cc2349 100644
--- a/erpnext/startup/boot.py
+++ b/erpnext/startup/boot.py
@@ -39,6 +39,8 @@ def boot_session(bootinfo):
party_account_types = frappe.db.sql(""" select name, ifnull(account_type, '') from `tabParty Type`""")
bootinfo.party_account_types = frappe._dict(party_account_types)
+ load_dimension_filters(bootinfo)
+ load_default_dimensions(bootinfo)
def load_country_and_currency(bootinfo):
country = frappe.db.get_default("country")
@@ -49,6 +51,22 @@ def load_country_and_currency(bootinfo):
number_format, smallest_currency_fraction_value, symbol from tabCurrency
where enabled=1""", as_dict=1, update={"doctype":":Currency"})
+def load_dimension_filters(bootinfo):
+ bootinfo.dimension_filters = frappe.db.sql("""
+ SELECT label, fieldname, document_type
+ FROM `tabAccounting Dimension`
+ WHERE disabled = 0
+ """, as_dict=1)
+
+def load_default_dimensions(bootinfo):
+ default_dimensions = frappe.db.sql("""SELECT parent, company, default_dimension
+ FROM `tabAccounting Dimension Detail`""", as_dict=1)
+
+ bootinfo.default_dimensions = {}
+ for dimension in default_dimensions:
+ bootinfo.default_dimensions.setdefault(dimension['company'], {})
+ bootinfo.default_dimensions[dimension['company']][dimension['parent']] = dimension['default_dimension']
+
def update_page_info(bootinfo):
bootinfo.page_info.update({
"Chart of Accounts": {
From f1f79ff1e14308cd31ef752469278f79bc1f7cf1 Mon Sep 17 00:00:00 2001
From: deepeshgarg007
Date: Thu, 18 Jul 2019 08:54:15 +0530
Subject: [PATCH 146/484] fix: Remove dimensions from boot
---
.../accounting_dimension.json | 18 +---------
.../accounting_dimension.py | 34 ++++++++++++++-----
.../accounting_dimension_detail.json | 24 +++++++++++--
erpnext/accounts/doctype/gl_entry/gl_entry.py | 16 ++++-----
.../accounts_payable/accounts_payable.js | 2 +-
.../accounts_payable_summary.js | 2 +-
.../accounts_receivable.js | 2 +-
.../accounts_receivable_summary.js | 2 +-
.../budget_variance_report.js | 2 +-
.../report/general_ledger/general_ledger.js | 2 +-
.../profitability_analysis.js | 2 +-
.../report/sales_register/sales_register.js | 2 +-
.../report/trial_balance/trial_balance.js | 2 +-
erpnext/public/js/financial_statements.js | 2 +-
.../public/js/utils/dimension_tree_filter.js | 18 +++++++---
erpnext/startup/boot.py | 18 ----------
16 files changed, 79 insertions(+), 69 deletions(-)
diff --git a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.json b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.json
index 19fa9bf837..cf6dc7a8fa 100644
--- a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.json
+++ b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.json
@@ -1,6 +1,4 @@
{
- "_comments": "[]",
- "_liked_by": "[]",
"autoname": "field:label",
"creation": "2019-05-04 18:13:37.002352",
"doctype": "DocType",
@@ -10,8 +8,6 @@
"label",
"fieldname",
"dimension_defaults",
- "mandatory_for_bs",
- "mandatory_for_pl",
"disabled"
],
"fields": [
@@ -43,18 +39,6 @@
"label": "Disable",
"read_only": 1
},
- {
- "default": "0",
- "fieldname": "mandatory_for_bs",
- "fieldtype": "Check",
- "label": "Mandatory For Balance Sheet"
- },
- {
- "default": "0",
- "fieldname": "mandatory_for_pl",
- "fieldtype": "Check",
- "label": "Mandatory For Profit and Loss Account"
- },
{
"fieldname": "dimension_defaults",
"fieldtype": "Table",
@@ -62,7 +46,7 @@
"options": "Accounting Dimension Detail"
}
],
- "modified": "2019-07-16 18:00:11.365510",
+ "modified": "2019-07-17 16:49:31.134385",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Accounting Dimension",
diff --git a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py
index 218ab596e3..90cc50d419 100644
--- a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py
+++ b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py
@@ -144,14 +144,6 @@ def toggle_disabling(doc):
frappe.clear_cache(doctype=doctype)
- dimension_filters = frappe.db.sql("""
- SELECT label, fieldname, document_type
- FROM `tabAccounting Dimension`
- WHERE disabled = 0
- """, as_dict=1)
-
- return dimension_filters
-
def get_doctypes_with_dimensions():
doclist = ["GL Entry", "Sales Invoice", "Purchase Invoice", "Payment Entry", "Asset",
"Expense Claim", "Stock Entry", "Budget", "Payroll Entry", "Delivery Note", "Sales Invoice Item", "Purchase Invoice Item",
@@ -163,9 +155,33 @@ def get_doctypes_with_dimensions():
return doclist
def get_accounting_dimensions(as_list=True):
- accounting_dimensions = frappe.get_all("Accounting Dimension", fields=["label", "fieldname", "mandatory_for_pl", "mandatory_for_bs", "disabled"], filters={"disabled": 0})
+ accounting_dimensions = frappe.get_all("Accounting Dimension", fields=["label", "fieldname", "disabled"])
if as_list:
return [d.fieldname for d in accounting_dimensions]
else:
return accounting_dimensions
+
+def get_checks_for_pl_and_bs_accounts():
+ dimensions = frappe.db.sql("""SELECT parent, company, mandatory_for_pl, mandatory_for_bs
+ FROM `tabAccounting Dimension Detail`""", as_dict=1)
+
+ return dimensions
+
+@frappe.whitelist()
+def get_dimension_filters():
+ dimension_filters = frappe.db.sql("""
+ SELECT label, fieldname, document_type
+ FROM `tabAccounting Dimension`
+ WHERE disabled = 0
+ """, as_dict=1)
+
+ default_dimensions = frappe.db.sql("""SELECT parent, company, default_dimension
+ FROM `tabAccounting Dimension Detail`""", as_dict=1)
+
+ default_dimensions_map = {}
+ for dimension in default_dimensions:
+ default_dimensions_map.setdefault(dimension['company'], {})
+ default_dimensions_map[dimension['company']][dimension['parent']] = dimension['default_dimension']
+
+ return dimension_filters, default_dimensions_map
diff --git a/erpnext/accounts/doctype/accounting_dimension_detail/accounting_dimension_detail.json b/erpnext/accounts/doctype/accounting_dimension_detail/accounting_dimension_detail.json
index f46a065271..1ccef6cc7a 100644
--- a/erpnext/accounts/doctype/accounting_dimension_detail/accounting_dimension_detail.json
+++ b/erpnext/accounts/doctype/accounting_dimension_detail/accounting_dimension_detail.json
@@ -6,10 +6,13 @@
"field_order": [
"company",
"reference_document",
- "default_dimension"
+ "default_dimension",
+ "mandatory_for_bs",
+ "mandatory_for_pl"
],
"fields": [
{
+ "columns": 2,
"fieldname": "company",
"fieldtype": "Link",
"in_list_view": 1,
@@ -26,16 +29,33 @@
"read_only": 1
},
{
+ "columns": 2,
"fieldname": "default_dimension",
"fieldtype": "Dynamic Link",
"in_list_view": 1,
"label": "Default Dimension",
"options": "reference_document",
"reqd": 1
+ },
+ {
+ "columns": 3,
+ "default": "0",
+ "fieldname": "mandatory_for_bs",
+ "fieldtype": "Check",
+ "in_list_view": 1,
+ "label": "Mandatory For Balance Sheet"
+ },
+ {
+ "columns": 3,
+ "default": "0",
+ "fieldname": "mandatory_for_pl",
+ "fieldtype": "Check",
+ "in_list_view": 1,
+ "label": "Mandatory For Profit and Loss Account"
}
],
"istable": 1,
- "modified": "2019-07-16 18:54:52.202378",
+ "modified": "2019-07-17 23:34:33.026883",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Accounting Dimension Detail",
diff --git a/erpnext/accounts/doctype/gl_entry/gl_entry.py b/erpnext/accounts/doctype/gl_entry/gl_entry.py
index 84276eae10..80e518644d 100644
--- a/erpnext/accounts/doctype/gl_entry/gl_entry.py
+++ b/erpnext/accounts/doctype/gl_entry/gl_entry.py
@@ -12,7 +12,7 @@ from erpnext.accounts.party import validate_party_gle_currency, validate_party_f
from erpnext.accounts.utils import get_account_currency
from erpnext.accounts.utils import get_fiscal_year
from erpnext.exceptions import InvalidAccountCurrency
-from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions
+from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_checks_for_pl_and_bs_accounts
exclude_from_linked_with = True
class GLEntry(Document):
@@ -86,19 +86,19 @@ class GLEntry(Document):
account_type = frappe.db.get_value("Account", self.account, "report_type")
- for dimension in get_accounting_dimensions(as_list=False):
+ for dimension in get_checks_for_pl_and_bs_accounts():
if account_type == "Profit and Loss" \
- and dimension.mandatory_for_pl and not dimension.disabled:
- if not self.get(dimension.fieldname):
+ and self.company == dimension.company and dimension.mandatory_for_pl and not dimension.disabled:
+ if not self.get(frappe.scrub(dimension.parent)):
frappe.throw(_("Accounting Dimension {0} is required for 'Profit and Loss' account {1}.")
- .format(dimension.label, self.account))
+ .format(dimension.parent, self.account))
if account_type == "Balance Sheet" \
- and dimension.mandatory_for_bs and not dimension.disabled:
- if not self.get(dimension.fieldname):
+ and self.company == dimension.company and dimension.mandatory_for_bs and not dimension.disabled:
+ if not self.get(frappe.scrub(dimension.parent)):
frappe.throw(_("Accounting Dimension {0} is required for 'Balance Sheet' account {1}.")
- .format(dimension.label, self.account))
+ .format(dimension.parent, self.account))
def check_pl_account(self):
diff --git a/erpnext/accounts/report/accounts_payable/accounts_payable.js b/erpnext/accounts/report/accounts_payable/accounts_payable.js
index 5e07d080fb..8eb670de51 100644
--- a/erpnext/accounts/report/accounts_payable/accounts_payable.js
+++ b/erpnext/accounts/report/accounts_payable/accounts_payable.js
@@ -115,7 +115,7 @@ frappe.query_reports["Accounts Payable"] = {
}
}
-frappe.boot.dimension_filters.forEach((dimension) => {
+erpnext.dimension_filters.forEach((dimension) => {
frappe.query_reports["Accounts Payable"].filters.splice(9, 0 ,{
"fieldname": dimension["fieldname"],
"label": __(dimension["label"]),
diff --git a/erpnext/accounts/report/accounts_payable_summary/accounts_payable_summary.js b/erpnext/accounts/report/accounts_payable_summary/accounts_payable_summary.js
index 426de6782d..5f0fdc9f2c 100644
--- a/erpnext/accounts/report/accounts_payable_summary/accounts_payable_summary.js
+++ b/erpnext/accounts/report/accounts_payable_summary/accounts_payable_summary.js
@@ -99,7 +99,7 @@ frappe.query_reports["Accounts Payable Summary"] = {
}
}
-frappe.boot.dimension_filters.forEach((dimension) => {
+erpnext.dimension_filters.forEach((dimension) => {
frappe.query_reports["Accounts Payable Summary"].filters.splice(9, 0 ,{
"fieldname": dimension["fieldname"],
"label": __(dimension["label"]),
diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.js b/erpnext/accounts/report/accounts_receivable/accounts_receivable.js
index 816e43898a..4551973ac6 100644
--- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.js
+++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.js
@@ -173,7 +173,7 @@ frappe.query_reports["Accounts Receivable"] = {
}
}
-frappe.boot.dimension_filters.forEach((dimension) => {
+erpnext.dimension_filters.forEach((dimension) => {
frappe.query_reports["Accounts Receivable"].filters.splice(9, 0 ,{
"fieldname": dimension["fieldname"],
"label": __(dimension["label"]),
diff --git a/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.js b/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.js
index d63af8b3f3..0120608a8f 100644
--- a/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.js
+++ b/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.js
@@ -117,7 +117,7 @@ frappe.query_reports["Accounts Receivable Summary"] = {
}
}
-frappe.boot.dimension_filters.forEach((dimension) => {
+erpnext.dimension_filters.forEach((dimension) => {
frappe.query_reports["Accounts Receivable Summary"].filters.splice(9, 0 ,{
"fieldname": dimension["fieldname"],
"label": __(dimension["label"]),
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 33dc555a95..24511871fd 100644
--- a/erpnext/accounts/report/budget_variance_report/budget_variance_report.js
+++ b/erpnext/accounts/report/budget_variance_report/budget_variance_report.js
@@ -63,7 +63,7 @@ frappe.query_reports["Budget Variance Report"] = {
]
}
-frappe.boot.dimension_filters.forEach((dimension) => {
+erpnext.dimension_filters.forEach((dimension) => {
frappe.query_reports["Budget Variance Report"].filters[4].options.push(dimension["document_type"]);
});
diff --git a/erpnext/accounts/report/general_ledger/general_ledger.js b/erpnext/accounts/report/general_ledger/general_ledger.js
index 74a1ea70ac..4a287060b3 100644
--- a/erpnext/accounts/report/general_ledger/general_ledger.js
+++ b/erpnext/accounts/report/general_ledger/general_ledger.js
@@ -159,7 +159,7 @@ frappe.query_reports["General Ledger"] = {
]
}
-frappe.boot.dimension_filters.forEach((dimension) => {
+erpnext.dimension_filters.forEach((dimension) => {
frappe.query_reports["General Ledger"].filters.splice(15, 0 ,{
"fieldname": dimension["fieldname"],
"label": __(dimension["label"]),
diff --git a/erpnext/accounts/report/profitability_analysis/profitability_analysis.js b/erpnext/accounts/report/profitability_analysis/profitability_analysis.js
index 2656a7e7b5..889ede5a82 100644
--- a/erpnext/accounts/report/profitability_analysis/profitability_analysis.js
+++ b/erpnext/accounts/report/profitability_analysis/profitability_analysis.js
@@ -105,7 +105,7 @@ frappe.require("assets/erpnext/js/financial_statements.js", function() {
"initial_depth": 3
}
- frappe.boot.dimension_filters.forEach((dimension) => {
+ erpnext.dimension_filters.forEach((dimension) => {
frappe.query_reports["Profitability Analysis"].filters[1].options.push(dimension["document_type"]);
});
diff --git a/erpnext/accounts/report/sales_register/sales_register.js b/erpnext/accounts/report/sales_register/sales_register.js
index 105f5a29c1..9dee656d4a 100644
--- a/erpnext/accounts/report/sales_register/sales_register.js
+++ b/erpnext/accounts/report/sales_register/sales_register.js
@@ -68,7 +68,7 @@ frappe.query_reports["Sales Register"] = {
]
}
-frappe.boot.dimension_filters.forEach((dimension) => {
+erpnext.dimension_filters.forEach((dimension) => {
frappe.query_reports["Sales Register"].filters.splice(7, 0 ,{
"fieldname": dimension["fieldname"],
"label": __(dimension["label"]),
diff --git a/erpnext/accounts/report/trial_balance/trial_balance.js b/erpnext/accounts/report/trial_balance/trial_balance.js
index dc6d07e2bb..f15b5b1a19 100644
--- a/erpnext/accounts/report/trial_balance/trial_balance.js
+++ b/erpnext/accounts/report/trial_balance/trial_balance.js
@@ -95,7 +95,7 @@ frappe.require("assets/erpnext/js/financial_statements.js", function() {
"initial_depth": 3
}
- frappe.boot.dimension_filters.forEach((dimension) => {
+ erpnext.dimension_filters.forEach((dimension) => {
frappe.query_reports["Trial Balance"].filters.splice(5, 0 ,{
"fieldname": dimension["fieldname"],
"label": __(dimension["label"]),
diff --git a/erpnext/public/js/financial_statements.js b/erpnext/public/js/financial_statements.js
index 5feedd3e15..63e057c39d 100644
--- a/erpnext/public/js/financial_statements.js
+++ b/erpnext/public/js/financial_statements.js
@@ -129,7 +129,7 @@ function get_filters(){
}
]
- frappe.boot.dimension_filters.forEach((dimension) => {
+ erpnext.dimension_filters.forEach((dimension) => {
filters.push({
"fieldname": dimension["fieldname"],
"label": __(dimension["label"]),
diff --git a/erpnext/public/js/utils/dimension_tree_filter.js b/erpnext/public/js/utils/dimension_tree_filter.js
index 22b4834dfb..9d4c435240 100644
--- a/erpnext/public/js/utils/dimension_tree_filter.js
+++ b/erpnext/public/js/utils/dimension_tree_filter.js
@@ -7,10 +7,18 @@ erpnext.doctypes_with_dimensions = ["GL Entry", "Sales Invoice", "Purchase Invoi
"Landed Cost Item", "Asset Value Adjustment", "Loyalty Program", "Fee Schedule", "Fee Structure", "Stock Reconciliation",
"Travel Request", "Fees", "POS Profile"];
+frappe.call({
+ method: "erpnext.accounts.doctype.accounting_dimension.accounting_dimension.get_dimension_filters",
+ callback: function(r){
+ erpnext.dimension_filters = r.message[0];
+ erpnext.default_dimensions = r.message[1];
+ }
+});
+
erpnext.doctypes_with_dimensions.forEach((doctype) => {
frappe.ui.form.on(doctype, {
onload: function(frm) {
- frappe.boot.dimension_filters.forEach((dimension) => {
+ erpnext.dimension_filters.forEach((dimension) => {
frappe.model.with_doctype(dimension['document_type'], () => {
if (frappe.meta.has_field(dimension['document_type'], 'is_group')) {
frm.set_query(dimension['fieldname'], {
@@ -23,21 +31,21 @@ erpnext.doctypes_with_dimensions.forEach((doctype) => {
company: function(frm) {
if(frm.doc.company) {
- frappe.boot.dimension_filters.forEach((dimension) => {
- frm.set_value(dimension['fieldname'], frappe.boot.default_dimensions[frm.doc.company][dimension['document_type']]);
+ erpnext.dimension_filters.forEach((dimension) => {
+ frm.set_value(dimension['fieldname'], erpnext.default_dimensions[frm.doc.company][dimension['document_type']]);
});
}
},
items_add: function(frm, cdt, cdn) {
- frappe.boot.dimension_filters.forEach((dimension) => {
+ erpnext.dimension_filters.forEach((dimension) => {
var row = frappe.get_doc(cdt, cdn);
frm.script_manager.copy_from_first_row("items", row, [dimension['fieldname']]);
});
},
accounts_add: function(frm, cdt, cdn) {
- frappe.boot.dimension_filters.forEach((dimension) => {
+ erpnext.dimension_filters.forEach((dimension) => {
var row = frappe.get_doc(cdt, cdn);
frm.script_manager.copy_from_first_row("accounts", row, [dimension['fieldname']]);
});
diff --git a/erpnext/startup/boot.py b/erpnext/startup/boot.py
index 7d70cc2349..4ca43a89b8 100644
--- a/erpnext/startup/boot.py
+++ b/erpnext/startup/boot.py
@@ -39,8 +39,6 @@ def boot_session(bootinfo):
party_account_types = frappe.db.sql(""" select name, ifnull(account_type, '') from `tabParty Type`""")
bootinfo.party_account_types = frappe._dict(party_account_types)
- load_dimension_filters(bootinfo)
- load_default_dimensions(bootinfo)
def load_country_and_currency(bootinfo):
country = frappe.db.get_default("country")
@@ -51,22 +49,6 @@ def load_country_and_currency(bootinfo):
number_format, smallest_currency_fraction_value, symbol from tabCurrency
where enabled=1""", as_dict=1, update={"doctype":":Currency"})
-def load_dimension_filters(bootinfo):
- bootinfo.dimension_filters = frappe.db.sql("""
- SELECT label, fieldname, document_type
- FROM `tabAccounting Dimension`
- WHERE disabled = 0
- """, as_dict=1)
-
-def load_default_dimensions(bootinfo):
- default_dimensions = frappe.db.sql("""SELECT parent, company, default_dimension
- FROM `tabAccounting Dimension Detail`""", as_dict=1)
-
- bootinfo.default_dimensions = {}
- for dimension in default_dimensions:
- bootinfo.default_dimensions.setdefault(dimension['company'], {})
- bootinfo.default_dimensions[dimension['company']][dimension['parent']] = dimension['default_dimension']
-
def update_page_info(bootinfo):
bootinfo.page_info.update({
"Chart of Accounts": {
From acc0958ead357df9bcc5691af386ccbea28d90d1 Mon Sep 17 00:00:00 2001
From: deepeshgarg007
Date: Thu, 18 Jul 2019 18:14:12 +0530
Subject: [PATCH 147/484] fix: Patch
---
.../v12_0/update_ewaybill_field_position.py | 25 ++++++++++---------
1 file changed, 13 insertions(+), 12 deletions(-)
diff --git a/erpnext/patches/v12_0/update_ewaybill_field_position.py b/erpnext/patches/v12_0/update_ewaybill_field_position.py
index d0291d2123..c0230c4395 100644
--- a/erpnext/patches/v12_0/update_ewaybill_field_position.py
+++ b/erpnext/patches/v12_0/update_ewaybill_field_position.py
@@ -10,18 +10,19 @@ def execute():
field = frappe.db.get_value("Custom Field", {"dt": "Sales Invoice", "fieldname": "ewaybill"})
- ewaybill_field = frappe.get_doc("Custom Field", field)
+ if field:
+ ewaybill_field = frappe.get_doc("Custom Field", field)
- ewaybill_field.flags.ignore_validate = True
+ ewaybill_field.flags.ignore_validate = True
- ewaybill_field.update({
- 'fieldname': 'ewaybill',
- 'label': 'e-Way Bill No.',
- 'fieldtype': 'Data',
- 'depends_on': 'eval:(doc.docstatus === 1)',
- 'allow_on_submit': 1,
- 'insert_after': 'tax_id',
- 'translatable': 0
- })
+ ewaybill_field.update({
+ 'fieldname': 'ewaybill',
+ 'label': 'e-Way Bill No.',
+ 'fieldtype': 'Data',
+ 'depends_on': 'eval:(doc.docstatus === 1)',
+ 'allow_on_submit': 1,
+ 'insert_after': 'tax_id',
+ 'translatable': 0
+ })
- ewaybill_field.save()
\ No newline at end of file
+ ewaybill_field.save()
\ No newline at end of file
From 22a4857a3c305c3f92a73be286ceaf9c1b34214a Mon Sep 17 00:00:00 2001
From: deepeshgarg007
Date: Thu, 18 Jul 2019 18:29:34 +0530
Subject: [PATCH 148/484] fix: Codacy Fixes
---
.../doctype/accounting_dimension/accounting_dimension.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.js b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.js
index bb4d514981..d5f39b5cd3 100644
--- a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.js
+++ b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.js
@@ -63,4 +63,4 @@ frappe.ui.form.on('Accounting Dimension Detail', {
let row = locals[cdt][cdn];
row.reference_document = frm.doc.document_type;
}
-})
\ No newline at end of file
+});
\ No newline at end of file
From 5dfe4df23b8dd282fdbda33ab7ce4ae4970bdf6a Mon Sep 17 00:00:00 2001
From: deepeshgarg007
Date: Sat, 20 Jul 2019 17:53:29 +0530
Subject: [PATCH 149/484] fix: Set query fix
---
.../accounting_dimension/accounting_dimension.js | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.js b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.js
index d5f39b5cd3..88b11dd678 100644
--- a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.js
+++ b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.js
@@ -4,19 +4,19 @@
frappe.ui.form.on('Accounting Dimension', {
refresh: function(frm) {
+ frm.set_query('document_type', () => {
+ return {
+ filters: {
+ name: ['not in', ['Accounting Dimension', 'Project', 'Cost Center', 'Accounting Dimension Detail']]
+ }
+ };
+ });
+
if (!frm.is_new()) {
frm.add_custom_button(__('Show {0}', [frm.doc.document_type]), function () {
frappe.set_route("List", frm.doc.document_type);
});
- frm.set_query('document_type', () => {
- return {
- filters: {
- name: ['not in', ['Accounting Dimension', 'Project', 'Cost Center']]
- }
- };
- });
-
let button = frm.doc.disabled ? "Enable" : "Disable";
frm.add_custom_button(__(button), function() {
From 1c1f6f90bb8280a92b5090954a1615ea08ee24c3 Mon Sep 17 00:00:00 2001
From: deepeshgarg007
Date: Mon, 22 Jul 2019 12:41:48 +0530
Subject: [PATCH 150/484] fix: Test Cases for accounting dimensions
---
.../test_accounting_dimension.py | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)
diff --git a/erpnext/accounts/doctype/accounting_dimension/test_accounting_dimension.py b/erpnext/accounts/doctype/accounting_dimension/test_accounting_dimension.py
index 527ddcc80f..7de7c108a2 100644
--- a/erpnext/accounts/doctype/accounting_dimension/test_accounting_dimension.py
+++ b/erpnext/accounts/doctype/accounting_dimension/test_accounting_dimension.py
@@ -28,11 +28,20 @@ class TestAccountingDimension(unittest.TestCase):
"doctype": "Accounting Dimension",
"document_type": "Location",
"mandatory_for_pl": 1
- }).insert()
+ })
+
+ dimension1.append("dimension_defaults", {
+ "company": "_Test Company",
+ "reference_document": "Location",
+ "default_dimension": "Block 1",
+ "mandatory_for_pl": 1
+ })
+
+ dimension1.insert()
+ dimension1.save()
else:
dimension1 = frappe.get_doc("Accounting Dimension", "Location")
dimension1.disabled = 0
- dimension1.mandatory_for_pl = 1
dimension1.save()
def test_dimension_against_sales_invoice(self):
From 3d15128b91038b476fe1440e7ebd2f04ae61fc2a Mon Sep 17 00:00:00 2001
From: deepeshgarg007
Date: Tue, 23 Jul 2019 08:32:37 +0530
Subject: [PATCH 151/484] fix: Test cases for accounting dimensions
---
.../doctype/accounting_dimension/test_accounting_dimension.py | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/erpnext/accounts/doctype/accounting_dimension/test_accounting_dimension.py b/erpnext/accounts/doctype/accounting_dimension/test_accounting_dimension.py
index 7de7c108a2..c75ba825a4 100644
--- a/erpnext/accounts/doctype/accounting_dimension/test_accounting_dimension.py
+++ b/erpnext/accounts/doctype/accounting_dimension/test_accounting_dimension.py
@@ -27,14 +27,13 @@ class TestAccountingDimension(unittest.TestCase):
dimension1 = frappe.get_doc({
"doctype": "Accounting Dimension",
"document_type": "Location",
- "mandatory_for_pl": 1
})
dimension1.append("dimension_defaults", {
"company": "_Test Company",
"reference_document": "Location",
"default_dimension": "Block 1",
- "mandatory_for_pl": 1
+ "mandatory_for_bs": 1
})
dimension1.insert()
From 82661372f72f1905380ffe06d6318b246a62a0e2 Mon Sep 17 00:00:00 2001
From: deepeshgarg007
Date: Fri, 26 Jul 2019 09:12:30 +0530
Subject: [PATCH 152/484] fix: Add accounting dimensions to subscription and
opening invoice tool
---
.../accounting_dimension.py | 7 +-
.../opening_invoice_creation_tool.json | 14 +-
.../opening_invoice_creation_tool.py | 8 +
.../opening_invoice_creation_tool_item.json | 15 +-
.../doctype/subscription/subscription.json | 1099 ++++-------------
.../doctype/subscription/subscription.py | 13 +
.../subscription_plan/subscription_plan.json | 723 ++---------
erpnext/patches.txt | 1 +
...counting_dimensions_in_missing_doctypes.py | 38 +
.../public/js/utils/dimension_tree_filter.js | 5 +-
10 files changed, 440 insertions(+), 1483 deletions(-)
create mode 100644 erpnext/patches/v12_0/create_accounting_dimensions_in_missing_doctypes.py
diff --git a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py
index 90cc50d419..61f699f6ab 100644
--- a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py
+++ b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py
@@ -96,13 +96,13 @@ def delete_accounting_dimension(doc):
frappe.db.sql("""
DELETE FROM `tabCustom Field`
- WHERE fieldname = %s
+ WHERE fieldname = %s
AND dt IN (%s)""" % #nosec
('%s', ', '.join(['%s']* len(doclist))), tuple([doc.fieldname] + doclist))
frappe.db.sql("""
DELETE FROM `tabProperty Setter`
- WHERE field_name = %s
+ WHERE field_name = %s
AND doc_type IN (%s)""" % #nosec
('%s', ', '.join(['%s']* len(doclist))), tuple([doc.fieldname] + doclist))
@@ -150,7 +150,8 @@ def get_doctypes_with_dimensions():
"Purchase Order Item", "Journal Entry Account", "Material Request Item", "Delivery Note Item", "Purchase Receipt Item",
"Stock Entry Detail", "Payment Entry Deduction", "Sales Taxes and Charges", "Purchase Taxes and Charges", "Shipping Rule",
"Landed Cost Item", "Asset Value Adjustment", "Loyalty Program", "Fee Schedule", "Fee Structure", "Stock Reconciliation",
- "Travel Request", "Fees", "POS Profile"]
+ "Travel Request", "Fees", "POS Profile", "Opening Invoice Creation Tool", "Opening Invoice Creation Tool Item", "Subscription",
+ "Subscription Plan"]
return doclist
diff --git a/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.json b/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.json
index 7d2d5a11a8..bc9241802d 100644
--- a/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.json
+++ b/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.json
@@ -10,7 +10,9 @@
"create_missing_party",
"column_break_3",
"invoice_type",
+ "accounting_dimensions_section",
"cost_center",
+ "dimension_col_break",
"section_break_4",
"invoices"
],
@@ -59,11 +61,21 @@
"fieldtype": "Link",
"label": "Cost Center",
"options": "Cost Center"
+ },
+ {
+ "collapsible": 1,
+ "fieldname": "accounting_dimensions_section",
+ "fieldtype": "Section Break",
+ "label": "Accounting Dimensions"
+ },
+ {
+ "fieldname": "dimension_col_break",
+ "fieldtype": "Column Break"
}
],
"hide_toolbar": 1,
"issingle": 1,
- "modified": "2019-06-13 11:45:31.405267",
+ "modified": "2019-07-25 14:57:33.187689",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Opening Invoice Creation Tool",
diff --git a/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py b/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py
index 5fa7b48c09..ce8aba75b2 100644
--- a/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py
+++ b/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py
@@ -7,6 +7,7 @@ import frappe
from frappe import _, scrub
from frappe.utils import flt, nowdate
from frappe.model.document import Document
+from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions
class OpeningInvoiceCreationTool(Document):
@@ -173,6 +174,13 @@ class OpeningInvoiceCreationTool(Document):
"currency": frappe.get_cached_value('Company', self.company, "default_currency")
})
+ accounting_dimension = get_accounting_dimensions()
+
+ for dimension in accounting_dimension:
+ args.update({
+ dimension: item.get(dimension)
+ })
+
if self.invoice_type == "Sales":
args["is_pos"] = 0
diff --git a/erpnext/accounts/doctype/opening_invoice_creation_tool_item/opening_invoice_creation_tool_item.json b/erpnext/accounts/doctype/opening_invoice_creation_tool_item/opening_invoice_creation_tool_item.json
index afa7229e53..4ce8cb95b1 100644
--- a/erpnext/accounts/doctype/opening_invoice_creation_tool_item/opening_invoice_creation_tool_item.json
+++ b/erpnext/accounts/doctype/opening_invoice_creation_tool_item/opening_invoice_creation_tool_item.json
@@ -15,7 +15,9 @@
"outstanding_amount",
"column_break_4",
"qty",
- "cost_center"
+ "accounting_dimensions_section",
+ "cost_center",
+ "dimension_col_break"
],
"fields": [
{
@@ -92,10 +94,19 @@
"fieldtype": "Link",
"label": "Cost Center",
"options": "Cost Center"
+ },
+ {
+ "fieldname": "accounting_dimensions_section",
+ "fieldtype": "Section Break",
+ "label": "Accounting Dimensions"
+ },
+ {
+ "fieldname": "dimension_col_break",
+ "fieldtype": "Column Break"
}
],
"istable": 1,
- "modified": "2019-06-13 11:48:08.324063",
+ "modified": "2019-07-25 15:00:00.460695",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Opening Invoice Creation Tool Item",
diff --git a/erpnext/accounts/doctype/subscription/subscription.json b/erpnext/accounts/doctype/subscription/subscription.json
index c9305164f0..29cb62a397 100644
--- a/erpnext/accounts/doctype/subscription/subscription.json
+++ b/erpnext/accounts/doctype/subscription/subscription.json
@@ -1,926 +1,245 @@
{
- "allow_copy": 0,
- "allow_events_in_timeline": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "autoname": "ACC-SUB-.YYYY.-.#####",
- "beta": 0,
- "creation": "2017-07-18 17:50:43.967266",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "",
- "editable_grid": 1,
- "engine": "InnoDB",
+ "autoname": "ACC-SUB-.YYYY.-.#####",
+ "creation": "2017-07-18 17:50:43.967266",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "customer",
+ "cb_1",
+ "status",
+ "subscription_period",
+ "start",
+ "cancelation_date",
+ "trial_period_start",
+ "trial_period_end",
+ "column_break_11",
+ "current_invoice_start",
+ "current_invoice_end",
+ "days_until_due",
+ "cancel_at_period_end",
+ "generate_invoice_at_period_start",
+ "sb_4",
+ "plans",
+ "sb_1",
+ "tax_template",
+ "sb_2",
+ "apply_additional_discount",
+ "cb_2",
+ "additional_discount_percentage",
+ "additional_discount_amount",
+ "sb_3",
+ "invoices",
+ "accounting_dimensions_section",
+ "dimension_col_break"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "customer",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Customer",
- "length": 0,
- "no_copy": 0,
- "options": "Customer",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 1,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "customer",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Customer",
+ "options": "Customer",
+ "reqd": 1,
+ "set_only_once": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "cb_1",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "allow_on_submit": 1,
+ "fieldname": "cb_1",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "status",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Status",
- "length": 0,
- "no_copy": 0,
- "options": "\nTrialling\nActive\nPast Due Date\nCancelled\nUnpaid",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "status",
+ "fieldtype": "Select",
+ "label": "Status",
+ "options": "\nTrialling\nActive\nPast Due Date\nCancelled\nUnpaid",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "subscription_period",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Subscription Period",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "subscription_period",
+ "fieldtype": "Section Break",
+ "label": "Subscription Period"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "start",
- "fieldtype": "Date",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Subscription Start Date",
- "length": 0,
- "no_copy": 0,
- "options": "",
- "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": 1,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "start",
+ "fieldtype": "Date",
+ "label": "Subscription Start Date",
+ "set_only_once": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "cancelation_date",
- "fieldtype": "Date",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Cancelation Date",
- "length": 0,
- "no_copy": 0,
- "options": "",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "cancelation_date",
+ "fieldtype": "Date",
+ "label": "Cancelation Date",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "trial_period_start",
- "fieldtype": "Date",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Trial Period Start Date",
- "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": 1,
- "translatable": 0,
- "unique": 0
- },
+ "allow_on_submit": 1,
+ "fieldname": "trial_period_start",
+ "fieldtype": "Date",
+ "label": "Trial Period Start Date",
+ "set_only_once": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:doc.trial_period_start",
- "fieldname": "trial_period_end",
- "fieldtype": "Date",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Trial Period End Date",
- "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": 1,
- "translatable": 0,
- "unique": 0
- },
+ "depends_on": "eval:doc.trial_period_start",
+ "fieldname": "trial_period_end",
+ "fieldtype": "Date",
+ "label": "Trial Period End Date",
+ "set_only_once": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_11",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "column_break_11",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "current_invoice_start",
- "fieldtype": "Date",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Current Invoice Start Date",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "current_invoice_start",
+ "fieldtype": "Date",
+ "label": "Current Invoice Start Date",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "current_invoice_end",
- "fieldtype": "Date",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Current Invoice End Date",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "current_invoice_end",
+ "fieldtype": "Date",
+ "label": "Current Invoice End Date",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "0",
- "description": "Number of days that the subscriber has to pay invoices generated by this subscription",
- "fieldname": "days_until_due",
- "fieldtype": "Int",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Days Until Due",
- "length": 0,
- "no_copy": 0,
- "options": "",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "default": "0",
+ "description": "Number of days that the subscriber has to pay invoices generated by this subscription",
+ "fieldname": "days_until_due",
+ "fieldtype": "Int",
+ "label": "Days Until Due"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "cancel_at_period_end",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Cancel At End Of Period",
- "length": 0,
- "no_copy": 0,
- "options": "",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "default": "0",
+ "fieldname": "cancel_at_period_end",
+ "fieldtype": "Check",
+ "label": "Cancel At End Of Period"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "generate_invoice_at_period_start",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Generate Invoice At Beginning Of Period",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "default": "0",
+ "fieldname": "generate_invoice_at_period_start",
+ "fieldtype": "Check",
+ "label": "Generate Invoice At Beginning Of Period"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
- "fieldname": "sb_4",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Plans",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "allow_on_submit": 1,
+ "fieldname": "sb_4",
+ "fieldtype": "Section Break",
+ "label": "Plans"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "plans",
- "fieldtype": "Table",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Plans",
- "length": 0,
- "no_copy": 0,
- "options": "Subscription Plan Detail",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "allow_on_submit": 1,
+ "fieldname": "plans",
+ "fieldtype": "Table",
+ "label": "Plans",
+ "options": "Subscription Plan Detail",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "sb_1",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Taxes",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "sb_1",
+ "fieldtype": "Section Break",
+ "label": "Taxes"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "tax_template",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Sales Taxes and Charges Template",
- "length": 0,
- "no_copy": 0,
- "options": "Sales Taxes and Charges Template",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "tax_template",
+ "fieldtype": "Link",
+ "label": "Sales Taxes and Charges Template",
+ "options": "Sales Taxes and Charges Template"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
- "description": "",
- "fieldname": "sb_2",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Discounts",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "sb_2",
+ "fieldtype": "Section Break",
+ "label": "Discounts"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "apply_additional_discount",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Apply Additional Discount On",
- "length": 0,
- "no_copy": 0,
- "options": "\nGrand Total\nNet total",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "apply_additional_discount",
+ "fieldtype": "Select",
+ "label": "Apply Additional Discount On",
+ "options": "\nGrand Total\nNet total"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
- "fieldname": "cb_2",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "cb_2",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
- "fieldname": "additional_discount_percentage",
- "fieldtype": "Percent",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Additional DIscount Percentage",
- "length": 0,
- "no_copy": 0,
- "options": "",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "additional_discount_percentage",
+ "fieldtype": "Percent",
+ "label": "Additional DIscount Percentage"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "columns": 0,
- "depends_on": "",
- "fieldname": "additional_discount_amount",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Additional DIscount Amount",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "collapsible": 1,
+ "fieldname": "additional_discount_amount",
+ "fieldtype": "Currency",
+ "label": "Additional DIscount Amount"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "",
- "depends_on": "eval:doc.invoices",
- "fieldname": "sb_3",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Invoices",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "depends_on": "eval:doc.invoices",
+ "fieldname": "sb_3",
+ "fieldtype": "Section Break",
+ "label": "Invoices"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "columns": 0,
- "depends_on": "",
- "fieldname": "invoices",
- "fieldtype": "Table",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Invoices",
- "length": 0,
- "no_copy": 0,
- "options": "Subscription Invoice",
- "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,
- "translatable": 0,
- "unique": 0
+ "collapsible": 1,
+ "fieldname": "invoices",
+ "fieldtype": "Table",
+ "label": "Invoices",
+ "options": "Subscription Invoice"
+ },
+ {
+ "collapsible": 1,
+ "fieldname": "accounting_dimensions_section",
+ "fieldtype": "Section Break",
+ "label": "Accounting Dimensions"
+ },
+ {
+ "fieldname": "dimension_col_break",
+ "fieldtype": "Column Break"
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2018-10-14 10:38:55.545540",
- "modified_by": "Administrator",
- "module": "Accounts",
- "name": "Subscription",
- "name_case": "",
- "owner": "Administrator",
+ ],
+ "modified": "2019-07-25 18:45:38.579579",
+ "modified_by": "Administrator",
+ "module": "Accounts",
+ "name": "Subscription",
+ "owner": "Administrator",
"permissions": [
{
- "amend": 0,
- "cancel": 0,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "System Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "System Manager",
+ "share": 1,
"write": 1
- },
+ },
{
- "amend": 0,
- "cancel": 0,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Accounts User",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Accounts User",
+ "share": 1,
"write": 1
- },
+ },
{
- "amend": 0,
- "cancel": 0,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Accounts Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Accounts Manager",
+ "share": 1,
"write": 1
}
- ],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "search_fields": "",
- "show_name_in_global_search": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "title_field": "",
- "track_changes": 1,
- "track_seen": 0,
- "track_views": 0
-}
+ ],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/subscription/subscription.py b/erpnext/accounts/doctype/subscription/subscription.py
index 858359eccb..6d01897e8f 100644
--- a/erpnext/accounts/doctype/subscription/subscription.py
+++ b/erpnext/accounts/doctype/subscription/subscription.py
@@ -9,6 +9,7 @@ from frappe import _
from frappe.model.document import Document
from frappe.utils.data import nowdate, getdate, cint, add_days, date_diff, get_last_day, add_to_date, flt
from erpnext.accounts.doctype.subscription_plan.subscription_plan import get_plan_rate
+from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions
class Subscription(Document):
@@ -241,6 +242,15 @@ class Subscription(Document):
invoice.posting_date = self.current_invoice_start
invoice.customer = self.customer
+ ## Add dimesnions in invoice for subscription:
+ accounting_dimensions = get_accounting_dimensions()
+
+ for dimension in accounting_dimensions:
+ if self.get(dimension):
+ invoice.update({
+ dimension: self.get(dimension)
+ })
+
# Subscription is better suited for service items. I won't update `update_stock`
# for that reason
items_list = self.get_items_from_plans(self.plans, prorate)
@@ -280,6 +290,9 @@ class Subscription(Document):
invoice.save()
invoice.submit()
+ for dimension in accounting_dimensions:
+ invoice.load_from_db()
+
return invoice
def get_items_from_plans(self, plans, prorate=0):
diff --git a/erpnext/accounts/doctype/subscription_plan/subscription_plan.json b/erpnext/accounts/doctype/subscription_plan/subscription_plan.json
index 453521d04d..9f79066235 100644
--- a/erpnext/accounts/doctype/subscription_plan/subscription_plan.json
+++ b/erpnext/accounts/doctype/subscription_plan/subscription_plan.json
@@ -1,612 +1,163 @@
{
- "allow_copy": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 1,
- "autoname": "field:plan_name",
- "beta": 0,
- "creation": "2018-02-24 11:31:23.066506",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "",
- "editable_grid": 1,
- "engine": "InnoDB",
+ "allow_rename": 1,
+ "autoname": "field:plan_name",
+ "creation": "2018-02-24 11:31:23.066506",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "plan_name",
+ "currency",
+ "column_break_3",
+ "item",
+ "section_break_5",
+ "price_determination",
+ "column_break_7",
+ "cost",
+ "price_list",
+ "section_break_11",
+ "billing_interval",
+ "column_break_13",
+ "billing_interval_count",
+ "payment_plan_section",
+ "payment_plan_id",
+ "column_break_16",
+ "payment_gateway",
+ "accounting_dimensions_section",
+ "dimension_col_break"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "plan_name",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Plan Name",
- "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": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
+ "fieldname": "plan_name",
+ "fieldtype": "Data",
+ "in_list_view": 1,
+ "label": "Plan Name",
+ "reqd": 1,
"unique": 1
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "currency",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Currency",
- "length": 0,
- "no_copy": 0,
- "options": "Currency",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "currency",
+ "fieldtype": "Link",
+ "label": "Currency",
+ "options": "Currency"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_3",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "column_break_3",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "item",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Item",
- "length": 0,
- "no_copy": 0,
- "options": "Item",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "item",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Item",
+ "options": "Item",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "section_break_5",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "section_break_5",
+ "fieldtype": "Section Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "",
- "fieldname": "price_determination",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Price Determination",
- "length": 0,
- "no_copy": 0,
- "options": "\nFixed rate\nBased on price list",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "price_determination",
+ "fieldtype": "Select",
+ "label": "Price Determination",
+ "options": "\nFixed rate\nBased on price list",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_7",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "column_break_7",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:doc.price_determination==\"Fixed rate\"",
- "fieldname": "cost",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Cost",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "depends_on": "eval:doc.price_determination==\"Fixed rate\"",
+ "fieldname": "cost",
+ "fieldtype": "Currency",
+ "in_list_view": 1,
+ "label": "Cost"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:doc.price_determination==\"Based on price list\"",
- "fieldname": "price_list",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Price List",
- "length": 0,
- "no_copy": 0,
- "options": "Price List",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "depends_on": "eval:doc.price_determination==\"Based on price list\"",
+ "fieldname": "price_list",
+ "fieldtype": "Link",
+ "label": "Price List",
+ "options": "Price List"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "section_break_11",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "section_break_11",
+ "fieldtype": "Section Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "Day",
- "fieldname": "billing_interval",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Billing Interval",
- "length": 0,
- "no_copy": 0,
- "options": "Day\nWeek\nMonth\nYear",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "default": "Day",
+ "fieldname": "billing_interval",
+ "fieldtype": "Select",
+ "in_list_view": 1,
+ "label": "Billing Interval",
+ "options": "Day\nWeek\nMonth\nYear",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_13",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "column_break_13",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "1",
- "description": "Number of intervals for the interval field e.g if Interval is 'Days' and Billing Interval Count is 3, invoices will be generated every 3 days",
- "fieldname": "billing_interval_count",
- "fieldtype": "Int",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Billing Interval Count",
- "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": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "default": "1",
+ "description": "Number of intervals for the interval field e.g if Interval is 'Days' and Billing Interval Count is 3, invoices will be generated every 3 days",
+ "fieldname": "billing_interval_count",
+ "fieldtype": "Int",
+ "label": "Billing Interval Count",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "payment_plan_section",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Payment Plan",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "payment_plan_section",
+ "fieldtype": "Section Break",
+ "label": "Payment Plan"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "payment_plan_id",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Payment Plan",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "payment_plan_id",
+ "fieldtype": "Data",
+ "label": "Payment Plan"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_16",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "column_break_16",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "payment_gateway",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Payment Gateway",
- "length": 0,
- "no_copy": 0,
- "options": "Payment Gateway Account",
- "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,
- "translatable": 0,
- "unique": 0
+ "fieldname": "payment_gateway",
+ "fieldtype": "Link",
+ "label": "Payment Gateway",
+ "options": "Payment Gateway Account"
+ },
+ {
+ "collapsible": 1,
+ "fieldname": "accounting_dimensions_section",
+ "fieldtype": "Section Break",
+ "label": "Accounting Dimensions"
+ },
+ {
+ "fieldname": "dimension_col_break",
+ "fieldtype": "Column Break"
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2018-06-20 16:59:54.082358",
- "modified_by": "Administrator",
- "module": "Accounts",
- "name": "Subscription Plan",
- "name_case": "",
- "owner": "Administrator",
+ ],
+ "modified": "2019-07-25 18:35:04.362556",
+ "modified_by": "Administrator",
+ "module": "Accounts",
+ "name": "Subscription Plan",
+ "owner": "Administrator",
"permissions": [
{
- "amend": 0,
- "cancel": 0,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "System Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "System Manager",
+ "share": 1,
"write": 1
}
- ],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1,
- "track_seen": 0
+ ],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
}
\ No newline at end of file
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 398c6020a0..33d4f55ae0 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -624,4 +624,5 @@ erpnext.patches.v11_1.update_default_supplier_in_item_defaults
erpnext.patches.v12_0.update_due_date_in_gle
erpnext.patches.v12_0.add_default_buying_selling_terms_in_company
erpnext.patches.v12_0.update_ewaybill_field_position
+erpnext.patches.v12_0.create_accounting_dimensions_in_missing_doctypes
erpnext.patches.v11_1.set_status_for_material_request_type_manufacture
diff --git a/erpnext/patches/v12_0/create_accounting_dimensions_in_missing_doctypes.py b/erpnext/patches/v12_0/create_accounting_dimensions_in_missing_doctypes.py
new file mode 100644
index 0000000000..1796c53c14
--- /dev/null
+++ b/erpnext/patches/v12_0/create_accounting_dimensions_in_missing_doctypes.py
@@ -0,0 +1,38 @@
+from __future__ import unicode_literals
+import frappe
+from frappe.custom.doctype.custom_field.custom_field import create_custom_field
+
+def execute():
+ accounting_dimensions = frappe.db.sql("""select fieldname, label, document_type, disabled from
+ `tabAccounting Dimension`""", as_dict=1)
+
+ if not accounting_dimensions:
+ return
+
+ count = 1
+ for d in accounting_dimensions:
+
+ if count%2 == 0:
+ insert_after_field = 'dimension_col_break'
+ else:
+ insert_after_field = 'accounting_dimensions_section'
+
+ for doctype in ["Subscription Plan", "Subscription", "Opening Invoice Creation Tool", "Opening Invoice Creation Tool Item"]:
+
+ field = frappe.db.get_value("Custom Field", {"dt": doctype, "fieldname": d.fieldname})
+
+ if field:
+ continue
+
+ df = {
+ "fieldname": d.fieldname,
+ "label": d.label,
+ "fieldtype": "Link",
+ "options": d.document_type,
+ "insert_after": insert_after_field
+ }
+
+ create_custom_field(doctype, df)
+ frappe.clear_cache(doctype=doctype)
+
+ count += 1
\ No newline at end of file
diff --git a/erpnext/public/js/utils/dimension_tree_filter.js b/erpnext/public/js/utils/dimension_tree_filter.js
index 9d4c435240..10855ea3e6 100644
--- a/erpnext/public/js/utils/dimension_tree_filter.js
+++ b/erpnext/public/js/utils/dimension_tree_filter.js
@@ -5,7 +5,7 @@ erpnext.doctypes_with_dimensions = ["GL Entry", "Sales Invoice", "Purchase Invoi
"Purchase Order Item", "Journal Entry Account", "Material Request Item", "Delivery Note Item", "Purchase Receipt Item",
"Stock Entry Detail", "Payment Entry Deduction", "Sales Taxes and Charges", "Purchase Taxes and Charges", "Shipping Rule",
"Landed Cost Item", "Asset Value Adjustment", "Loyalty Program", "Fee Schedule", "Fee Structure", "Stock Reconciliation",
- "Travel Request", "Fees", "POS Profile"];
+ "Travel Request", "Fees", "POS Profile", "Opening Invoice Creation Tool", "Opening Invoice Creation Tool Item"];
frappe.call({
method: "erpnext.accounts.doctype.accounting_dimension.accounting_dimension.get_dimension_filters",
@@ -25,6 +25,9 @@ erpnext.doctypes_with_dimensions.forEach((doctype) => {
"is_group": 0
});
}
+ if (frm.is_new() && frappe.meta.has_field(doctype, 'company') && frm.doc.company) {
+ frm.set_value(dimension['fieldname'], erpnext.default_dimensions[frm.doc.company][dimension['document_type']]);
+ }
});
});
},
From 724be6eca27f167f872f19d777934d84503fb2ee Mon Sep 17 00:00:00 2001
From: deepeshgarg007
Date: Sat, 27 Jul 2019 19:06:36 +0530
Subject: [PATCH 153/484] fix: GL entry validation fix
---
.../doctype/accounting_dimension/accounting_dimension.py | 5 +++--
.../accounting_dimension/test_accounting_dimension.py | 1 -
erpnext/accounts/doctype/gl_entry/gl_entry.py | 8 ++++----
3 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py
index 61f699f6ab..1f418de47b 100644
--- a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py
+++ b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py
@@ -164,8 +164,9 @@ def get_accounting_dimensions(as_list=True):
return accounting_dimensions
def get_checks_for_pl_and_bs_accounts():
- dimensions = frappe.db.sql("""SELECT parent, company, mandatory_for_pl, mandatory_for_bs
- FROM `tabAccounting Dimension Detail`""", as_dict=1)
+ dimensions = frappe.db.sql("""SELECT p.label, p.disabled, p.fieldname, c.company, c.mandatory_for_pl, c.mandatory_for_bs
+ FROM `tabAccounting Dimension`p ,`tabAccounting Dimension Detail` c
+ WHERE p.name = c.parent""", as_dict=1)
return dimensions
diff --git a/erpnext/accounts/doctype/accounting_dimension/test_accounting_dimension.py b/erpnext/accounts/doctype/accounting_dimension/test_accounting_dimension.py
index c75ba825a4..104880f6f3 100644
--- a/erpnext/accounts/doctype/accounting_dimension/test_accounting_dimension.py
+++ b/erpnext/accounts/doctype/accounting_dimension/test_accounting_dimension.py
@@ -108,7 +108,6 @@ def disable_dimension():
dimension1.save()
dimension2 = frappe.get_doc("Accounting Dimension", "Location")
- dimension2.mandatory_for_pl = 0
dimension2.disabled = 1
dimension2.save()
diff --git a/erpnext/accounts/doctype/gl_entry/gl_entry.py b/erpnext/accounts/doctype/gl_entry/gl_entry.py
index 80e518644d..4944c8f76f 100644
--- a/erpnext/accounts/doctype/gl_entry/gl_entry.py
+++ b/erpnext/accounts/doctype/gl_entry/gl_entry.py
@@ -90,15 +90,15 @@ class GLEntry(Document):
if account_type == "Profit and Loss" \
and self.company == dimension.company and dimension.mandatory_for_pl and not dimension.disabled:
- if not self.get(frappe.scrub(dimension.parent)):
+ if not self.get(frappe.scrub(dimension.fieldname)):
frappe.throw(_("Accounting Dimension {0} is required for 'Profit and Loss' account {1}.")
- .format(dimension.parent, self.account))
+ .format(dimension.label, self.account))
if account_type == "Balance Sheet" \
and self.company == dimension.company and dimension.mandatory_for_bs and not dimension.disabled:
- if not self.get(frappe.scrub(dimension.parent)):
+ if not self.get(frappe.scrub(dimension.fieldname)):
frappe.throw(_("Accounting Dimension {0} is required for 'Balance Sheet' account {1}.")
- .format(dimension.parent, self.account))
+ .format(dimension.label, self.account))
def check_pl_account(self):
From d9f3ba5fdacbac81391b4051152bace359523d83 Mon Sep 17 00:00:00 2001
From: deepeshgarg007
Date: Sun, 28 Jul 2019 10:30:32 +0530
Subject: [PATCH 154/484] fix: Reload doc in patch
---
.../v12_0/create_accounting_dimensions_in_missing_doctypes.py | 3 +++
1 file changed, 3 insertions(+)
diff --git a/erpnext/patches/v12_0/create_accounting_dimensions_in_missing_doctypes.py b/erpnext/patches/v12_0/create_accounting_dimensions_in_missing_doctypes.py
index 1796c53c14..b71ea66594 100644
--- a/erpnext/patches/v12_0/create_accounting_dimensions_in_missing_doctypes.py
+++ b/erpnext/patches/v12_0/create_accounting_dimensions_in_missing_doctypes.py
@@ -3,6 +3,9 @@ import frappe
from frappe.custom.doctype.custom_field.custom_field import create_custom_field
def execute():
+
+ frappe.reload_doc('accounts', 'doctype', 'accounting_dimension')
+
accounting_dimensions = frappe.db.sql("""select fieldname, label, document_type, disabled from
`tabAccounting Dimension`""", as_dict=1)
From f37fb82069b7bb244b62acd2da55f0bf605c2212 Mon Sep 17 00:00:00 2001
From: deepeshgarg007
Date: Mon, 29 Jul 2019 08:58:56 +0530
Subject: [PATCH 155/484] fix: Code cleanup
---
erpnext/accounts/doctype/gl_entry/gl_entry.py | 4 ++--
erpnext/accounts/doctype/subscription/subscription.py | 3 ---
erpnext/public/js/utils/dimension_tree_filter.js | 3 ++-
3 files changed, 4 insertions(+), 6 deletions(-)
diff --git a/erpnext/accounts/doctype/gl_entry/gl_entry.py b/erpnext/accounts/doctype/gl_entry/gl_entry.py
index 4944c8f76f..078e05816d 100644
--- a/erpnext/accounts/doctype/gl_entry/gl_entry.py
+++ b/erpnext/accounts/doctype/gl_entry/gl_entry.py
@@ -90,13 +90,13 @@ class GLEntry(Document):
if account_type == "Profit and Loss" \
and self.company == dimension.company and dimension.mandatory_for_pl and not dimension.disabled:
- if not self.get(frappe.scrub(dimension.fieldname)):
+ if not self.get(dimension.fieldname):
frappe.throw(_("Accounting Dimension {0} is required for 'Profit and Loss' account {1}.")
.format(dimension.label, self.account))
if account_type == "Balance Sheet" \
and self.company == dimension.company and dimension.mandatory_for_bs and not dimension.disabled:
- if not self.get(frappe.scrub(dimension.fieldname)):
+ if not self.get(dimension.fieldname):
frappe.throw(_("Accounting Dimension {0} is required for 'Balance Sheet' account {1}.")
.format(dimension.label, self.account))
diff --git a/erpnext/accounts/doctype/subscription/subscription.py b/erpnext/accounts/doctype/subscription/subscription.py
index 6d01897e8f..f13ca4c49e 100644
--- a/erpnext/accounts/doctype/subscription/subscription.py
+++ b/erpnext/accounts/doctype/subscription/subscription.py
@@ -290,9 +290,6 @@ class Subscription(Document):
invoice.save()
invoice.submit()
- for dimension in accounting_dimensions:
- invoice.load_from_db()
-
return invoice
def get_items_from_plans(self, plans, prorate=0):
diff --git a/erpnext/public/js/utils/dimension_tree_filter.js b/erpnext/public/js/utils/dimension_tree_filter.js
index 10855ea3e6..f1c92091a8 100644
--- a/erpnext/public/js/utils/dimension_tree_filter.js
+++ b/erpnext/public/js/utils/dimension_tree_filter.js
@@ -5,7 +5,8 @@ erpnext.doctypes_with_dimensions = ["GL Entry", "Sales Invoice", "Purchase Invoi
"Purchase Order Item", "Journal Entry Account", "Material Request Item", "Delivery Note Item", "Purchase Receipt Item",
"Stock Entry Detail", "Payment Entry Deduction", "Sales Taxes and Charges", "Purchase Taxes and Charges", "Shipping Rule",
"Landed Cost Item", "Asset Value Adjustment", "Loyalty Program", "Fee Schedule", "Fee Structure", "Stock Reconciliation",
- "Travel Request", "Fees", "POS Profile", "Opening Invoice Creation Tool", "Opening Invoice Creation Tool Item"];
+ "Travel Request", "Fees", "POS Profile", "Opening Invoice Creation Tool", "Opening Invoice Creation Tool Item", "Subscription",
+ "Subscription Plan"];
frappe.call({
method: "erpnext.accounts.doctype.accounting_dimension.accounting_dimension.get_dimension_filters",
From 107c07e5cbb63aabf5f715f3fe00cd3e8e7721d5 Mon Sep 17 00:00:00 2001
From: deepeshgarg007
Date: Mon, 29 Jul 2019 14:57:33 +0530
Subject: [PATCH 156/484] fix: Opening balance not getting calculated in
trail_balance_report
---
erpnext/accounts/report/trial_balance/trial_balance.py | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/erpnext/accounts/report/trial_balance/trial_balance.py b/erpnext/accounts/report/trial_balance/trial_balance.py
index b6ddaa8e85..10e977acbf 100644
--- a/erpnext/accounts/report/trial_balance/trial_balance.py
+++ b/erpnext/accounts/report/trial_balance/trial_balance.py
@@ -123,11 +123,12 @@ def get_rootwise_opening_balances(filters, report_type):
if accounting_dimensions:
for dimension in accounting_dimensions:
- additional_conditions += """ and {0} in (%({0})s) """.format(dimension)
+ if filters.get(dimension):
+ additional_conditions += """ and {0} in (%({0})s) """.format(dimension)
- query_filters.update({
- dimension: filters.get(dimension)
- })
+ query_filters.update({
+ dimension: filters.get(dimension)
+ })
gle = frappe.db.sql("""
select
From 9ad10cb425732be855ac390480de4327e2e32182 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Mon, 29 Jul 2019 16:52:26 +0530
Subject: [PATCH 157/484] test: Add basic tests
---
.../doctype/pick_ticket/test_pick_ticket.py | 105 ++++++++++++++++--
1 file changed, 96 insertions(+), 9 deletions(-)
diff --git a/erpnext/stock/doctype/pick_ticket/test_pick_ticket.py b/erpnext/stock/doctype/pick_ticket/test_pick_ticket.py
index 3fee6db667..3a0492a2dc 100644
--- a/erpnext/stock/doctype/pick_ticket/test_pick_ticket.py
+++ b/erpnext/stock/doctype/pick_ticket/test_pick_ticket.py
@@ -3,21 +3,108 @@
# See license.txt
from __future__ import unicode_literals
-# import frappe
+import frappe
import unittest
+# test_dependencies = ['Item', 'Sales Invoice', 'Stock Entry', 'Batch']
+
+from erpnext.selling.doctype.sales_order.sales_order import make_pick_ticket
class TestPickTicket(unittest.TestCase):
- def test_pick_list_picks_warehouse_for_each_item():
+ def test_pick_ticket_picks_warehouse_for_each_item(self):
+ pick_ticket = frappe.get_doc({
+ 'doctype': 'Pick Ticket',
+ 'company': '_Test Company',
+ 'reference_document_items': [{
+ 'item': '_Test Item Home Desktop 100',
+ 'reference_doctype': 'Sales Order',
+ 'qty': 5,
+ 'reference_name': '_T-Sales Order-1',
+ }],
+ })
+
+ pick_ticket.set_item_locations()
+
+ self.assertEqual(pick_ticket.items[0].item, '_Test Item Home Desktop 100')
+ self.assertEqual(pick_ticket.items[0].warehouse, '_Test Warehouse - _TC')
+ self.assertEqual(pick_ticket.items[0].qty, 5)
+
+ def test_pick_ticket_skips_out_of_stock_item(self):
+ pick_ticket = frappe.get_doc({
+ 'doctype': 'Pick Ticket',
+ 'company': '_Test Company',
+ 'reference_document_items': [{
+ 'item': '_Test Item Warehouse Group Wise Reorder',
+ 'reference_doctype': 'Sales Order',
+ 'qty': 1000,
+ 'reference_name': '_T-Sales Order-1',
+ }],
+ })
+
+ pick_ticket.set_item_locations()
+
+ self.assertEqual(pick_ticket.items[0].item, '_Test Item Warehouse Group Wise Reorder')
+ self.assertEqual(pick_ticket.items[0].warehouse, '_Test Warehouse Group-C1 - _TC')
+ self.assertEqual(pick_ticket.items[0].qty, 30)
+
+
+ def test_pick_ticket_skips_items_in_expired_batch(self):
pass
- def test_pick_list_skips_out_of_warranty_item():
+ def test_pick_ticket_shows_serial_no_for_serialized_item(self):
+
+ stock_reconciliation = frappe.get_doc({
+ 'doctype': 'Stock Reconciliation',
+ 'company': '_Test Company',
+ 'items': [{
+ 'item_code': '_Test Serialized Item',
+ 'warehouse': '_Test Warehouse - _TC',
+ 'qty': 5,
+ 'serial_no': '123450\n123451\n123452\n123453\n123454'
+ }]
+ })
+
+ stock_reconciliation.submit()
+
+ pick_ticket = frappe.get_doc({
+ 'doctype': 'Pick Ticket',
+ 'company': '_Test Company',
+ 'reference_document_items': [{
+ 'item': '_Test Serialized Item',
+ 'reference_doctype': 'Sales Order',
+ 'qty': 1000,
+ 'reference_name': '_T-Sales Order-1',
+ }],
+ })
+
+ pick_ticket.set_item_locations()
+ self.assertEqual(pick_ticket.items[0].item, '_Test Serialized Item')
+ self.assertEqual(pick_ticket.items[0].warehouse, '_Test Warehouse Group-C1 - _TC')
+ self.assertEqual(pick_ticket.items[0].qty, 30)
+ self.assertEqual(pick_ticket.items[0].serial_no, 30)
+
+
+ def test_pick_ticket_for_multiple_reference_doctypes(self):
pass
- def test_pick_list_skips_items_in_expired_batch():
- pass
- def test_pick_list_shows_serial_no_for_serialized_item():
- pass
+# def create_new_pick_ticket():
+# pass
+# doc = frappe.new_doc('Pick Ticket')
+# doc.items.append({
+# 'item': '_Test Warehouse - _TC',
+# ''
+# })
- def test_pick_list_for_multiple_reference_doctypes():
- pass
+
+
+## records required
+
+'''
+batch no
+items
+sales invoice
+stock entries
+ bin
+ stock ledger entry
+warehouses
+'''
\ No newline at end of file
From 40e35048b87234eb82409da09f164db30ec9bbd2 Mon Sep 17 00:00:00 2001
From: Rohit Waghchaure
Date: Mon, 29 Jul 2019 17:14:39 +0530
Subject: [PATCH 158/484] fix: can't compare datetime.date to unicode
---
erpnext/selling/doctype/quotation/quotation.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/selling/doctype/quotation/quotation.py b/erpnext/selling/doctype/quotation/quotation.py
index cc73e76bf3..46009f45e4 100644
--- a/erpnext/selling/doctype/quotation/quotation.py
+++ b/erpnext/selling/doctype/quotation/quotation.py
@@ -34,7 +34,7 @@ class Quotation(SellingController):
self.with_items = 1
def validate_valid_till(self):
- if self.valid_till and self.valid_till < self.transaction_date:
+ if self.valid_till and getdate(self.valid_till) < getdate(self.transaction_date):
frappe.throw(_("Valid till date cannot be before transaction date"))
def has_sales_order(self):
From 55ab31314c6ef69a65e74e43e08977af5239aab9 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Tue, 30 Jul 2019 09:02:03 +0530
Subject: [PATCH 159/484] fix: Add code to set batch no - And split item based
on batch availibility
---
.../stock/doctype/pick_ticket/pick_ticket.py | 80 ++++++++++++++-----
1 file changed, 58 insertions(+), 22 deletions(-)
diff --git a/erpnext/stock/doctype/pick_ticket/pick_ticket.py b/erpnext/stock/doctype/pick_ticket/pick_ticket.py
index 18382e6781..93eb7134a1 100644
--- a/erpnext/stock/doctype/pick_ticket/pick_ticket.py
+++ b/erpnext/stock/doctype/pick_ticket/pick_ticket.py
@@ -14,13 +14,13 @@ class PickTicket(Document):
data = get_items_with_warehouse_and_quantity(item)
for item_info in data:
- self.append('items', item_info)
+ print(self.append('items', item_info))
- for item in self.get('items'):
- if frappe.get_cached_value('Item', item.item, 'has_serial_no'):
- set_serial_nos(item)
- elif frappe.get_cached_value('Item', item.item, 'has_batch_no'):
- set_batch_no(item, self)
+ for item_doc in self.get('items'):
+ if frappe.get_cached_value('Item', item_doc.item, 'has_serial_no'):
+ set_serial_nos(item_doc)
+ elif frappe.get_cached_value('Item', item_doc.item, 'has_batch_no'):
+ set_batch_no(item_doc, self)
def get_available_items(item):
# gets all items available in different warehouses
@@ -56,22 +56,58 @@ def get_items_with_warehouse_and_quantity(item_doc):
return items
-def set_serial_nos(item):
+def set_serial_nos(item_doc):
serial_nos = frappe.get_all('Serial No', {
- 'item_code': item.item,
- 'warehouse': item.warehouse
- }, limit=item.qty, order_by='purchase_date')
- item.set('serial_no', '\n'.join([serial_no.name for serial_no in serial_nos]))
+ 'item_code': item_doc.item,
+ 'warehouse': item_doc.warehouse
+ }, limit=item_doc.qty, order_by='purchase_date')
+ item_doc.set('serial_no', '\n'.join([serial_no.name for serial_no in serial_nos]))
-def set_batch_no(item, doc):
- batches = frappe.get_all('Stock Ledger Entry',
- fields=['batch_no', 'sum(actual_qty) as qty'],
- filters={
- 'item_code': item.item,
- 'warehouse': item.warehouse
- },
- group_by='warehouse, batch_no, item_code')
+def set_batch_no(item_doc, parent_doc):
+ batches = frappe.db.sql("""
+ SELECT
+ `batch_no`,
+ SUM(`actual_qty`) AS `qty`
+ FROM
+ `tabStock Ledger Entry`
+ WHERE
+ `item_code`=%(item_code)s
+ AND `warehouse`=%(warehouse)s
+ GROUP BY
+ `warehouse`,
+ `batch_no`,
+ `item_code`
+ HAVING `qty` > 0
+ """, {
+ 'item_code': item_doc.item,
+ 'warehouse': item_doc.warehouse,
+ }, as_dict=1)
+ print(batches)
- if batches:
- # TODO: check expiry and split item if batch is more than 1
- item.batch_no = batches[0].batch_no
\ No newline at end of file
+ required_qty = item_doc.qty
+ while required_qty > 0 and batches:
+ batch = batches.pop()
+ batch_expiry = frappe.get_value('Batch', batch.batch_no, 'expiry_date')
+ if batch_expiry and batch_expiry < frappe.utils.getdate():
+ print('---------- Batch {} is expired. Skipping... -------------'.format(batch.batch_no))
+ continue
+ item_doc.batch_no = batch.batch_no
+ required_qty -= batch.qty
+ if batch.qty >= item_doc.qty:
+ break
+ else:
+ # split item if quantity of item in batch is less that required
+ # Look for another batch
+
+ # set quantity of of item equal to batch quantity
+ item_doc.set('qty', batch.qty)
+ item_doc = parent_doc.append('items', {
+ 'item': item_doc.item,
+ 'qty': required_qty,
+ 'warehouse': item_doc.warehouse,
+ 'reference_doctype': item_doc.reference_doctype,
+ 'reference_name': item_doc.reference_name
+ })
+ if required_qty:
+ print('---------- No batches found for {} qty of {}. Skipping... -------------'.format(required_qty, item_doc.item))
+ parent_doc.remove(item_doc)
From e260e8239fd183c14d6403ff28e14e287ce94606 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Tue, 30 Jul 2019 10:02:10 +0530
Subject: [PATCH 160/484] fix: Batch number selection code
---
erpnext/stock/doctype/pick_ticket/pick_ticket.py | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/erpnext/stock/doctype/pick_ticket/pick_ticket.py b/erpnext/stock/doctype/pick_ticket/pick_ticket.py
index 93eb7134a1..ce0e5526b6 100644
--- a/erpnext/stock/doctype/pick_ticket/pick_ticket.py
+++ b/erpnext/stock/doctype/pick_ticket/pick_ticket.py
@@ -63,6 +63,8 @@ def set_serial_nos(item_doc):
}, limit=item_doc.qty, order_by='purchase_date')
item_doc.set('serial_no', '\n'.join([serial_no.name for serial_no in serial_nos]))
+ # should we assume that all serialized item available in stock will have serial no?
+
def set_batch_no(item_doc, parent_doc):
batches = frappe.db.sql("""
SELECT
@@ -88,18 +90,19 @@ def set_batch_no(item_doc, parent_doc):
while required_qty > 0 and batches:
batch = batches.pop()
batch_expiry = frappe.get_value('Batch', batch.batch_no, 'expiry_date')
- if batch_expiry and batch_expiry < frappe.utils.getdate():
+ if batch_expiry and batch_expiry <= frappe.utils.getdate():
print('---------- Batch {} is expired. Skipping... -------------'.format(batch.batch_no))
continue
item_doc.batch_no = batch.batch_no
- required_qty -= batch.qty
if batch.qty >= item_doc.qty:
+ required_qty = 0
break
else:
# split item if quantity of item in batch is less that required
# Look for another batch
# set quantity of of item equal to batch quantity
+ required_qty -= batch.qty
item_doc.set('qty', batch.qty)
item_doc = parent_doc.append('items', {
'item': item_doc.item,
From 341f7733d1e2ce8b0bd1c5a41e957a48af3735f4 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Tue, 30 Jul 2019 10:02:50 +0530
Subject: [PATCH 161/484] fix: Make item read-only in item location table
---
erpnext/stock/doctype/pick_ticket_item/pick_ticket_item.json | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/erpnext/stock/doctype/pick_ticket_item/pick_ticket_item.json b/erpnext/stock/doctype/pick_ticket_item/pick_ticket_item.json
index 7095be68f0..0a65eed376 100644
--- a/erpnext/stock/doctype/pick_ticket_item/pick_ticket_item.json
+++ b/erpnext/stock/doctype/pick_ticket_item/pick_ticket_item.json
@@ -27,7 +27,8 @@
"fieldtype": "Link",
"in_list_view": 1,
"label": "Item",
- "options": "Item"
+ "options": "Item",
+ "read_only": 1
},
{
"fieldname": "qty",
@@ -129,7 +130,7 @@
}
],
"istable": 1,
- "modified": "2019-07-26 14:47:33.965373",
+ "modified": "2019-07-30 09:28:44.969479",
"modified_by": "Administrator",
"module": "Stock",
"name": "Pick Ticket Item",
From 14fb1600ec22b0ee3d78c5c49740615db215e016 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Tue, 30 Jul 2019 11:47:21 +0530
Subject: [PATCH 162/484] fix: Select location based on group warehouse
---
.../stock/doctype/pick_ticket/pick_ticket.js | 10 ++++
.../stock/doctype/pick_ticket/pick_ticket.py | 47 ++++++++++++-------
2 files changed, 39 insertions(+), 18 deletions(-)
diff --git a/erpnext/stock/doctype/pick_ticket/pick_ticket.js b/erpnext/stock/doctype/pick_ticket/pick_ticket.js
index a2d6cd71de..87fad7f9ee 100644
--- a/erpnext/stock/doctype/pick_ticket/pick_ticket.js
+++ b/erpnext/stock/doctype/pick_ticket/pick_ticket.js
@@ -2,6 +2,16 @@
// For license information, please see license.txt
frappe.ui.form.on('Pick Ticket', {
+ setup: (frm) => {
+ frm.set_query('group_warehouse', () => {
+ return {
+ filters: {
+ 'is_group': 1,
+ 'company': frm.doc.company
+ }
+ };
+ });
+ },
refresh: (frm) => {
this.frm.add_custom_button(__('Sales Order'), function() {
erpnext.utils.map_current_doc({
diff --git a/erpnext/stock/doctype/pick_ticket/pick_ticket.py b/erpnext/stock/doctype/pick_ticket/pick_ticket.py
index ce0e5526b6..a1adf9fee4 100644
--- a/erpnext/stock/doctype/pick_ticket/pick_ticket.py
+++ b/erpnext/stock/doctype/pick_ticket/pick_ticket.py
@@ -9,10 +9,15 @@ from frappe.model.document import Document
class PickTicket(Document):
def set_item_locations(self):
reference_items = self.reference_document_items
+
+ from_warehouses = None
+ if self.group_warehouse:
+ from_warehouses = frappe.db.get_descendants('Warehouse', self.group_warehouse)
+
+ # Reset
self.delete_key('items')
for item in reference_items:
- data = get_items_with_warehouse_and_quantity(item)
-
+ data = get_items_with_warehouse_and_quantity(item, from_warehouses)
for item_info in data:
print(self.append('items', item_info))
@@ -22,22 +27,11 @@ class PickTicket(Document):
elif frappe.get_cached_value('Item', item_doc.item, 'has_batch_no'):
set_batch_no(item_doc, self)
-def get_available_items(item):
- # gets all items available in different warehouses
- # FIFO
- available_items = frappe.get_all('Bin', filters={
- 'item_code': item,
- 'actual_qty': ['>', 0]
- }, fields=['warehouse', 'actual_qty as qty'], order_by='creation')
-
- return available_items
-
-def get_items_with_warehouse_and_quantity(item_doc):
+def get_items_with_warehouse_and_quantity(item_doc, from_warehouses):
items = []
- item_locations = get_available_items(item_doc.item)
+ item_locations = get_available_items(item_doc.item, from_warehouses)
remaining_qty = item_doc.qty
-
while remaining_qty > 0 and item_locations:
item_location = item_locations.pop(0)
qty = remaining_qty if item_location.qty >= remaining_qty else item_location.qty
@@ -51,11 +45,28 @@ def get_items_with_warehouse_and_quantity(item_doc):
remaining_qty -= qty
if remaining_qty:
- print('---------- {} qty of {} is out of stock. Skipping... -------------'.format(remaining_qty, item_doc.item))
+ frappe.msgprint('{} qty of {} is out of stock. Skipping...'.format(remaining_qty, item_doc.item))
return items
return items
+def get_available_items(item, from_warehouses):
+ # gets all items available in different warehouses
+ # FIFO
+ filters = frappe._dict({
+ 'item_code': item,
+ 'actual_qty': ['>', 0]
+ })
+ if from_warehouses:
+ filters.warehouse = ['in', from_warehouses]
+
+ available_items = frappe.get_all('Bin',
+ fields=['warehouse', 'actual_qty as qty'],
+ filters=filters,
+ order_by='creation')
+
+ return available_items
+
def set_serial_nos(item_doc):
serial_nos = frappe.get_all('Serial No', {
'item_code': item_doc.item,
@@ -91,7 +102,7 @@ def set_batch_no(item_doc, parent_doc):
batch = batches.pop()
batch_expiry = frappe.get_value('Batch', batch.batch_no, 'expiry_date')
if batch_expiry and batch_expiry <= frappe.utils.getdate():
- print('---------- Batch {} is expired. Skipping... -------------'.format(batch.batch_no))
+ frappe.msgprint('Skipping expired Batch {}'.format(batch.batch_no))
continue
item_doc.batch_no = batch.batch_no
if batch.qty >= item_doc.qty:
@@ -112,5 +123,5 @@ def set_batch_no(item_doc, parent_doc):
'reference_name': item_doc.reference_name
})
if required_qty:
- print('---------- No batches found for {} qty of {}. Skipping... -------------'.format(required_qty, item_doc.item))
+ frappe.msgprint('No batches found for {} qty of {}. Skipping...'.format(required_qty, item_doc.item))
parent_doc.remove(item_doc)
From 72d03464dcc584885738d6e7a634264ad49bbc21 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Tue, 30 Jul 2019 11:56:24 +0530
Subject: [PATCH 163/484] fix: Show "Get Item Location" only if there are
reference items
---
erpnext/stock/doctype/pick_ticket/pick_ticket.js | 12 +++++-------
1 file changed, 5 insertions(+), 7 deletions(-)
diff --git a/erpnext/stock/doctype/pick_ticket/pick_ticket.js b/erpnext/stock/doctype/pick_ticket/pick_ticket.js
index 87fad7f9ee..5903e6fea0 100644
--- a/erpnext/stock/doctype/pick_ticket/pick_ticket.js
+++ b/erpnext/stock/doctype/pick_ticket/pick_ticket.js
@@ -27,13 +27,11 @@ frappe.ui.form.on('Pick Ticket', {
});
}, __("Get items from"));
- frm.add_custom_button(__('Get Item Locations'), () => {
- frm.trigger('set_item_locations');
- });
+ if (frm.doc.reference_document_items.length) {
+ frm.add_custom_button(__('Get Item Locations'), () => {
+ frm.call('set_item_locations');
+ });
+ }
},
- set_item_locations: (frm) => {
- frm.call('set_item_locations')
- }
-
});
From 403968b2f7f458e6ce7934f93b1b3bfbeaf6fe4a Mon Sep 17 00:00:00 2001
From: Sahil Khan
Date: Tue, 30 Jul 2019 13:29:07 +0550
Subject: [PATCH 164/484] bumped to version 12.0.3
---
erpnext/__init__.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/__init__.py b/erpnext/__init__.py
index 04f741e14b..5e2669368b 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__ = '12.0.2'
+__version__ = '12.0.3'
def get_default_company(user=None):
'''Get default company for user'''
From 1214e2d2a41b2b69149b5b96afe7fad6fa24ec87 Mon Sep 17 00:00:00 2001
From: Faris Ansari
Date: Tue, 30 Jul 2019 16:52:24 +0530
Subject: [PATCH 165/484] feat: BOM Comparison Tool
---
erpnext/manufacturing/doctype/bom/bom.py | 50 ++++
.../page/bom_comparison_tool/__init__.py | 0
.../bom_comparison_tool.js | 218 ++++++++++++++++++
.../bom_comparison_tool.json | 30 +++
4 files changed, 298 insertions(+)
create mode 100644 erpnext/manufacturing/page/bom_comparison_tool/__init__.py
create mode 100644 erpnext/manufacturing/page/bom_comparison_tool/bom_comparison_tool.js
create mode 100644 erpnext/manufacturing/page/bom_comparison_tool/bom_comparison_tool.json
diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py
index a7162933bf..22c2f694f5 100644
--- a/erpnext/manufacturing/doctype/bom/bom.py
+++ b/erpnext/manufacturing/doctype/bom/bom.py
@@ -9,6 +9,7 @@ from erpnext.setup.utils import get_exchange_rate
from frappe.website.website_generator import WebsiteGenerator
from erpnext.stock.get_item_details import get_conversion_factor
from erpnext.stock.get_item_details import get_price_list_rate
+from frappe.core.doctype.version.version import get_diff
import functools
@@ -763,3 +764,52 @@ def add_additional_cost(stock_entry, work_order):
'description': name[0],
'amount': items.get(name[0])
})
+
+@frappe.whitelist()
+def get_bom_diff(bom1, bom2):
+ from frappe.model import table_fields
+
+ doc1 = frappe.get_doc('BOM', bom1)
+ doc2 = frappe.get_doc('BOM', bom2)
+
+ out = get_diff(doc1, doc2)
+ out.row_changed = []
+ out.added = []
+ out.removed = []
+
+ meta = doc1.meta
+
+ identifiers = {
+ 'operations': 'operation',
+ 'items': 'item_code',
+ 'scrap_items': 'item_code',
+ 'exploded_items': 'item_code'
+ }
+
+ for df in meta.fields:
+ old_value, new_value = doc1.get(df.fieldname), doc2.get(df.fieldname)
+
+ if df.fieldtype in table_fields:
+ identifier = identifiers[df.fieldname]
+ # make maps
+ old_row_by_identifier, new_row_by_identifier = {}, {}
+ for d in old_value:
+ old_row_by_identifier[d.get(identifier)] = d
+ for d in new_value:
+ new_row_by_identifier[d.get(identifier)] = d
+
+ # check rows for additions, changes
+ for i, d in enumerate(new_value):
+ if d.get(identifier) in old_row_by_identifier:
+ diff = get_diff(old_row_by_identifier[d.get(identifier)], d, for_child=True)
+ if diff and diff.changed:
+ out.row_changed.append((df.fieldname, i, d.get(identifier), diff.changed))
+ else:
+ out.added.append([df.fieldname, d.as_dict()])
+
+ # check for deletions
+ for d in old_value:
+ if not d.get(identifier) in new_row_by_identifier:
+ out.removed.append([df.fieldname, d.as_dict()])
+
+ return out
diff --git a/erpnext/manufacturing/page/bom_comparison_tool/__init__.py b/erpnext/manufacturing/page/bom_comparison_tool/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/manufacturing/page/bom_comparison_tool/bom_comparison_tool.js b/erpnext/manufacturing/page/bom_comparison_tool/bom_comparison_tool.js
new file mode 100644
index 0000000000..eeecdf69ae
--- /dev/null
+++ b/erpnext/manufacturing/page/bom_comparison_tool/bom_comparison_tool.js
@@ -0,0 +1,218 @@
+frappe.pages['bom-comparison-tool'].on_page_load = function(wrapper) {
+ var page = frappe.ui.make_app_page({
+ parent: wrapper,
+ title: __('BOM Comparison Tool'),
+ single_column: true
+ });
+
+ new erpnext.BOMComparisonTool(page);
+}
+
+erpnext.BOMComparisonTool = class BOMComparisonTool {
+ constructor(page) {
+ this.page = page;
+ this.make_form();
+ }
+
+ make_form() {
+ this.form = new frappe.ui.FieldGroup({
+ fields: [
+ {
+ label: __('BOM 1'),
+ fieldname: 'name1',
+ fieldtype: 'Link',
+ options: 'BOM',
+ change: () => this.fetch_and_render()
+ },
+ {
+ fieldtype: 'Column Break'
+ },
+ {
+ label: __('BOM 2'),
+ fieldname: 'name2',
+ fieldtype: 'Link',
+ options: 'BOM',
+ change: () => this.fetch_and_render()
+ },
+ {
+ fieldtype: 'Section Break'
+ },
+ {
+ fieldtype: 'HTML',
+ fieldname: 'preview'
+ }
+ ],
+ body: this.page.body
+ });
+ this.form.make();
+ }
+
+ fetch_and_render() {
+ let { name1, name2 } = this.form.get_values();
+ if (!(name1 && name2)) {
+ this.form.get_field('preview').html('');
+ return;
+ }
+
+ // set working state
+ this.form.get_field('preview').html(`
+
+ ${__("Fetching...")}
+
+ `);
+
+ frappe.call('erpnext.manufacturing.doctype.bom.bom.get_bom_diff', {
+ bom1: name1,
+ bom2: name2
+ }).then(r => {
+ let diff = r.message;
+ frappe.model.with_doctype('BOM', () => {
+ this.render('BOM', name1, name2, diff);
+ });
+ });
+ }
+
+ render(doctype, name1, name2, diff) {
+
+ let change_html = (title, doctype, changed) => {
+ let values_changed = this.get_changed_values(doctype, changed)
+ .map(change => {
+ let [fieldname, value1, value2] = change;
+ return `
+
+ ${frappe.meta.get_label(doctype, fieldname)}
+ ${value1}
+ ${value2}
+
+ `;
+ })
+ .join('');
+
+ return `
+ ${title}
+
+
+
+ ${__('Field')}
+ ${name1}
+ ${name2}
+
+ ${values_changed}
+
+
+ `;
+ }
+
+ let value_changes = change_html(__('Values Changed'), doctype, diff.changed);
+
+ let row_changes_by_fieldname = group_items(diff.row_changed, change => change[0]);
+
+ let table_changes = Object.keys(row_changes_by_fieldname).map(fieldname => {
+ let changes = row_changes_by_fieldname[fieldname];
+ let df = frappe.meta.get_docfield(doctype, fieldname);
+
+ let html = changes.map(change => {
+ let [fieldname, idx, item_code, changes] = change;
+ let df = frappe.meta.get_docfield(doctype, fieldname);
+ let child_doctype = df.options;
+ let values_changed = this.get_changed_values(child_doctype, changes);
+
+ return values_changed.map((change, i) => {
+ let [fieldname, value1, value2] = change;
+ return `
+
+ ${i === 0
+ ? `${item_code} `
+ : ''}
+ ${frappe.meta.get_label(child_doctype, fieldname)}
+ ${value1}
+ ${value2}
+
+ `;
+ }).join('');
+ }).join('');
+
+ return `
+ ${__('Changes in {0}', [df.label])}
+
+
+ ${__('Item Code')}
+ ${__('Field')}
+ ${name1}
+ ${name2}
+
+ ${html}
+
+ `;
+ }).join('');
+
+ let get_added_removed_html = (title, grouped_items) => {
+ return Object.keys(grouped_items).map(fieldname => {
+ let rows = grouped_items[fieldname];
+ let df = frappe.meta.get_docfield(doctype, fieldname);
+ let fields = frappe.meta.get_docfields(df.options)
+ .filter(df => df.in_list_view);
+
+ let html = rows.map(row => {
+ let [, doc] = row;
+ return `
+
+
+ ${fields.map(df => {
+ return `${doc[df.fieldname]} `
+ }).join('')}
+
+ `;
+ }).join('');
+
+ return `
+ ${$.format(title, [df.label])}
+
+ ${fields.map(df => {
+ return `${df.label} `
+ }).join('')}
+
+ ${html}
+
+ `;
+ }).join('');
+ }
+
+ let added_by_fieldname = group_items(diff.added, change => change[0]);
+ let removed_by_fieldname = group_items(diff.removed, change => change[0]);
+
+ let added_html = get_added_removed_html(__('Rows Added in {0}'), added_by_fieldname);
+ let removed_html = get_added_removed_html(__('Rows Removed in {0}'), removed_by_fieldname);
+
+ let html = `
+ ${value_changes}
+ ${table_changes}
+ ${added_html}
+ ${removed_html}
+ `;
+
+ this.form.get_field('preview').html(html);
+ }
+
+ get_changed_values(doctype, changed) {
+ return changed.filter(change => {
+ let [fieldname, value1, value2] = change;
+ if (!value1) value1 = '';
+ if (!value2) value2 = '';
+ if (value1 === value2) return false;
+ let df = frappe.meta.get_docfield(doctype, fieldname);
+ if (!df) return false;
+ if (df.hidden) return false;
+ return true;
+ });
+ }
+}
+
+function group_items(array, fn) {
+ return array.reduce((acc, item) => {
+ let key = fn(item);
+ acc[key] = acc[key] || [];
+ acc[key].push(item);
+ return acc;
+ }, {});
+}
diff --git a/erpnext/manufacturing/page/bom_comparison_tool/bom_comparison_tool.json b/erpnext/manufacturing/page/bom_comparison_tool/bom_comparison_tool.json
new file mode 100644
index 0000000000..067a1061b8
--- /dev/null
+++ b/erpnext/manufacturing/page/bom_comparison_tool/bom_comparison_tool.json
@@ -0,0 +1,30 @@
+{
+ "content": null,
+ "creation": "2019-07-29 13:24:38.201981",
+ "docstatus": 0,
+ "doctype": "Page",
+ "idx": 0,
+ "modified": "2019-07-29 13:24:38.201981",
+ "modified_by": "Administrator",
+ "module": "Manufacturing",
+ "name": "bom-comparison-tool",
+ "owner": "Administrator",
+ "page_name": "BOM Comparison Tool",
+ "restrict_to_domain": "Manufacturing",
+ "roles": [
+ {
+ "role": "System Manager"
+ },
+ {
+ "role": "Manufacturing User"
+ },
+ {
+ "role": "Manufacturing Manager"
+ }
+ ],
+ "script": null,
+ "standard": "Yes",
+ "style": null,
+ "system_page": 0,
+ "title": "BOM Comparison Tool"
+}
\ No newline at end of file
From 66064c7827db557f208caca72f87d86c614c8d38 Mon Sep 17 00:00:00 2001
From: Faris Ansari
Date: Tue, 30 Jul 2019 17:11:18 +0530
Subject: [PATCH 166/484] fix: Add BOM Comparison Tool to module view
---
erpnext/config/manufacturing.py | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/erpnext/config/manufacturing.py b/erpnext/config/manufacturing.py
index c79c5b8b11..2c18eeb83a 100644
--- a/erpnext/config/manufacturing.py
+++ b/erpnext/config/manufacturing.py
@@ -94,6 +94,13 @@ def get_data():
"name": "BOM Update Tool",
"description": _("Replace BOM and update latest price in all BOMs"),
},
+ {
+ "type": "page",
+ "label": _("BOM Comparison Tool"),
+ "name": "bom-comparison-tool",
+ "description": _("Compare BOMs for changes in Raw Materials and Operations"),
+ "data_doctype": "BOM"
+ },
]
},
{
From a4ada938345b8a2e824d278124c3b0ba52d60f96 Mon Sep 17 00:00:00 2001
From: Faris Ansari
Date: Tue, 30 Jul 2019 17:11:34 +0530
Subject: [PATCH 167/484] fix: Field labels
---
erpnext/manufacturing/doctype/bom/bom.json | 2458 ++++----------------
1 file changed, 459 insertions(+), 1999 deletions(-)
diff --git a/erpnext/manufacturing/doctype/bom/bom.json b/erpnext/manufacturing/doctype/bom/bom.json
index 7865a2476f..a0faeb5fb5 100644
--- a/erpnext/manufacturing/doctype/bom/bom.json
+++ b/erpnext/manufacturing/doctype/bom/bom.json
@@ -1,2068 +1,528 @@
{
- "allow_copy": 0,
- "allow_events_in_timeline": 0,
- "allow_guest_to_view": 0,
- "allow_import": 1,
- "allow_rename": 0,
- "beta": 0,
- "creation": "2013-01-22 15:11:38",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "Setup",
- "editable_grid": 0,
+ "allow_import": 1,
+ "creation": "2013-01-22 15:11:38",
+ "doctype": "DocType",
+ "document_type": "Setup",
+ "field_order": [
+ "item",
+ "item_name",
+ "image",
+ "uom",
+ "quantity",
+ "cb0",
+ "is_active",
+ "is_default",
+ "with_operations",
+ "inspection_required",
+ "allow_alternative_item",
+ "allow_same_item_multiple_times",
+ "set_rate_of_sub_assembly_item_based_on_bom",
+ "quality_inspection_template",
+ "currency_detail",
+ "company",
+ "transfer_material_against",
+ "conversion_rate",
+ "column_break_12",
+ "currency",
+ "rm_cost_as_per",
+ "buying_price_list",
+ "operations_section",
+ "routing",
+ "operations",
+ "materials_section",
+ "items",
+ "scrap_section",
+ "scrap_items",
+ "costing",
+ "operating_cost",
+ "raw_material_cost",
+ "scrap_material_cost",
+ "cb1",
+ "base_operating_cost",
+ "base_raw_material_cost",
+ "base_scrap_material_cost",
+ "total_cost_of_bom",
+ "total_cost",
+ "column_break_26",
+ "base_total_cost",
+ "more_info_section",
+ "project",
+ "amended_from",
+ "col_break23",
+ "section_break_25",
+ "description",
+ "column_break_27",
+ "section_break0",
+ "exploded_items",
+ "website_section",
+ "show_in_website",
+ "route",
+ "website_image",
+ "thumbnail",
+ "sb_web_spec",
+ "web_long_description",
+ "show_items",
+ "show_operations"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "Item to be manufactured or repacked",
- "fetch_if_empty": 0,
- "fieldname": "item",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 1,
- "label": "Item",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "item",
- "oldfieldtype": "Link",
- "options": "Item",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 1,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "description": "Item to be manufactured or repacked",
+ "fieldname": "item",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "in_standard_filter": 1,
+ "label": "Item",
+ "oldfieldname": "item",
+ "oldfieldtype": "Link",
+ "options": "Item",
+ "reqd": 1,
+ "search_index": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
- "fetch_from": "item.item_name",
- "fetch_if_empty": 0,
- "fieldname": "item_name",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 1,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Item Name",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fetch_from": "item.item_name",
+ "fieldname": "item_name",
+ "fieldtype": "Data",
+ "in_global_search": 1,
+ "label": "Item Name",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_from": "item.image",
- "fetch_if_empty": 0,
- "fieldname": "image",
- "fieldtype": "Attach Image",
- "hidden": 1,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Image",
- "length": 0,
- "no_copy": 0,
- "options": "image",
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fetch_from": "item.image",
+ "fieldname": "image",
+ "fieldtype": "Attach Image",
+ "hidden": 1,
+ "label": "Image",
+ "options": "image",
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_from": "item.stock_uom",
- "fetch_if_empty": 0,
- "fieldname": "uom",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Item UOM",
- "length": 0,
- "no_copy": 0,
- "options": "UOM",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fetch_from": "item.stock_uom",
+ "fieldname": "uom",
+ "fieldtype": "Link",
+ "label": "Item UOM",
+ "options": "UOM",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "1",
- "description": "Quantity of item obtained after manufacturing / repacking from given quantities of raw materials",
- "fetch_if_empty": 0,
- "fieldname": "quantity",
- "fieldtype": "Float",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Quantity",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "quantity",
- "oldfieldtype": "Currency",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "default": "1",
+ "description": "Quantity of item obtained after manufacturing / repacking from given quantities of raw materials",
+ "fieldname": "quantity",
+ "fieldtype": "Float",
+ "label": "Quantity",
+ "oldfieldname": "quantity",
+ "oldfieldtype": "Currency",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "cb0",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "cb0",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "1",
- "fetch_if_empty": 0,
- "fieldname": "is_active",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Is Active",
- "length": 0,
- "no_copy": 1,
- "oldfieldname": "is_active",
- "oldfieldtype": "Select",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "allow_on_submit": 1,
+ "default": "1",
+ "fieldname": "is_active",
+ "fieldtype": "Check",
+ "in_list_view": 1,
+ "label": "Is Active",
+ "no_copy": 1,
+ "oldfieldname": "is_active",
+ "oldfieldtype": "Select"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "1",
- "fetch_if_empty": 0,
- "fieldname": "is_default",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Is Default",
- "length": 0,
- "no_copy": 1,
- "oldfieldname": "is_default",
- "oldfieldtype": "Check",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "allow_on_submit": 1,
+ "default": "1",
+ "fieldname": "is_default",
+ "fieldtype": "Check",
+ "in_list_view": 1,
+ "label": "Is Default",
+ "no_copy": 1,
+ "oldfieldname": "is_default",
+ "oldfieldtype": "Check"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "Manage cost of operations",
- "fetch_if_empty": 0,
- "fieldname": "with_operations",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 1,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "With Operations",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "default": "0",
+ "description": "Manage cost of operations",
+ "fieldname": "with_operations",
+ "fieldtype": "Check",
+ "ignore_user_permissions": 1,
+ "label": "With Operations"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "inspection_required",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Inspection Required",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "default": "0",
+ "fieldname": "inspection_required",
+ "fieldtype": "Check",
+ "label": "Inspection Required"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "allow_alternative_item",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Allow Alternative Item",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "default": "0",
+ "fieldname": "allow_alternative_item",
+ "fieldtype": "Check",
+ "label": "Allow Alternative Item"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "allow_same_item_multiple_times",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Allow Same Item Multiple Times",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "default": "0",
+ "fieldname": "allow_same_item_multiple_times",
+ "fieldtype": "Check",
+ "label": "Allow Same Item Multiple Times"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "1",
- "fetch_if_empty": 0,
- "fieldname": "set_rate_of_sub_assembly_item_based_on_bom",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Set rate of sub-assembly item based on BOM",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "allow_on_submit": 1,
+ "default": "1",
+ "fieldname": "set_rate_of_sub_assembly_item_based_on_bom",
+ "fieldtype": "Check",
+ "label": "Set rate of sub-assembly item based on BOM"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "inspection_required",
- "fetch_if_empty": 0,
- "fieldname": "quality_inspection_template",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Quality Inspection Template",
- "length": 0,
- "no_copy": 0,
- "options": "Quality Inspection Template",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "depends_on": "inspection_required",
+ "fieldname": "quality_inspection_template",
+ "fieldtype": "Link",
+ "label": "Quality Inspection Template",
+ "options": "Quality Inspection Template"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "currency_detail",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "currency_detail",
+ "fieldtype": "Section Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "company",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Company",
- "length": 0,
- "no_copy": 0,
- "options": "Company",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 1,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "label": "Company",
+ "options": "Company",
+ "remember_last_selected_value": 1,
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "",
- "fetch_if_empty": 0,
- "fieldname": "transfer_material_against",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Transfer Material Against",
- "length": 0,
- "no_copy": 0,
- "options": "\nWork Order\nJob Card",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "transfer_material_against",
+ "fieldtype": "Select",
+ "label": "Transfer Material Against",
+ "options": "\nWork Order\nJob Card"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "conversion_rate",
- "fieldtype": "Float",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Conversion Rate",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "9",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "conversion_rate",
+ "fieldtype": "Float",
+ "label": "Conversion Rate",
+ "precision": "9",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "column_break_12",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "column_break_12",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "currency",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Currency",
- "length": 0,
- "no_copy": 0,
- "options": "Currency",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "currency",
+ "fieldtype": "Link",
+ "label": "Currency",
+ "options": "Currency",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "Valuation Rate",
- "fetch_if_empty": 0,
- "fieldname": "rm_cost_as_per",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Rate Of Materials Based On",
- "length": 0,
- "no_copy": 0,
- "options": "Valuation Rate\nLast Purchase Rate\nPrice List",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "allow_on_submit": 1,
+ "default": "Valuation Rate",
+ "fieldname": "rm_cost_as_per",
+ "fieldtype": "Select",
+ "label": "Rate Of Materials Based On",
+ "options": "Valuation Rate\nLast Purchase Rate\nPrice List"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:doc.rm_cost_as_per===\"Price List\"",
- "fetch_if_empty": 0,
- "fieldname": "buying_price_list",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Price List",
- "length": 0,
- "no_copy": 0,
- "options": "Price List",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "allow_on_submit": 1,
+ "depends_on": "eval:doc.rm_cost_as_per===\"Price List\"",
+ "fieldname": "buying_price_list",
+ "fieldtype": "Link",
+ "label": "Price List",
+ "options": "Price List"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
- "description": "",
- "fetch_if_empty": 0,
- "fieldname": "operations_section",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Operations",
- "length": 0,
- "no_copy": 0,
- "oldfieldtype": "Section Break",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "operations_section",
+ "fieldtype": "Section Break",
+ "label": "Operations",
+ "oldfieldtype": "Section Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "routing",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Routing",
- "length": 0,
- "no_copy": 0,
- "options": "Routing",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "routing",
+ "fieldtype": "Link",
+ "label": "Routing",
+ "options": "Routing"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "operations",
- "fieldtype": "Table",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Operations",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "bom_operations",
- "oldfieldtype": "Table",
- "options": "BOM Operation",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "operations",
+ "fieldtype": "Table",
+ "label": "Operations",
+ "oldfieldname": "bom_operations",
+ "oldfieldtype": "Table",
+ "options": "BOM Operation"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "materials_section",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Materials",
- "length": 0,
- "no_copy": 0,
- "oldfieldtype": "Section Break",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "materials_section",
+ "fieldtype": "Section Break",
+ "label": "Materials",
+ "oldfieldtype": "Section Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "items",
- "fieldtype": "Table",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Items",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "bom_materials",
- "oldfieldtype": "Table",
- "options": "BOM Item",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "items",
+ "fieldtype": "Table",
+ "label": "Items",
+ "oldfieldname": "bom_materials",
+ "oldfieldtype": "Table",
+ "options": "BOM Item",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "scrap_section",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Scrap",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "collapsible": 1,
+ "fieldname": "scrap_section",
+ "fieldtype": "Section Break",
+ "label": "Scrap"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "scrap_items",
- "fieldtype": "Table",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Scrap Items",
- "length": 0,
- "no_copy": 0,
- "options": "BOM Scrap Item",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "scrap_items",
+ "fieldtype": "Table",
+ "label": "Scrap Items",
+ "options": "BOM Scrap Item"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "costing",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Costing",
- "length": 0,
- "no_copy": 0,
- "oldfieldtype": "Section Break",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "costing",
+ "fieldtype": "Section Break",
+ "label": "Costing",
+ "oldfieldtype": "Section Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "operating_cost",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Operating Cost",
- "length": 0,
- "no_copy": 0,
- "options": "currency",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "operating_cost",
+ "fieldtype": "Currency",
+ "label": "Operating Cost",
+ "options": "currency",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "raw_material_cost",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Raw Material Cost",
- "length": 0,
- "no_copy": 0,
- "options": "currency",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "raw_material_cost",
+ "fieldtype": "Currency",
+ "label": "Raw Material Cost",
+ "options": "currency",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "scrap_material_cost",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Scrap Material Cost",
- "length": 0,
- "no_copy": 0,
- "options": "currency",
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "scrap_material_cost",
+ "fieldtype": "Currency",
+ "label": "Scrap Material Cost",
+ "options": "currency",
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "cb1",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "cb1",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "base_operating_cost",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Operating Cost (Company Currency)",
- "length": 0,
- "no_copy": 0,
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "base_operating_cost",
+ "fieldtype": "Currency",
+ "label": "Operating Cost (Company Currency)",
+ "options": "Company:company:default_currency",
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "base_raw_material_cost",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Raw Material Cost(Company Currency)",
- "length": 0,
- "no_copy": 0,
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "base_raw_material_cost",
+ "fieldtype": "Currency",
+ "label": "Raw Material Cost (Company Currency)",
+ "options": "Company:company:default_currency",
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "base_scrap_material_cost",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Scrap Material Cost(Company Currency)",
- "length": 0,
- "no_copy": 1,
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "base_scrap_material_cost",
+ "fieldtype": "Data",
+ "label": "Scrap Material Cost(Company Currency)",
+ "no_copy": 1,
+ "options": "Company:company:default_currency",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "total_cost_of_bom",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "total_cost_of_bom",
+ "fieldtype": "Section Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "total_cost",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Total Cost",
- "length": 0,
- "no_copy": 0,
- "options": "currency",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "total_cost",
+ "fieldtype": "Currency",
+ "in_list_view": 1,
+ "label": "Total Cost",
+ "options": "currency",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "column_break_26",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "column_break_26",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "base_total_cost",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Total Cost(Company Currency)",
- "length": 0,
- "no_copy": 0,
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "base_total_cost",
+ "fieldtype": "Currency",
+ "label": "Total Cost (Company Currency)",
+ "options": "Company:company:default_currency",
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "more_info_section",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "more_info_section",
+ "fieldtype": "Section Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "project",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Project",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "project",
- "oldfieldtype": "Link",
- "options": "Project",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "project",
+ "fieldtype": "Link",
+ "label": "Project",
+ "oldfieldname": "project",
+ "oldfieldtype": "Link",
+ "options": "Project"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "amended_from",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 1,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Amended From",
- "length": 0,
- "no_copy": 1,
- "options": "BOM",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "amended_from",
+ "fieldtype": "Link",
+ "ignore_user_permissions": 1,
+ "label": "Amended From",
+ "no_copy": 1,
+ "options": "BOM",
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "col_break23",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "col_break23",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "section_break_25",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "section_break_25",
+ "fieldtype": "Section Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_from": "item.description",
- "fetch_if_empty": 0,
- "fieldname": "description",
- "fieldtype": "Small Text",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Item Description",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fetch_from": "item.description",
+ "fieldname": "description",
+ "fieldtype": "Small Text",
+ "label": "Item Description",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "column_break_27",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "column_break_27",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:!doc.__islocal",
- "fetch_if_empty": 0,
- "fieldname": "section_break0",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Materials Required (Exploded)",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "depends_on": "eval:!doc.__islocal",
+ "fieldname": "section_break0",
+ "fieldtype": "Section Break",
+ "label": "Materials Required (Exploded)"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "exploded_items",
- "fieldtype": "Table",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Exploded_items",
- "length": 0,
- "no_copy": 1,
- "oldfieldname": "flat_bom_details",
- "oldfieldtype": "Table",
- "options": "BOM Explosion Item",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "exploded_items",
+ "fieldtype": "Table",
+ "label": "Exploded Items",
+ "no_copy": 1,
+ "oldfieldname": "flat_bom_details",
+ "oldfieldtype": "Table",
+ "options": "BOM Explosion Item",
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "website_section",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Website",
- "length": 0,
- "no_copy": 0,
- "options": "",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "collapsible": 1,
+ "fieldname": "website_section",
+ "fieldtype": "Section Break",
+ "label": "Website"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
- "fetch_if_empty": 0,
- "fieldname": "show_in_website",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Show in Website",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "allow_on_submit": 1,
+ "default": "0",
+ "fieldname": "show_in_website",
+ "fieldtype": "Check",
+ "label": "Show in Website"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "route",
- "fieldtype": "Small Text",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Route",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "allow_on_submit": 1,
+ "fieldname": "route",
+ "fieldtype": "Small Text",
+ "label": "Route"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "show_in_website",
- "description": "Item Image (if not slideshow)",
- "fetch_if_empty": 0,
- "fieldname": "website_image",
- "fieldtype": "Attach Image",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Image",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "allow_on_submit": 1,
+ "depends_on": "show_in_website",
+ "description": "Item Image (if not slideshow)",
+ "fieldname": "website_image",
+ "fieldtype": "Attach Image",
+ "label": "Image"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "thumbnail",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Thumbnail",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "allow_on_submit": 1,
+ "fieldname": "thumbnail",
+ "fieldtype": "Data",
+ "label": "Thumbnail",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "collapsible_depends_on": "website_items",
- "columns": 0,
- "depends_on": "show_in_website",
- "fetch_if_empty": 0,
- "fieldname": "sb_web_spec",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Website Specifications",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "collapsible": 1,
+ "collapsible_depends_on": "website_items",
+ "depends_on": "show_in_website",
+ "fieldname": "sb_web_spec",
+ "fieldtype": "Section Break",
+ "label": "Website Specifications"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "show_in_website",
- "fetch_if_empty": 0,
- "fieldname": "web_long_description",
- "fieldtype": "Text Editor",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Website Description",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "allow_on_submit": 1,
+ "depends_on": "show_in_website",
+ "fieldname": "web_long_description",
+ "fieldtype": "Text Editor",
+ "label": "Website Description"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "show_in_website",
- "fetch_if_empty": 0,
- "fieldname": "show_items",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Show Items",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "allow_on_submit": 1,
+ "default": "0",
+ "depends_on": "show_in_website",
+ "fieldname": "show_items",
+ "fieldtype": "Check",
+ "label": "Show Items"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:(doc.show_in_website && doc.with_operations)",
- "fetch_if_empty": 0,
- "fieldname": "show_operations",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Show Operations",
- "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,
- "translatable": 0,
- "unique": 0
+ "allow_on_submit": 1,
+ "default": "0",
+ "depends_on": "eval:(doc.show_in_website && doc.with_operations)",
+ "fieldname": "show_operations",
+ "fieldtype": "Check",
+ "label": "Show Operations"
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "icon": "fa fa-sitemap",
- "idx": 1,
- "image_field": "image",
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 1,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2019-05-01 16:36:05.197126",
- "modified_by": "Administrator",
- "module": "Manufacturing",
- "name": "BOM",
- "owner": "Administrator",
+ ],
+ "icon": "fa fa-sitemap",
+ "idx": 1,
+ "image_field": "image",
+ "is_submittable": 1,
+ "modified": "2019-07-30 17:00:09.665068",
+ "modified_by": "Administrator",
+ "module": "Manufacturing",
+ "name": "BOM",
+ "owner": "Administrator",
"permissions": [
{
- "amend": 0,
- "cancel": 1,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Manufacturing Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 1,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Manufacturing Manager",
+ "share": 1,
+ "submit": 1,
"write": 1
- },
+ },
{
- "amend": 0,
- "cancel": 1,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Manufacturing User",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 1,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Manufacturing User",
+ "share": 1,
+ "submit": 1,
"write": 1
}
- ],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "search_fields": "item, item_name",
- "show_name_in_global_search": 1,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1,
- "track_seen": 0,
- "track_views": 0
+ ],
+ "search_fields": "item, item_name",
+ "show_name_in_global_search": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
}
\ No newline at end of file
From f650cb8e4bdbfc34210cb624eabc1b93deca8ced Mon Sep 17 00:00:00 2001
From: Faris Ansari
Date: Tue, 30 Jul 2019 17:46:15 +0530
Subject: [PATCH 168/484] style: Indent and missing semicolon
---
.../bom_comparison_tool.js | 29 ++++++++-----------
1 file changed, 12 insertions(+), 17 deletions(-)
diff --git a/erpnext/manufacturing/page/bom_comparison_tool/bom_comparison_tool.js b/erpnext/manufacturing/page/bom_comparison_tool/bom_comparison_tool.js
index eeecdf69ae..11648226a8 100644
--- a/erpnext/manufacturing/page/bom_comparison_tool/bom_comparison_tool.js
+++ b/erpnext/manufacturing/page/bom_comparison_tool/bom_comparison_tool.js
@@ -112,18 +112,19 @@ erpnext.BOMComparisonTool = class BOMComparisonTool {
let df = frappe.meta.get_docfield(doctype, fieldname);
let html = changes.map(change => {
- let [fieldname, idx, item_code, changes] = change;
+ let [fieldname,, item_code, changes] = change;
let df = frappe.meta.get_docfield(doctype, fieldname);
let child_doctype = df.options;
let values_changed = this.get_changed_values(child_doctype, changes);
return values_changed.map((change, i) => {
let [fieldname, value1, value2] = change;
+ let th = i === 0
+ ? `${item_code} `
+ : '';
return `
- ${i === 0
- ? `${item_code} `
- : ''}
+ ${th}
${frappe.meta.get_label(child_doctype, fieldname)}
${value1}
${value2}
@@ -155,23 +156,17 @@ erpnext.BOMComparisonTool = class BOMComparisonTool {
let html = rows.map(row => {
let [, doc] = row;
- return `
-
-
- ${fields.map(df => {
- return `${doc[df.fieldname]} `
- }).join('')}
-
- `;
+ let cells = fields
+ .map(df => `${doc[df.fieldname]} `)
+ .join('');
+ return `${cells} `;
}).join('');
+ let header = fields.map(df => `${df.label} `).join('');
return `
${$.format(title, [df.label])}
- ${fields.map(df => {
- return `${df.label} `
- }).join('')}
-
+ ${header}
${html}
`;
@@ -206,7 +201,7 @@ erpnext.BOMComparisonTool = class BOMComparisonTool {
return true;
});
}
-}
+};
function group_items(array, fn) {
return array.reduce((acc, item) => {
From 548293ad0893560c41acd5bbf22d37b1a8e4941f Mon Sep 17 00:00:00 2001
From: deepeshgarg007
Date: Tue, 30 Jul 2019 18:49:19 +0530
Subject: [PATCH 169/484] fix: Check zero valuation rate only for valid
doctypes
---
erpnext/stock/stock_ledger.py | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)
diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py
index ff5b026695..5fda2a4007 100644
--- a/erpnext/stock/stock_ledger.py
+++ b/erpnext/stock/stock_ledger.py
@@ -363,8 +363,17 @@ class update_entries_after(object):
self.stock_queue.append([0, sle.incoming_rate or sle.outgoing_rate or self.valuation_rate])
def check_if_allow_zero_valuation_rate(self, voucher_type, voucher_detail_no):
- ref_item_dt = voucher_type + (" Detail" if voucher_type == "Stock Entry" else " Item")
- return frappe.db.get_value(ref_item_dt, voucher_detail_no, "allow_zero_valuation_rate")
+ ref_item_dt = ""
+
+ if voucher_type == "Stock Entry":
+ ref_item_dt = voucher_type + " Detail"
+ elif voucher_type in ["Purchase Invoice", "Sales Invoice", "Delivery Note", "Purchase Receipt"]:
+ ref_item_dt = voucher_type + " Item"
+
+ if ref_item_dt:
+ return frappe.db.get_value(ref_item_dt, voucher_detail_no, "allow_zero_valuation_rate")
+ else:
+ return 0
def get_sle_before_datetime(self):
"""get previous stock ledger entry before current time-bucket"""
From 862363521bfc898b7fd2a724827354de4add5013 Mon Sep 17 00:00:00 2001
From: Rohit Waghchaure
Date: Tue, 23 Jul 2019 16:05:29 +0530
Subject: [PATCH 170/484] fix: scrap item not adding while doing finished good
entry
---
erpnext/stock/doctype/stock_entry/stock_entry.py | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py
index f40560a57f..b5303327f6 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.py
@@ -802,13 +802,13 @@ class StockEntry(StockController):
self.add_to_stock_entry_detail(item_dict)
- if self.purpose != "Send to Subcontractor":
- scrap_item_dict = self.get_bom_scrap_material(self.fg_completed_qty)
- for item in itervalues(scrap_item_dict):
- if self.pro_doc and self.pro_doc.scrap_warehouse:
- item["to_warehouse"] = self.pro_doc.scrap_warehouse
+ if self.purpose != "Send to Subcontractor" and self.purpose == "Manufacture":
+ scrap_item_dict = self.get_bom_scrap_material(self.fg_completed_qty)
+ for item in itervalues(scrap_item_dict):
+ if self.pro_doc and self.pro_doc.scrap_warehouse:
+ item["to_warehouse"] = self.pro_doc.scrap_warehouse
- self.add_to_stock_entry_detail(scrap_item_dict, bom_no=self.bom_no)
+ self.add_to_stock_entry_detail(scrap_item_dict, bom_no=self.bom_no)
# fetch the serial_no of the first stock entry for the second stock entry
if self.work_order and self.purpose == "Manufacture":
From b65c761b16f65a8c29b88e106f672ac1363d54ac Mon Sep 17 00:00:00 2001
From: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com>
Date: Wed, 31 Jul 2019 15:58:01 +0530
Subject: [PATCH 171/484] fix: Enhancement in credit note (#18510)
* fix: Credit note enhancement
* Fix: Print format for Sales Invoice Return
* fix: Zero quantity validation fix for credit note
---
.../doctype/sales_invoice/sales_invoice.js | 14 +-
.../sales_invoice_return/__init__.py | 0
.../sales_invoice_return.html | 129 ++++++++++++++++++
.../sales_invoice_return.json | 24 ++++
erpnext/controllers/accounts_controller.py | 4 +-
erpnext/controllers/taxes_and_totals.py | 7 +-
.../public/js/controllers/taxes_and_totals.js | 8 +-
7 files changed, 182 insertions(+), 4 deletions(-)
create mode 100644 erpnext/accounts/print_format/sales_invoice_return/__init__.py
create mode 100644 erpnext/accounts/print_format/sales_invoice_return/sales_invoice_return.html
create mode 100644 erpnext/accounts/print_format/sales_invoice_return/sales_invoice_return.json
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
index 1fe6895601..74e9186e37 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
@@ -44,6 +44,10 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
this.frm.toggle_reqd("due_date", !this.frm.doc.is_return);
+ if (this.frm.doc.is_return) {
+ this.frm.return_print_format = "Sales Invoice Return";
+ }
+
this.show_general_ledger();
if(doc.update_stock) this.show_stock_ledger();
@@ -148,16 +152,24 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
},
set_default_print_format: function() {
- // set default print format to POS type
+ // set default print format to POS type or Credit Note
if(cur_frm.doc.is_pos) {
if(cur_frm.pos_print_format) {
cur_frm.meta._default_print_format = cur_frm.meta.default_print_format;
cur_frm.meta.default_print_format = cur_frm.pos_print_format;
}
+ } else if(cur_frm.doc.is_return) {
+ if(cur_frm.return_print_format) {
+ cur_frm.meta._default_print_format = cur_frm.meta.default_print_format;
+ cur_frm.meta.default_print_format = cur_frm.return_print_format;
+ }
} else {
if(cur_frm.meta._default_print_format) {
cur_frm.meta.default_print_format = cur_frm.meta._default_print_format;
cur_frm.meta._default_print_format = null;
+ } else if(in_list([cur_frm.pos_print_format, cur_frm.return_print_format], cur_frm.meta.default_print_format)) {
+ cur_frm.meta.default_print_format = null;
+ cur_frm.meta._default_print_format = null;
}
}
},
diff --git a/erpnext/accounts/print_format/sales_invoice_return/__init__.py b/erpnext/accounts/print_format/sales_invoice_return/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/accounts/print_format/sales_invoice_return/sales_invoice_return.html b/erpnext/accounts/print_format/sales_invoice_return/sales_invoice_return.html
new file mode 100644
index 0000000000..889b7f71aa
--- /dev/null
+++ b/erpnext/accounts/print_format/sales_invoice_return/sales_invoice_return.html
@@ -0,0 +1,129 @@
+{%- from "templates/print_formats/standard_macros.html" import add_header, render_field, print_value, fieldmeta,
+ get_width, get_align_class -%}
+
+{%- macro render_currency(df, doc) -%}
+
+
+ {{ _(df.label) }}
+
+
+ {% if doc.get(df.fieldname) != None -%}
+ {{ frappe.utils.fmt_money((doc[df.fieldname])|int|abs, currency=doc.currency) }}
+ {% endif %}
+
+
+{%- endmacro -%}
+
+{%- macro render_taxes(df, doc) -%}
+ {%- set data = doc.get(df.fieldname)[df.start:df.end] -%}
+
+
+
+ {%- for charge in data -%}
+ {%- if (charge.tax_amount or doc.flags.print_taxes_with_zero_amount) and (not charge.included_in_print_rate or doc.flags.show_inclusive_tax_in_print) -%}
+
+
+ {{ charge.get_formatted("description") }}
+
+ {{ frappe.utils.fmt_money((charge.tax_amount)|int|abs, currency=doc.currency) }}
+
+
+ {%- endif -%}
+ {%- endfor -%}
+
+
+{%- endmacro -%}
+
+{%- macro render_table(df, doc) -%}
+ {%- set table_meta = frappe.get_meta(df.options) -%}
+ {%- set data = doc.get(df.fieldname)[df.start:df.end] -%}
+ {%- if doc.print_templates and
+ doc.print_templates.get(df.fieldname) -%}
+ {% include doc.print_templates[df.fieldname] %}
+ {%- else -%}
+ {%- if data -%}
+ {%- set visible_columns = get_visible_columns(doc.get(df.fieldname),
+ table_meta, df) -%}
+
+
+
+
+ {{ _("Sr") }}
+ {% for tdf in visible_columns %}
+ {% if (data and not data[0].flags.compact_item_print) or tdf.fieldname in doc.get(df.fieldname)[0].flags.compact_item_fields %}
+
+ {{ _(tdf.label) }}
+ {% endif %}
+ {% endfor %}
+
+
+
+ {% for d in data %}
+
+ {{ d.idx }}
+ {% for tdf in visible_columns %}
+ {% if not d.flags.compact_item_print or tdf.fieldname in doc.get(df.fieldname)[0].flags.compact_item_fields %}
+
+ {% if tdf.fieldtype == 'Currency' %}
+ {{ frappe.utils.fmt_money((d[tdf.fieldname])|int|abs, currency=doc.currency) }}
+ {% else %}
+ {{ print_value(tdf, d, doc, visible_columns) }}
+ {% endif %}
+ {% endif %}
+ {% endfor %}
+
+ {% endfor %}
+
+
+
+ {%- endif -%}
+ {%- endif -%}
+{%- endmacro -%}
+
+{% for page in layout %}
+
+
+
+ {% if print_settings.repeat_header_footer %}
+
+ {% endif %}
+
+ {% for section in page %}
+
+ {% if section.columns.fields %}
+ {%- if doc._line_breaks and loop.index != 1 -%}
{%- endif -%}
+ {%- if doc._show_section_headings and section.label and section.has_data -%}
+
{{ _(section.label) }}
+ {% endif %}
+ {%- endif -%}
+ {% for column in section.columns %}
+
+ {% for df in column.fields %}
+ {% if df.fieldname == 'taxes' %}
+ {{ render_taxes(df, doc) }}
+ {% elif df.fieldtype == 'Currency' %}
+ {{ render_currency(df, doc) }}
+ {% elif df.fieldtype =='Table' %}
+ {{ render_table(df, doc)}}
+ {% elif doc[df.fieldname] %}
+ {{ render_field(df, doc) }}
+ {% endif %}
+ {% endfor %}
+
+ {% endfor %}
+
+ {% endfor %}
+
+{% endfor %}
diff --git a/erpnext/accounts/print_format/sales_invoice_return/sales_invoice_return.json b/erpnext/accounts/print_format/sales_invoice_return/sales_invoice_return.json
new file mode 100644
index 0000000000..352b5498e6
--- /dev/null
+++ b/erpnext/accounts/print_format/sales_invoice_return/sales_invoice_return.json
@@ -0,0 +1,24 @@
+{
+ "align_labels_right": 1,
+ "creation": "2019-07-24 20:13:30.259953",
+ "custom_format": 0,
+ "default_print_language": "en-US",
+ "disabled": 0,
+ "doc_type": "Sales Invoice",
+ "docstatus": 0,
+ "doctype": "Print Format",
+ "font": "Default",
+ "html": "",
+ "idx": 0,
+ "line_breaks": 1,
+ "modified": "2019-07-24 20:13:30.259953",
+ "modified_by": "Administrator",
+ "module": "Accounts",
+ "name": "Sales Invoice Return",
+ "owner": "Administrator",
+ "print_format_builder": 0,
+ "print_format_type": "Jinja",
+ "raw_printing": 0,
+ "show_section_headings": 1,
+ "standard": "Yes"
+}
\ No newline at end of file
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index ca59a396b8..288aa082c5 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -60,7 +60,9 @@ class AccountsController(TransactionBase):
def validate(self):
- self.validate_qty_is_not_zero()
+ if not self.get('is_return'):
+ self.validate_qty_is_not_zero()
+
if self.get("_action") and self._action != "update_after_submit":
self.set_missing_values(for_validate=True)
diff --git a/erpnext/controllers/taxes_and_totals.py b/erpnext/controllers/taxes_and_totals.py
index 8d24e7a316..b774037266 100644
--- a/erpnext/controllers/taxes_and_totals.py
+++ b/erpnext/controllers/taxes_and_totals.py
@@ -81,7 +81,12 @@ class calculate_taxes_and_totals(object):
item.discount_amount = item.price_list_rate - item.rate
item.net_rate = item.rate
- item.amount = flt(item.rate * item.qty, item.precision("amount"))
+
+ if not item.qty and self.doc.is_return:
+ item.amount = flt(-1 * item.rate, item.precision("amount"))
+ else:
+ item.amount = flt(item.rate * item.qty, item.precision("amount"))
+
item.net_amount = item.amount
self._set_in_company_currency(item, ["price_list_rate", "rate", "net_rate", "amount", "net_amount"])
diff --git a/erpnext/public/js/controllers/taxes_and_totals.js b/erpnext/public/js/controllers/taxes_and_totals.js
index 91800cd9a9..7cf2181e42 100644
--- a/erpnext/public/js/controllers/taxes_and_totals.js
+++ b/erpnext/public/js/controllers/taxes_and_totals.js
@@ -92,7 +92,13 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
$.each(this.frm.doc["items"] || [], function(i, item) {
frappe.model.round_floats_in(item);
item.net_rate = item.rate;
- item.amount = flt(item.rate * item.qty, precision("amount", item));
+
+ if ((!item.qty) && me.frm.doc.is_return) {
+ item.amount = flt(item.rate * -1, precision("amount", item));
+ } else {
+ item.amount = flt(item.rate * item.qty, precision("amount", item));
+ }
+
item.net_amount = item.amount;
item.item_tax_amount = 0.0;
item.total_weight = flt(item.weight_per_unit * item.stock_qty);
From 5eac8703da409c7c540552eeda87456ffd02bf4c Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Wed, 31 Jul 2019 19:28:21 +0530
Subject: [PATCH 172/484] fix: create reverse expiry for back dated leaves
---
.../leave_encashment/leave_encashment.py | 30 ++++++++++++++-----
.../leave_encashment/test_leave_encashment.py | 1 -
2 files changed, 22 insertions(+), 9 deletions(-)
diff --git a/erpnext/hr/doctype/leave_encashment/leave_encashment.py b/erpnext/hr/doctype/leave_encashment/leave_encashment.py
index 70cd5780c8..c47ff85717 100644
--- a/erpnext/hr/doctype/leave_encashment/leave_encashment.py
+++ b/erpnext/hr/doctype/leave_encashment/leave_encashment.py
@@ -11,6 +11,7 @@ from erpnext.hr.utils import set_employee_name
from erpnext.hr.doctype.leave_application.leave_application import get_leave_balance_on
from erpnext.hr.doctype.salary_structure_assignment.salary_structure_assignment import get_assigned_salary_structure
from erpnext.hr.doctype.leave_ledger_entry.leave_ledger_entry import create_leave_ledger_entry
+from erpnext.hr.doctype.leave_allocation.leave_allocation import get_unused_leaves
class LeaveEncashment(Document):
def validate(self):
@@ -26,7 +27,7 @@ class LeaveEncashment(Document):
def on_submit(self):
if not self.leave_allocation:
- self.leave_allocation = self.get_leave_allocation()
+ self.leave_allocation = self.get_leave_allocation().get('name')
additional_salary = frappe.new_doc("Additional Salary")
additional_salary.company = frappe.get_value("Employee", self.employee, "company")
additional_salary.employee = self.employee
@@ -61,8 +62,9 @@ class LeaveEncashment(Document):
if not frappe.db.get_value("Leave Type", self.leave_type, 'allow_encashment'):
frappe.throw(_("Leave Type {0} is not encashable").format(self.leave_type))
- self.leave_balance = get_leave_balance_on(self.employee, self.leave_type,
- self.encashment_date or getdate(nowdate()), consider_all_leaves_in_the_allocation_period=True)
+ allocation = self.get_leave_allocation()
+
+ self.leave_balance = allocation.total_leaves_allocated - get_unused_leaves(self.employee, self.leave_type, allocation.from_date, self.encashment_date)
encashable_days = self.leave_balance - frappe.db.get_value('Leave Type', self.leave_type, 'encashment_threshold_days')
self.encashable_days = encashable_days if encashable_days > 0 else 0
@@ -70,15 +72,15 @@ class LeaveEncashment(Document):
per_day_encashment = frappe.db.get_value('Salary Structure', salary_structure , 'leave_encashment_amount_per_day')
self.encashment_amount = self.encashable_days * per_day_encashment if per_day_encashment > 0 else 0
- self.leave_allocation = self.get_leave_allocation()
+ self.leave_allocation = allocation.name
return True
def get_leave_allocation(self):
- leave_allocation = frappe.db.sql("""select name from `tabLeave Allocation` where '{0}'
+ leave_allocation = frappe.db.sql("""select name, to_date, total_leaves_allocated from `tabLeave Allocation` where '{0}'
between from_date and to_date and docstatus=1 and leave_type='{1}'
- and employee= '{2}'""".format(self.encashment_date or getdate(nowdate()), self.leave_type, self.employee))
+ and employee= '{2}'""".format(self.encashment_date or getdate(nowdate()), self.leave_type, self.employee), as_dict=1)
- return leave_allocation[0][0] if leave_allocation else None
+ return leave_allocation[0] if leave_allocation else None
def create_leave_ledger_entry(self, submit=True):
args = frappe._dict(
@@ -87,4 +89,16 @@ class LeaveEncashment(Document):
to_date=self.encashment_date,
is_carry_forward=0
)
- create_leave_ledger_entry(self, args, submit)
\ No newline at end of file
+ create_leave_ledger_entry(self, args, submit)
+
+ # create reverse entry for expired leaves
+ to_date = self.get_leave_allocation().get('to_date')
+ if to_date < getdate(nowdate()):
+ args = frappe._dict(
+ leaves=self.encashable_days,
+ from_date=to_date,
+ to_date=to_date,
+ is_carry_forward=0
+ )
+ create_leave_ledger_entry(self, args, submit)
+
diff --git a/erpnext/hr/doctype/leave_encashment/test_leave_encashment.py b/erpnext/hr/doctype/leave_encashment/test_leave_encashment.py
index 2daeffcffe..e5bd170bc4 100644
--- a/erpnext/hr/doctype/leave_encashment/test_leave_encashment.py
+++ b/erpnext/hr/doctype/leave_encashment/test_leave_encashment.py
@@ -38,7 +38,6 @@ class TestLeaveEncashment(unittest.TestCase):
self.leave_period = create_leave_period(add_months(today(), -3), add_months(today(), 3))
self.leave_period.grant_leave_allocation(employee=self.employee)
-
def test_leave_balance_value_and_amount(self):
frappe.db.sql('''delete from `tabLeave Encashment`''')
leave_encashment = frappe.get_doc(dict(
From 8fb600162e1f93c0adaffcbff567b4821d853635 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Wed, 31 Jul 2019 19:31:26 +0530
Subject: [PATCH 173/484] fix: remove all leaves via scheduler
---
.../leave_allocation/leave_allocation.js | 7 +-
.../leave_allocation/leave_allocation.py | 96 +++++++------------
.../leave_allocation/test_leave_allocation.py | 4 +-
.../leave_application/leave_application.py | 2 +-
.../leave_ledger_entry/leave_ledger_entry.py | 91 ++++++++++++------
.../v12_0/generate_leave_ledger_entries.py | 3 +-
6 files changed, 107 insertions(+), 96 deletions(-)
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.js b/erpnext/hr/doctype/leave_allocation/leave_allocation.js
index 7c3e1e44fa..8c910a200a 100755
--- a/erpnext/hr/doctype/leave_allocation/leave_allocation.js
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.js
@@ -35,8 +35,11 @@ frappe.ui.form.on("Leave Allocation", {
expire_allocation: function(frm) {
frappe.call({
- method: 'expire_current_allocation',
- doc: frm.doc,
+ method: 'erpnext.hr.doctype.leave_ledger_entry.leave_ledger_entry.expire_allocation',
+ args: {
+ 'allocation': frm.doc,
+ 'expiry_date': frappe.datetime.get_today()
+ },
freeze: true,
callback: function(r){
if(!r.exc){
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.py b/erpnext/hr/doctype/leave_allocation/leave_allocation.py
index 67f30b5816..2374e469a5 100755
--- a/erpnext/hr/doctype/leave_allocation/leave_allocation.py
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.py
@@ -7,7 +7,7 @@ from frappe.utils import flt, date_diff, formatdate, add_days, today
from frappe import _
from frappe.model.document import Document
from erpnext.hr.utils import set_employee_name, get_leave_period
-from erpnext.hr.doctype.leave_ledger_entry.leave_ledger_entry import create_leave_ledger_entry
+from erpnext.hr.doctype.leave_ledger_entry.leave_ledger_entry import expire_allocation, create_leave_ledger_entry
class OverlapError(frappe.ValidationError): pass
class BackDatedAllocationError(frappe.ValidationError): pass
@@ -42,7 +42,11 @@ class LeaveAllocation(Document):
def on_submit(self):
self.create_leave_ledger_entry()
- self.expire_previous_allocation()
+
+ # expire all unused leaves in the ledger on creation of carry forward allocation
+ allocation = get_previous_allocation(self.from_date, self.leave_type, self.employee)
+ if self.carry_forward and allocation:
+ expire_allocation(allocation)
def on_cancel(self):
self.create_leave_ledger_entry(submit=False)
@@ -128,55 +132,17 @@ class LeaveAllocation(Document):
)
create_leave_ledger_entry(self, args, submit)
- def expire_current_allocation(self):
- ''' expires allocation '''
- date = self.to_date
- leaves = get_unused_leaves(self.employee, self.leave_type, date)
- ref_name = self.name
-
- if leaves:
- expiry_date = today()
- args = dict(
- leaves=flt(leaves) * -1,
- transaction_name=ref_name,
- from_date=expiry_date,
- to_date=expiry_date,
- is_carry_forward=0,
- is_expired=1
- )
- create_leave_ledger_entry(self, args)
-
- frappe.db.set_value("Leave Allocation", self.name, "expired", 1)
-
- def expire_previous_allocation(self):
- date = self.from_date
- leaves = get_unused_leaves(self.employee, self.leave_type, date)
- ref_name = self.get_previous_allocation()
-
- if leaves:
- expiry_date = add_days(self.from_date, -1)
- args = dict(
- leaves=flt(leaves) * -1,
- transaction_name=ref_name,
- from_date=expiry_date,
- to_date=expiry_date,
- is_carry_forward=0,
- is_expired=1
- )
- create_leave_ledger_entry(self, args)
-
- frappe.db.set_value("Leave Allocation", ref_name, "expired", 1)
-
- def get_previous_allocation(self):
- return frappe.db.get_value("Leave Allocation",
- filters={
- 'to_date': ("<", self.from_date),
- 'leave_type': self.leave_type,
- 'employee': self.employee,
- 'docstatus': 1
- },
- order_by='to_date DESC',
- fieldname=['name'])
+def get_previous_allocation(from_date, leave_type, employee):
+ ''' Returns document properties of previous allocation '''
+ return frappe.db.get_value("Leave Allocation",
+ filters={
+ 'to_date': ("<", from_date),
+ 'leave_type': leave_type,
+ 'employee': employee,
+ 'docstatus': 1
+ },
+ order_by='to_date DESC',
+ fieldname=['name', 'from_date', 'to_date'], as_dict=1)
def get_leave_allocation_for_period(employee, leave_type, from_date, to_date):
leave_allocated = 0
@@ -203,21 +169,27 @@ def get_leave_allocation_for_period(employee, leave_type, from_date, to_date):
@frappe.whitelist()
def get_carry_forwarded_leaves(employee, leave_type, date, carry_forward=None):
- carry_forwarded_leaves = 0
- if carry_forward:
+ ''' Returns carry forwarded leaves for the given employee '''
+ carry_forwarded_leaves = 0.0
+ previous_allocation = get_previous_allocation(date, leave_type, employee)
+ if carry_forward and previous_allocation:
validate_carry_forward(leave_type)
- carry_forwarded_leaves = get_unused_leaves(employee, leave_type, date)
+ carry_forwarded_leaves = get_unused_leaves(employee, leave_type, previous_allocation.from_date, previous_allocation.to_date)
return carry_forwarded_leaves
-def get_unused_leaves(employee, leave_type, date):
- return frappe.db.get_value("Leave Ledger Entry", filters={
- "to_date": ("<=", date),
- "employee": employee,
- "docstatus": 1,
- "leave_type": leave_type,
- "is_lwp": 0
- }, fieldname=['SUM(leaves)'])
+def get_unused_leaves(employee, leave_type, from_date, to_date):
+ ''' Returns unused leaves between the given period while skipping leave allocation expiry '''
+ leaves = frappe.get_all("Leave Ledger Entry", filters={
+ 'employee': employee,
+ 'leave_type': leave_type,
+ 'from_date': ('>=', from_date),
+ 'to_date': ('<=', to_date)
+ }, or_filters={
+ 'is_expired': 0,
+ 'is_carry_forward': 1
+ }, fields=['sum(leaves) as leaves'])
+ return flt(leaves[0]['leaves'])
def validate_carry_forward(leave_type):
if not frappe.db.get_value("Leave Type", leave_type, "is_carry_forward"):
diff --git a/erpnext/hr/doctype/leave_allocation/test_leave_allocation.py b/erpnext/hr/doctype/leave_allocation/test_leave_allocation.py
index dfa64db416..4f4e0ab1fc 100644
--- a/erpnext/hr/doctype/leave_allocation/test_leave_allocation.py
+++ b/erpnext/hr/doctype/leave_allocation/test_leave_allocation.py
@@ -3,7 +3,7 @@ import frappe
import unittest
from frappe.utils import nowdate, add_months, getdate, add_days
from erpnext.hr.doctype.leave_type.test_leave_type import create_leave_type
-from erpnext.hr.doctype.leave_ledger_entry.leave_ledger_entry import process_expired_allocation
+from erpnext.hr.doctype.leave_ledger_entry.leave_ledger_entry import process_expired_allocation, expire_allocation
class TestLeaveAllocation(unittest.TestCase):
def test_overlapping_allocation(self):
@@ -108,6 +108,8 @@ class TestLeaveAllocation(unittest.TestCase):
carry_forward=1)
leave_allocation.submit()
+ expire_allocation(leave_allocation)
+
leave_allocation = create_leave_allocation(
leave_type="_Test_CF_leave_expiry",
from_date=add_days(nowdate(), -90),
diff --git a/erpnext/hr/doctype/leave_application/leave_application.py b/erpnext/hr/doctype/leave_application/leave_application.py
index 8f02ec0f92..36a4145467 100755
--- a/erpnext/hr/doctype/leave_application/leave_application.py
+++ b/erpnext/hr/doctype/leave_application/leave_application.py
@@ -198,7 +198,7 @@ class LeaveApplication(Document):
if not is_lwp(self.leave_type):
self.leave_balance = get_leave_balance_on(self.employee, self.leave_type, self.from_date, self.to_date,
consider_all_leaves_in_the_allocation_period=True)
- if self.status != "Rejected" and self.leave_balance < self.total_leave_days:
+ if self.status != "Rejected" and (self.leave_balance < self.total_leave_days or not self.leave_balance):
if frappe.db.get_value("Leave Type", self.leave_type, "allow_negative"):
frappe.msgprint(_("Note: There is not enough leave balance for Leave Type {0}")
.format(self.leave_type))
diff --git a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
index 135b750bf9..d19e15cf1a 100644
--- a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
+++ b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
@@ -6,29 +6,31 @@ from __future__ import unicode_literals
import frappe
from frappe.model.document import Document
from frappe import _
-from frappe.utils import add_days, today, flt, DATE_FORMAT
+from frappe.utils import add_days, today, flt, DATE_FORMAT, getdate
class LeaveLedgerEntry(Document):
def validate(self):
- if self.from_date > self.to_date:
+ if getdate(self.from_date) > getdate(self.to_date):
frappe.throw(_("To date needs to be before from date"))
def on_cancel(self):
# allow cancellation of expiry leaves
- if not self.is_expired:
+ if self.is_expired:
+ frappe.db.set_value("Leave Allocation", self.transaction_name, "expired", 0)
+ else:
frappe.throw(_("Only expired allocation can be cancelled"))
def validate_leave_allocation_against_leave_application(ledger):
''' Checks that leave allocation has no leave application against it '''
leave_application_records = frappe.db.sql_list("""
SELECT transaction_name
- FROM `tabLeave Application`
+ FROM `tabLeave Ledger Entry`
WHERE
- employee=%s,
- leave_type=%s,
- transaction_type='Leave Application',
- from_date>=%s,
- to_date<=%s
+ employee=%s
+ AND leave_type=%s
+ AND transaction_type='Leave Application'
+ AND from_date>=%s
+ AND to_date<=%s
""", (ledger.employee, ledger.leave_type, ledger.from_date, ledger.to_date))
if leave_application_records:
@@ -48,6 +50,7 @@ def create_leave_ledger_entry(ref_doc, args, submit=True):
is_lwp=0
)
ledger.update(args)
+
if submit:
frappe.get_doc(ledger).submit()
else:
@@ -91,40 +94,70 @@ def process_expired_allocation():
if leave_type_records:
leave_type = [record[0] for record in leave_type_records]
- expired_allocation = frappe.get_all("Leave Ledger Entry",
+ expired_allocation = frappe.get_all("Leave Ledger Entry",
+ fields=['leaves', 'to_date', 'employee', 'leave_type', 'is_carry_forward', 'transaction_name as name', 'transaction_type'],
filters={
'to_date': add_days(today(), -1),
'transaction_type': 'Leave Allocation',
- 'is_carry_forward': 1,
+ },
+ or_filters={
+ 'is_carry_forward': 0,
'leave_type': ('in', leave_type)
- }, fields=['leaves', 'to_date', 'employee', 'leave_type'])
+ })
if expired_allocation:
create_expiry_ledger_entry(expired_allocation)
def create_expiry_ledger_entry(expired_allocation):
- ''' Create expiry ledger entry for carry forwarded leaves '''
+ ''' Create ledger entry for expired allocation '''
for allocation in expired_allocation:
- leaves_taken = get_leaves_taken(allocation)
- leaves = flt(allocation.leaves) + flt(leaves_taken)
+ if allocation.is_carry_forward:
+ expire_carried_forward_allocation(allocation)
+ else:
+ expire_allocation(allocation)
- if leaves > 0:
- args = frappe._dict(
- leaves=allocation.leaves * -1,
- to_date=allocation.to_date,
- is_carry_forward=1,
- is_expired=1,
- from_date=allocation.to_date
- )
- create_leave_ledger_entry(allocation, args)
-
-def get_leaves_taken(allocation):
+def get_remaining_leaves(allocation):
+ ''' Returns remaining leaves from the given allocation '''
return frappe.db.get_value("Leave Ledger Entry",
filters={
'employee': allocation.employee,
'leave_type': allocation.leave_type,
- 'from_date': ('>=', allocation.from_date),
'to_date': ('<=', allocation.to_date),
- 'transaction_type': 'Leave application'
- }, fieldname=['SUM(leaves)'])
\ No newline at end of file
+ }, fieldname=['SUM(leaves)'])
+
+@frappe.whitelist()
+def expire_allocation(allocation, expiry_date=None):
+ ''' expires allocation '''
+ leaves = get_remaining_leaves(allocation)
+ expiry_date = expiry_date if expiry_date else allocation.to_date
+
+ if leaves:
+ args = dict(
+ leaves=flt(leaves) * -1,
+ transaction_name=allocation.name,
+ from_date=expiry_date,
+ to_date=expiry_date,
+ is_carry_forward=0,
+ is_expired=1
+ )
+ create_leave_ledger_entry(allocation, args)
+
+ frappe.db.set_value("Leave Allocation", allocation.name, "expired", 1)
+
+def expire_carried_forward_allocation(allocation):
+ ''' Expires remaining leaves in the on carried forward allocation '''
+ from erpnext.hr.doctype.leave_application.leave_application import get_leaves_for_period
+ leaves_taken = get_leaves_for_period(allocation.employee, allocation.leave_type, allocation.from_date, allocation.to_date)
+ leaves = flt(allocation.leaves) + flt(leaves_taken)
+ if leaves > 0:
+ args = frappe._dict(
+ transaction_name=allocation.name,
+ transaction_type="Leave Allocation",
+ leaves=allocation.leaves * -1,
+ is_carry_forward=allocation.is_carry_forward,
+ is_expired=1,
+ from_date=allocation.to_date,
+ to_date=allocation.to_date
+ )
+ create_leave_ledger_entry(allocation, args)
\ No newline at end of file
diff --git a/erpnext/patches/v12_0/generate_leave_ledger_entries.py b/erpnext/patches/v12_0/generate_leave_ledger_entries.py
index f2a798e1f8..7dfdcc162b 100644
--- a/erpnext/patches/v12_0/generate_leave_ledger_entries.py
+++ b/erpnext/patches/v12_0/generate_leave_ledger_entries.py
@@ -48,13 +48,14 @@ def generate_encashment_leave_ledger_entries():
def generate_expiry_allocation_ledger_entries():
''' fix ledger entries for missing leave allocation transaction '''
+ from erpnext.hr.doctype.leave_ledger_entry.leave_ledger_entry import expire_allocation
allocation_list = get_allocation_records()
for allocation in allocation_list:
if not frappe.db.exists("Leave Ledger Entry", {'transaction_type': 'Leave Allocation', 'transaction_name': allocation.name, 'is_expired': 1}):
allocation.update(dict(doctype="Leave Allocation"))
allocation_obj = frappe.get_doc(allocation)
- allocation_obj.expire_previous_allocation()
+ expire_allocation(allocation_obj)
def get_allocation_records():
return frappe.db.sql("""
From fa9111ebe276395aeb35a8b73bc490bcde257d4b Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Thu, 1 Aug 2019 11:07:14 +0530
Subject: [PATCH 174/484] fix: Add and rename some fields
- Add ability to create delivery note from pick ticket
- Minor fix related to create button
---
.../doctype/sales_order/sales_order.js | 5 ++-
.../doctype/sales_order/sales_order.py | 3 +-
.../stock/doctype/pick_ticket/pick_ticket.js | 14 +++++--
.../doctype/pick_ticket/pick_ticket.json | 42 +++++++++----------
.../stock/doctype/pick_ticket/pick_ticket.py | 39 +++++++++++++----
.../doctype/pick_ticket/test_pick_ticket.py | 36 ++++++----------
.../pick_ticket_item/pick_ticket_item.json | 3 +-
.../pick_ticket_reference_item.json | 10 ++++-
8 files changed, 88 insertions(+), 64 deletions(-)
diff --git a/erpnext/selling/doctype/sales_order/sales_order.js b/erpnext/selling/doctype/sales_order/sales_order.js
index 89739cc633..6e6b730bc9 100644
--- a/erpnext/selling/doctype/sales_order/sales_order.js
+++ b/erpnext/selling/doctype/sales_order/sales_order.js
@@ -102,7 +102,6 @@ frappe.ui.form.on("Sales Order Item", {
erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend({
onload: function(doc, dt, dn) {
this._super();
- this.frm.add_custom_button(__('Pick Ticket'), () => this.make_pick_ticket(), __('Create'));
},
refresh: function(doc, dt, dn) {
@@ -110,7 +109,9 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
this._super();
let allow_delivery = false;
- if(doc.docstatus==1) {
+ if (doc.docstatus==1) {
+ this.frm.add_custom_button(__('Pick Ticket'), () => this.make_pick_ticket(), __('Create'));
+
if(this.frm.has_perm("submit")) {
if(doc.status === 'On Hold') {
// un-hold
diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py
index 97a9739e79..5e9a35883e 100755
--- a/erpnext/selling/doctype/sales_order/sales_order.py
+++ b/erpnext/selling/doctype/sales_order/sales_order.py
@@ -1011,7 +1011,8 @@ def make_pick_ticket(source_name, target_doc=None):
"field_map": {
"item_code": "item",
"parenttype": "reference_doctype",
- "parent": "reference_name"
+ "parent": "reference_name",
+ "name": "reference_document_item"
},
},
}, target_doc)
diff --git a/erpnext/stock/doctype/pick_ticket/pick_ticket.js b/erpnext/stock/doctype/pick_ticket/pick_ticket.js
index 5903e6fea0..5e5881ed62 100644
--- a/erpnext/stock/doctype/pick_ticket/pick_ticket.js
+++ b/erpnext/stock/doctype/pick_ticket/pick_ticket.js
@@ -3,7 +3,7 @@
frappe.ui.form.on('Pick Ticket', {
setup: (frm) => {
- frm.set_query('group_warehouse', () => {
+ frm.set_query('parent_warehouse', () => {
return {
filters: {
'is_group': 1,
@@ -13,7 +13,8 @@ frappe.ui.form.on('Pick Ticket', {
});
},
refresh: (frm) => {
- this.frm.add_custom_button(__('Sales Order'), function() {
+ frm.add_custom_button(__('Delivery Note'), () => frm.trigger('make_delivery_note'), __('Create'));
+ frm.add_custom_button(__('Sales Order'), function() {
erpnext.utils.map_current_doc({
method: "erpnext.selling.doctype.sales_order.sales_order.make_pick_ticket",
source_doctype: "Sales Order",
@@ -27,11 +28,16 @@ frappe.ui.form.on('Pick Ticket', {
});
}, __("Get items from"));
- if (frm.doc.reference_document_items.length) {
+ if (frm.doc.reference_items && frm.doc.reference_items.length) {
frm.add_custom_button(__('Get Item Locations'), () => {
frm.call('set_item_locations');
});
}
},
-
+ make_delivery_note(frm) {
+ frappe.model.open_mapped_doc({
+ method: "erpnext.stock.doctype.pick_ticket.pick_ticket.make_delivery_note",
+ frm: frm
+ });
+ },
});
diff --git a/erpnext/stock/doctype/pick_ticket/pick_ticket.json b/erpnext/stock/doctype/pick_ticket/pick_ticket.json
index 935192568e..d8a8e0175c 100644
--- a/erpnext/stock/doctype/pick_ticket/pick_ticket.json
+++ b/erpnext/stock/doctype/pick_ticket/pick_ticket.json
@@ -7,27 +7,13 @@
"field_order": [
"company",
"column_break_4",
- "group_warehouse",
+ "parent_warehouse",
"section_break_4",
- "reference_document_items",
+ "reference_items",
"section_break_6",
- "items"
+ "item_locations"
],
"fields": [
- {
- "fieldname": "items",
- "fieldtype": "Table",
- "label": "Items Locations",
- "options": "Pick Ticket Item",
- "read_only": 1
- },
- {
- "description": "Items under this warehouse will be suggested",
- "fieldname": "group_warehouse",
- "fieldtype": "Link",
- "label": "Group Warehouse",
- "options": "Warehouse"
- },
{
"fieldname": "company",
"fieldtype": "Link",
@@ -44,17 +30,29 @@
},
{
"fieldname": "section_break_4",
- "fieldtype": "Section Break",
- "label": "Reference Items"
+ "fieldtype": "Section Break"
},
{
- "fieldname": "reference_document_items",
+ "description": "Items under this warehouse will be suggested",
+ "fieldname": "parent_warehouse",
+ "fieldtype": "Link",
+ "label": "Parent Warehouse",
+ "options": "Warehouse"
+ },
+ {
+ "fieldname": "item_locations",
"fieldtype": "Table",
- "label": "Reference Document Items",
+ "label": "Item Locations",
+ "options": "Pick Ticket Item"
+ },
+ {
+ "fieldname": "reference_items",
+ "fieldtype": "Table",
+ "label": "Items To Be Picked",
"options": "Pick Ticket Reference Item"
}
],
- "modified": "2019-07-26 12:06:08.941760",
+ "modified": "2019-08-01 10:50:17.055509",
"modified_by": "Administrator",
"module": "Stock",
"name": "Pick Ticket",
diff --git a/erpnext/stock/doctype/pick_ticket/pick_ticket.py b/erpnext/stock/doctype/pick_ticket/pick_ticket.py
index a1adf9fee4..16f6d7a5df 100644
--- a/erpnext/stock/doctype/pick_ticket/pick_ticket.py
+++ b/erpnext/stock/doctype/pick_ticket/pick_ticket.py
@@ -5,23 +5,24 @@
from __future__ import unicode_literals
import frappe
from frappe.model.document import Document
+from frappe.model.mapper import get_mapped_doc
class PickTicket(Document):
def set_item_locations(self):
- reference_items = self.reference_document_items
+ reference_items = self.reference_items
from_warehouses = None
- if self.group_warehouse:
- from_warehouses = frappe.db.get_descendants('Warehouse', self.group_warehouse)
+ if self.parent_warehouse:
+ from_warehouses = frappe.db.get_descendants('Warehouse', self.parent_warehouse)
# Reset
- self.delete_key('items')
+ self.delete_key('item_locations')
for item in reference_items:
data = get_items_with_warehouse_and_quantity(item, from_warehouses)
for item_info in data:
- print(self.append('items', item_info))
+ print(self.append('item_locations', item_info))
- for item_doc in self.get('items'):
+ for item_doc in self.get('item_locations'):
if frappe.get_cached_value('Item', item_doc.item, 'has_serial_no'):
set_serial_nos(item_doc)
elif frappe.get_cached_value('Item', item_doc.item, 'has_batch_no'):
@@ -40,7 +41,8 @@ def get_items_with_warehouse_and_quantity(item_doc, from_warehouses):
'qty': qty,
'warehouse': item_location.warehouse,
'reference_doctype': item_doc.reference_doctype,
- 'reference_name': item_doc.reference_name
+ 'reference_name': item_doc.reference_name,
+ 'reference_document_item': item_doc.reference_document_item,
})
remaining_qty -= qty
@@ -120,8 +122,29 @@ def set_batch_no(item_doc, parent_doc):
'qty': required_qty,
'warehouse': item_doc.warehouse,
'reference_doctype': item_doc.reference_doctype,
- 'reference_name': item_doc.reference_name
+ 'reference_name': item_doc.reference_name,
+ 'reference_document_item': item_doc.reference_document_item,
})
if required_qty:
frappe.msgprint('No batches found for {} qty of {}. Skipping...'.format(required_qty, item_doc.item))
parent_doc.remove(item_doc)
+
+@frappe.whitelist()
+def make_delivery_note(source_name, target_doc=None):
+ target_doc = get_mapped_doc("Pick Ticket", source_name, {
+ "Pick Ticket": {
+ "doctype": "Delivery Note",
+ # "validation": {
+ # "docstatus": ["=", 1]
+ # }
+ },
+ "Pick Ticket Item": {
+ "doctype": "Delivery Note Item",
+ "field_map": {
+ "item": "item_code",
+ "reference_docname": "against_sales_order",
+ },
+ },
+ }, target_doc)
+
+ return target_doc
\ No newline at end of file
diff --git a/erpnext/stock/doctype/pick_ticket/test_pick_ticket.py b/erpnext/stock/doctype/pick_ticket/test_pick_ticket.py
index 3a0492a2dc..5a41bc9f2c 100644
--- a/erpnext/stock/doctype/pick_ticket/test_pick_ticket.py
+++ b/erpnext/stock/doctype/pick_ticket/test_pick_ticket.py
@@ -14,7 +14,7 @@ class TestPickTicket(unittest.TestCase):
pick_ticket = frappe.get_doc({
'doctype': 'Pick Ticket',
'company': '_Test Company',
- 'reference_document_items': [{
+ 'reference_items': [{
'item': '_Test Item Home Desktop 100',
'reference_doctype': 'Sales Order',
'qty': 5,
@@ -24,15 +24,15 @@ class TestPickTicket(unittest.TestCase):
pick_ticket.set_item_locations()
- self.assertEqual(pick_ticket.items[0].item, '_Test Item Home Desktop 100')
- self.assertEqual(pick_ticket.items[0].warehouse, '_Test Warehouse - _TC')
- self.assertEqual(pick_ticket.items[0].qty, 5)
+ self.assertEqual(pick_ticket.items_locations[0].item, '_Test Item Home Desktop 100')
+ self.assertEqual(pick_ticket.items_locations[0].warehouse, '_Test Warehouse - _TC')
+ self.assertEqual(pick_ticket.items_locations[0].qty, 5)
def test_pick_ticket_skips_out_of_stock_item(self):
pick_ticket = frappe.get_doc({
'doctype': 'Pick Ticket',
'company': '_Test Company',
- 'reference_document_items': [{
+ 'reference_items': [{
'item': '_Test Item Warehouse Group Wise Reorder',
'reference_doctype': 'Sales Order',
'qty': 1000,
@@ -42,9 +42,9 @@ class TestPickTicket(unittest.TestCase):
pick_ticket.set_item_locations()
- self.assertEqual(pick_ticket.items[0].item, '_Test Item Warehouse Group Wise Reorder')
- self.assertEqual(pick_ticket.items[0].warehouse, '_Test Warehouse Group-C1 - _TC')
- self.assertEqual(pick_ticket.items[0].qty, 30)
+ self.assertEqual(pick_ticket.items_locations[0].item, '_Test Item Warehouse Group Wise Reorder')
+ self.assertEqual(pick_ticket.items_locations[0].warehouse, '_Test Warehouse Group-C1 - _TC')
+ self.assertEqual(pick_ticket.items_locations[0].qty, 30)
def test_pick_ticket_skips_items_in_expired_batch(self):
@@ -68,7 +68,7 @@ class TestPickTicket(unittest.TestCase):
pick_ticket = frappe.get_doc({
'doctype': 'Pick Ticket',
'company': '_Test Company',
- 'reference_document_items': [{
+ 'reference_items': [{
'item': '_Test Serialized Item',
'reference_doctype': 'Sales Order',
'qty': 1000,
@@ -77,26 +77,16 @@ class TestPickTicket(unittest.TestCase):
})
pick_ticket.set_item_locations()
- self.assertEqual(pick_ticket.items[0].item, '_Test Serialized Item')
- self.assertEqual(pick_ticket.items[0].warehouse, '_Test Warehouse Group-C1 - _TC')
- self.assertEqual(pick_ticket.items[0].qty, 30)
- self.assertEqual(pick_ticket.items[0].serial_no, 30)
+ self.assertEqual(pick_ticket.items_locations[0].item, '_Test Serialized Item')
+ self.assertEqual(pick_ticket.items_locations[0].warehouse, '_Test Warehouse Group-C1 - _TC')
+ self.assertEqual(pick_ticket.items_locations[0].qty, 30)
+ self.assertEqual(pick_ticket.items_locations[0].serial_no, 30)
def test_pick_ticket_for_multiple_reference_doctypes(self):
pass
-# def create_new_pick_ticket():
-# pass
-# doc = frappe.new_doc('Pick Ticket')
-# doc.items.append({
-# 'item': '_Test Warehouse - _TC',
-# ''
-# })
-
-
-
## records required
'''
diff --git a/erpnext/stock/doctype/pick_ticket_item/pick_ticket_item.json b/erpnext/stock/doctype/pick_ticket_item/pick_ticket_item.json
index 0a65eed376..67a7e9caa5 100644
--- a/erpnext/stock/doctype/pick_ticket_item/pick_ticket_item.json
+++ b/erpnext/stock/doctype/pick_ticket_item/pick_ticket_item.json
@@ -68,7 +68,6 @@
{
"fieldname": "reference_document_item",
"fieldtype": "Data",
- "hidden": 1,
"label": "Reference Document Item",
"read_only": 1
},
@@ -130,7 +129,7 @@
}
],
"istable": 1,
- "modified": "2019-07-30 09:28:44.969479",
+ "modified": "2019-07-30 23:47:53.566473",
"modified_by": "Administrator",
"module": "Stock",
"name": "Pick Ticket Item",
diff --git a/erpnext/stock/doctype/pick_ticket_reference_item/pick_ticket_reference_item.json b/erpnext/stock/doctype/pick_ticket_reference_item/pick_ticket_reference_item.json
index ae7ea3567e..c31e2bcd23 100644
--- a/erpnext/stock/doctype/pick_ticket_reference_item/pick_ticket_reference_item.json
+++ b/erpnext/stock/doctype/pick_ticket_reference_item/pick_ticket_reference_item.json
@@ -7,7 +7,8 @@
"item",
"qty",
"reference_doctype",
- "reference_name"
+ "reference_name",
+ "reference_document_item"
],
"fields": [
{
@@ -34,10 +35,15 @@
"fieldtype": "Float",
"in_list_view": 1,
"label": "Qty"
+ },
+ {
+ "fieldname": "reference_document_item",
+ "fieldtype": "Data",
+ "label": "Reference Document Item"
}
],
"istable": 1,
- "modified": "2019-07-26 12:17:52.142186",
+ "modified": "2019-07-30 23:43:30.901151",
"modified_by": "Administrator",
"module": "Stock",
"name": "Pick Ticket Reference Item",
From fbcc56536b36c72e5d97a66e1b1d22f6bd03a982 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Thu, 1 Aug 2019 12:05:20 +0530
Subject: [PATCH 175/484] fix: Rename Pick TIcket -> Pick List
---
.../doctype/sales_order/sales_order.js | 2 +-
.../doctype/sales_order/sales_order.py | 4 +-
.../{pick_ticket => pick_list}/__init__.py | 0
.../pick_ticket.js => pick_list/pick_list.js} | 6 +-
.../pick_list.json} | 6 +-
.../pick_ticket.py => pick_list/pick_list.py} | 8 +-
.../stock/doctype/pick_list/test_pick_list.py | 100 ++++++++++++++++++
.../pick_list_item}/__init__.py | 0
.../pick_list_item}/pick_ticket_item.json | 2 +-
.../pick_list_item}/pick_ticket_item.py | 2 +-
.../pick_list_reference_item/__init__.py | 0
.../pick_list_reference_item.js} | 2 +-
.../pick_list_reference_item.json} | 2 +-
.../pick_list_reference_item.py} | 2 +-
.../doctype/pick_ticket/test_pick_ticket.py | 100 ------------------
15 files changed, 118 insertions(+), 118 deletions(-)
rename erpnext/stock/doctype/{pick_ticket => pick_list}/__init__.py (100%)
rename erpnext/stock/doctype/{pick_ticket/pick_ticket.js => pick_list/pick_list.js} (88%)
rename erpnext/stock/doctype/{pick_ticket/pick_ticket.json => pick_list/pick_list.json} (93%)
rename erpnext/stock/doctype/{pick_ticket/pick_ticket.py => pick_list/pick_list.py} (97%)
create mode 100644 erpnext/stock/doctype/pick_list/test_pick_list.py
rename erpnext/stock/doctype/{pick_ticket_item => pick_list_item/pick_list_item}/__init__.py (100%)
rename erpnext/stock/doctype/{pick_ticket_item => pick_list_item/pick_list_item}/pick_ticket_item.json (98%)
rename erpnext/stock/doctype/{pick_ticket_item => pick_list_item/pick_list_item}/pick_ticket_item.py (88%)
create mode 100644 erpnext/stock/doctype/pick_list_reference_item/__init__.py
rename erpnext/stock/doctype/{pick_ticket_reference_item/pick_ticket_reference_item.js => pick_list_reference_item/pick_list_reference_item.js} (76%)
rename erpnext/stock/doctype/{pick_ticket_reference_item/pick_ticket_reference_item.json => pick_list_reference_item/pick_list_reference_item.json} (96%)
rename erpnext/stock/doctype/{pick_ticket_reference_item/pick_ticket_reference_item.py => pick_list_reference_item/pick_list_reference_item.py} (85%)
delete mode 100644 erpnext/stock/doctype/pick_ticket/test_pick_ticket.py
diff --git a/erpnext/selling/doctype/sales_order/sales_order.js b/erpnext/selling/doctype/sales_order/sales_order.js
index 6e6b730bc9..136ff55344 100644
--- a/erpnext/selling/doctype/sales_order/sales_order.js
+++ b/erpnext/selling/doctype/sales_order/sales_order.js
@@ -110,7 +110,7 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
let allow_delivery = false;
if (doc.docstatus==1) {
- this.frm.add_custom_button(__('Pick Ticket'), () => this.make_pick_ticket(), __('Create'));
+ this.frm.add_custom_button(__('Pick List'), () => this.make_pick_ticket(), __('Create'));
if(this.frm.has_perm("submit")) {
if(doc.status === 'On Hold') {
diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py
index 5e9a35883e..1d636e3c26 100755
--- a/erpnext/selling/doctype/sales_order/sales_order.py
+++ b/erpnext/selling/doctype/sales_order/sales_order.py
@@ -1001,13 +1001,13 @@ def make_inter_company_purchase_order(source_name, target_doc=None):
def make_pick_ticket(source_name, target_doc=None):
doc = get_mapped_doc("Sales Order", source_name, {
"Sales Order": {
- "doctype": "Pick Ticket",
+ "doctype": "Pick List",
"validation": {
"docstatus": ["=", 1]
}
},
"Sales Order Item": {
- "doctype": "Pick Ticket Reference Item",
+ "doctype": "Pick List Reference Item",
"field_map": {
"item_code": "item",
"parenttype": "reference_doctype",
diff --git a/erpnext/stock/doctype/pick_ticket/__init__.py b/erpnext/stock/doctype/pick_list/__init__.py
similarity index 100%
rename from erpnext/stock/doctype/pick_ticket/__init__.py
rename to erpnext/stock/doctype/pick_list/__init__.py
diff --git a/erpnext/stock/doctype/pick_ticket/pick_ticket.js b/erpnext/stock/doctype/pick_list/pick_list.js
similarity index 88%
rename from erpnext/stock/doctype/pick_ticket/pick_ticket.js
rename to erpnext/stock/doctype/pick_list/pick_list.js
index 5e5881ed62..4cf4cdf78a 100644
--- a/erpnext/stock/doctype/pick_ticket/pick_ticket.js
+++ b/erpnext/stock/doctype/pick_list/pick_list.js
@@ -1,7 +1,7 @@
// Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
-frappe.ui.form.on('Pick Ticket', {
+frappe.ui.form.on('Pick List', {
setup: (frm) => {
frm.set_query('parent_warehouse', () => {
return {
@@ -16,7 +16,7 @@ frappe.ui.form.on('Pick Ticket', {
frm.add_custom_button(__('Delivery Note'), () => frm.trigger('make_delivery_note'), __('Create'));
frm.add_custom_button(__('Sales Order'), function() {
erpnext.utils.map_current_doc({
- method: "erpnext.selling.doctype.sales_order.sales_order.make_pick_ticket",
+ method: "erpnext.selling.doctype.sales_order.sales_order.make_pick_list",
source_doctype: "Sales Order",
target: frm,
setters: {
@@ -36,7 +36,7 @@ frappe.ui.form.on('Pick Ticket', {
},
make_delivery_note(frm) {
frappe.model.open_mapped_doc({
- method: "erpnext.stock.doctype.pick_ticket.pick_ticket.make_delivery_note",
+ method: "erpnext.stock.doctype.pick_list.pick_list.make_delivery_note",
frm: frm
});
},
diff --git a/erpnext/stock/doctype/pick_ticket/pick_ticket.json b/erpnext/stock/doctype/pick_list/pick_list.json
similarity index 93%
rename from erpnext/stock/doctype/pick_ticket/pick_ticket.json
rename to erpnext/stock/doctype/pick_list/pick_list.json
index d8a8e0175c..3f96630faf 100644
--- a/erpnext/stock/doctype/pick_ticket/pick_ticket.json
+++ b/erpnext/stock/doctype/pick_list/pick_list.json
@@ -43,19 +43,19 @@
"fieldname": "item_locations",
"fieldtype": "Table",
"label": "Item Locations",
- "options": "Pick Ticket Item"
+ "options": "Pick List Item"
},
{
"fieldname": "reference_items",
"fieldtype": "Table",
"label": "Items To Be Picked",
- "options": "Pick Ticket Reference Item"
+ "options": "Pick List Reference Item"
}
],
"modified": "2019-08-01 10:50:17.055509",
"modified_by": "Administrator",
"module": "Stock",
- "name": "Pick Ticket",
+ "name": "Pick List",
"owner": "Administrator",
"permissions": [
{
diff --git a/erpnext/stock/doctype/pick_ticket/pick_ticket.py b/erpnext/stock/doctype/pick_list/pick_list.py
similarity index 97%
rename from erpnext/stock/doctype/pick_ticket/pick_ticket.py
rename to erpnext/stock/doctype/pick_list/pick_list.py
index 16f6d7a5df..3e45bddfd3 100644
--- a/erpnext/stock/doctype/pick_ticket/pick_ticket.py
+++ b/erpnext/stock/doctype/pick_list/pick_list.py
@@ -7,7 +7,7 @@ import frappe
from frappe.model.document import Document
from frappe.model.mapper import get_mapped_doc
-class PickTicket(Document):
+class PickList(Document):
def set_item_locations(self):
reference_items = self.reference_items
@@ -131,14 +131,14 @@ def set_batch_no(item_doc, parent_doc):
@frappe.whitelist()
def make_delivery_note(source_name, target_doc=None):
- target_doc = get_mapped_doc("Pick Ticket", source_name, {
- "Pick Ticket": {
+ target_doc = get_mapped_doc("Pick List", source_name, {
+ "Pick List": {
"doctype": "Delivery Note",
# "validation": {
# "docstatus": ["=", 1]
# }
},
- "Pick Ticket Item": {
+ "Pick List Item": {
"doctype": "Delivery Note Item",
"field_map": {
"item": "item_code",
diff --git a/erpnext/stock/doctype/pick_list/test_pick_list.py b/erpnext/stock/doctype/pick_list/test_pick_list.py
new file mode 100644
index 0000000000..ed4b6b58cc
--- /dev/null
+++ b/erpnext/stock/doctype/pick_list/test_pick_list.py
@@ -0,0 +1,100 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+import frappe
+import unittest
+# test_dependencies = ['Item', 'Sales Invoice', 'Stock Entry', 'Batch']
+
+from erpnext.selling.doctype.sales_order.sales_order import make_pick_list
+
+class TestPickList(unittest.TestCase):
+ def test_pick_list_picks_warehouse_for_each_item(self):
+ pick_list = frappe.get_doc({
+ 'doctype': 'Pick List',
+ 'company': '_Test Company',
+ 'reference_items': [{
+ 'item': '_Test Item Home Desktop 100',
+ 'reference_doctype': 'Sales Order',
+ 'qty': 5,
+ 'reference_name': '_T-Sales Order-1',
+ }],
+ })
+
+ pick_list.set_item_locations()
+
+ self.assertEqual(pick_list.items_locations[0].item, '_Test Item Home Desktop 100')
+ self.assertEqual(pick_list.items_locations[0].warehouse, '_Test Warehouse - _TC')
+ self.assertEqual(pick_list.items_locations[0].qty, 5)
+
+ def test_pick_list_skips_out_of_stock_item(self):
+ pick_list = frappe.get_doc({
+ 'doctype': 'Pick List',
+ 'company': '_Test Company',
+ 'reference_items': [{
+ 'item': '_Test Item Warehouse Group Wise Reorder',
+ 'reference_doctype': 'Sales Order',
+ 'qty': 1000,
+ 'reference_name': '_T-Sales Order-1',
+ }],
+ })
+
+ pick_list.set_item_locations()
+
+ self.assertEqual(pick_list.items_locations[0].item, '_Test Item Warehouse Group Wise Reorder')
+ self.assertEqual(pick_list.items_locations[0].warehouse, '_Test Warehouse Group-C1 - _TC')
+ self.assertEqual(pick_list.items_locations[0].qty, 30)
+
+
+ def test_pick_list_skips_items_in_expired_batch(self):
+ pass
+
+ def test_pick_list_shows_serial_no_for_serialized_item(self):
+
+ stock_reconciliation = frappe.get_doc({
+ 'doctype': 'Stock Reconciliation',
+ 'company': '_Test Company',
+ 'items': [{
+ 'item_code': '_Test Serialized Item',
+ 'warehouse': '_Test Warehouse - _TC',
+ 'qty': 5,
+ 'serial_no': '123450\n123451\n123452\n123453\n123454'
+ }]
+ })
+
+ stock_reconciliation.submit()
+
+ pick_list = frappe.get_doc({
+ 'doctype': 'Pick List',
+ 'company': '_Test Company',
+ 'reference_items': [{
+ 'item': '_Test Serialized Item',
+ 'reference_doctype': 'Sales Order',
+ 'qty': 1000,
+ 'reference_name': '_T-Sales Order-1',
+ }],
+ })
+
+ pick_list.set_item_locations()
+ self.assertEqual(pick_list.items_locations[0].item, '_Test Serialized Item')
+ self.assertEqual(pick_list.items_locations[0].warehouse, '_Test Warehouse Group-C1 - _TC')
+ self.assertEqual(pick_list.items_locations[0].qty, 30)
+ self.assertEqual(pick_list.items_locations[0].serial_no, 30)
+
+
+ def test_pick_list_for_multiple_reference_doctypes(self):
+ pass
+
+
+## records required
+
+'''
+batch no
+items
+sales invoice
+stock entries
+ bin
+ stock ledger entry
+warehouses
+'''
\ No newline at end of file
diff --git a/erpnext/stock/doctype/pick_ticket_item/__init__.py b/erpnext/stock/doctype/pick_list_item/pick_list_item/__init__.py
similarity index 100%
rename from erpnext/stock/doctype/pick_ticket_item/__init__.py
rename to erpnext/stock/doctype/pick_list_item/pick_list_item/__init__.py
diff --git a/erpnext/stock/doctype/pick_ticket_item/pick_ticket_item.json b/erpnext/stock/doctype/pick_list_item/pick_list_item/pick_ticket_item.json
similarity index 98%
rename from erpnext/stock/doctype/pick_ticket_item/pick_ticket_item.json
rename to erpnext/stock/doctype/pick_list_item/pick_list_item/pick_ticket_item.json
index 67a7e9caa5..c83b696144 100644
--- a/erpnext/stock/doctype/pick_ticket_item/pick_ticket_item.json
+++ b/erpnext/stock/doctype/pick_list_item/pick_list_item/pick_ticket_item.json
@@ -132,7 +132,7 @@
"modified": "2019-07-30 23:47:53.566473",
"modified_by": "Administrator",
"module": "Stock",
- "name": "Pick Ticket Item",
+ "name": "Pick List Item",
"owner": "Administrator",
"permissions": [],
"quick_entry": 1,
diff --git a/erpnext/stock/doctype/pick_ticket_item/pick_ticket_item.py b/erpnext/stock/doctype/pick_list_item/pick_list_item/pick_ticket_item.py
similarity index 88%
rename from erpnext/stock/doctype/pick_ticket_item/pick_ticket_item.py
rename to erpnext/stock/doctype/pick_list_item/pick_list_item/pick_ticket_item.py
index a13666a438..8797b8dc21 100644
--- a/erpnext/stock/doctype/pick_ticket_item/pick_ticket_item.py
+++ b/erpnext/stock/doctype/pick_list_item/pick_list_item/pick_ticket_item.py
@@ -6,5 +6,5 @@ from __future__ import unicode_literals
# import frappe
from frappe.model.document import Document
-class PickTicketItem(Document):
+class PickListItem(Document):
pass
diff --git a/erpnext/stock/doctype/pick_list_reference_item/__init__.py b/erpnext/stock/doctype/pick_list_reference_item/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/stock/doctype/pick_ticket_reference_item/pick_ticket_reference_item.js b/erpnext/stock/doctype/pick_list_reference_item/pick_list_reference_item.js
similarity index 76%
rename from erpnext/stock/doctype/pick_ticket_reference_item/pick_ticket_reference_item.js
rename to erpnext/stock/doctype/pick_list_reference_item/pick_list_reference_item.js
index a3f909659b..875ce23a28 100644
--- a/erpnext/stock/doctype/pick_ticket_reference_item/pick_ticket_reference_item.js
+++ b/erpnext/stock/doctype/pick_list_reference_item/pick_list_reference_item.js
@@ -1,7 +1,7 @@
// Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
-frappe.ui.form.on('Pick Ticket Reference Item', {
+frappe.ui.form.on('Pick List Reference Item', {
// refresh: function(frm) {
// }
diff --git a/erpnext/stock/doctype/pick_ticket_reference_item/pick_ticket_reference_item.json b/erpnext/stock/doctype/pick_list_reference_item/pick_list_reference_item.json
similarity index 96%
rename from erpnext/stock/doctype/pick_ticket_reference_item/pick_ticket_reference_item.json
rename to erpnext/stock/doctype/pick_list_reference_item/pick_list_reference_item.json
index c31e2bcd23..23ef2553a2 100644
--- a/erpnext/stock/doctype/pick_ticket_reference_item/pick_ticket_reference_item.json
+++ b/erpnext/stock/doctype/pick_list_reference_item/pick_list_reference_item.json
@@ -46,7 +46,7 @@
"modified": "2019-07-30 23:43:30.901151",
"modified_by": "Administrator",
"module": "Stock",
- "name": "Pick Ticket Reference Item",
+ "name": "Pick List Reference Item",
"owner": "Administrator",
"permissions": [],
"sort_field": "modified",
diff --git a/erpnext/stock/doctype/pick_ticket_reference_item/pick_ticket_reference_item.py b/erpnext/stock/doctype/pick_list_reference_item/pick_list_reference_item.py
similarity index 85%
rename from erpnext/stock/doctype/pick_ticket_reference_item/pick_ticket_reference_item.py
rename to erpnext/stock/doctype/pick_list_reference_item/pick_list_reference_item.py
index 412be75f88..74f0563cdf 100644
--- a/erpnext/stock/doctype/pick_ticket_reference_item/pick_ticket_reference_item.py
+++ b/erpnext/stock/doctype/pick_list_reference_item/pick_list_reference_item.py
@@ -6,5 +6,5 @@ from __future__ import unicode_literals
# import frappe
from frappe.model.document import Document
-class PickTicketReferenceItem(Document):
+class PickListReferenceItem(Document):
pass
diff --git a/erpnext/stock/doctype/pick_ticket/test_pick_ticket.py b/erpnext/stock/doctype/pick_ticket/test_pick_ticket.py
deleted file mode 100644
index 5a41bc9f2c..0000000000
--- a/erpnext/stock/doctype/pick_ticket/test_pick_ticket.py
+++ /dev/null
@@ -1,100 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors
-# See license.txt
-from __future__ import unicode_literals
-
-import frappe
-import unittest
-# test_dependencies = ['Item', 'Sales Invoice', 'Stock Entry', 'Batch']
-
-from erpnext.selling.doctype.sales_order.sales_order import make_pick_ticket
-
-class TestPickTicket(unittest.TestCase):
- def test_pick_ticket_picks_warehouse_for_each_item(self):
- pick_ticket = frappe.get_doc({
- 'doctype': 'Pick Ticket',
- 'company': '_Test Company',
- 'reference_items': [{
- 'item': '_Test Item Home Desktop 100',
- 'reference_doctype': 'Sales Order',
- 'qty': 5,
- 'reference_name': '_T-Sales Order-1',
- }],
- })
-
- pick_ticket.set_item_locations()
-
- self.assertEqual(pick_ticket.items_locations[0].item, '_Test Item Home Desktop 100')
- self.assertEqual(pick_ticket.items_locations[0].warehouse, '_Test Warehouse - _TC')
- self.assertEqual(pick_ticket.items_locations[0].qty, 5)
-
- def test_pick_ticket_skips_out_of_stock_item(self):
- pick_ticket = frappe.get_doc({
- 'doctype': 'Pick Ticket',
- 'company': '_Test Company',
- 'reference_items': [{
- 'item': '_Test Item Warehouse Group Wise Reorder',
- 'reference_doctype': 'Sales Order',
- 'qty': 1000,
- 'reference_name': '_T-Sales Order-1',
- }],
- })
-
- pick_ticket.set_item_locations()
-
- self.assertEqual(pick_ticket.items_locations[0].item, '_Test Item Warehouse Group Wise Reorder')
- self.assertEqual(pick_ticket.items_locations[0].warehouse, '_Test Warehouse Group-C1 - _TC')
- self.assertEqual(pick_ticket.items_locations[0].qty, 30)
-
-
- def test_pick_ticket_skips_items_in_expired_batch(self):
- pass
-
- def test_pick_ticket_shows_serial_no_for_serialized_item(self):
-
- stock_reconciliation = frappe.get_doc({
- 'doctype': 'Stock Reconciliation',
- 'company': '_Test Company',
- 'items': [{
- 'item_code': '_Test Serialized Item',
- 'warehouse': '_Test Warehouse - _TC',
- 'qty': 5,
- 'serial_no': '123450\n123451\n123452\n123453\n123454'
- }]
- })
-
- stock_reconciliation.submit()
-
- pick_ticket = frappe.get_doc({
- 'doctype': 'Pick Ticket',
- 'company': '_Test Company',
- 'reference_items': [{
- 'item': '_Test Serialized Item',
- 'reference_doctype': 'Sales Order',
- 'qty': 1000,
- 'reference_name': '_T-Sales Order-1',
- }],
- })
-
- pick_ticket.set_item_locations()
- self.assertEqual(pick_ticket.items_locations[0].item, '_Test Serialized Item')
- self.assertEqual(pick_ticket.items_locations[0].warehouse, '_Test Warehouse Group-C1 - _TC')
- self.assertEqual(pick_ticket.items_locations[0].qty, 30)
- self.assertEqual(pick_ticket.items_locations[0].serial_no, 30)
-
-
- def test_pick_ticket_for_multiple_reference_doctypes(self):
- pass
-
-
-## records required
-
-'''
-batch no
-items
-sales invoice
-stock entries
- bin
- stock ledger entry
-warehouses
-'''
\ No newline at end of file
From bb7a2dbb6a9f6052a695ed26fc7a597df8fef107 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Thu, 1 Aug 2019 12:38:26 +0530
Subject: [PATCH 176/484] fix: Rename file
---
.../pick_list_item/{pick_ticket_item.json => pick_list_item.json} | 0
.../pick_list_item/{pick_ticket_item.py => pick_list_item.py} | 0
2 files changed, 0 insertions(+), 0 deletions(-)
rename erpnext/stock/doctype/pick_list_item/pick_list_item/{pick_ticket_item.json => pick_list_item.json} (100%)
rename erpnext/stock/doctype/pick_list_item/pick_list_item/{pick_ticket_item.py => pick_list_item.py} (100%)
diff --git a/erpnext/stock/doctype/pick_list_item/pick_list_item/pick_ticket_item.json b/erpnext/stock/doctype/pick_list_item/pick_list_item/pick_list_item.json
similarity index 100%
rename from erpnext/stock/doctype/pick_list_item/pick_list_item/pick_ticket_item.json
rename to erpnext/stock/doctype/pick_list_item/pick_list_item/pick_list_item.json
diff --git a/erpnext/stock/doctype/pick_list_item/pick_list_item/pick_ticket_item.py b/erpnext/stock/doctype/pick_list_item/pick_list_item/pick_list_item.py
similarity index 100%
rename from erpnext/stock/doctype/pick_list_item/pick_list_item/pick_ticket_item.py
rename to erpnext/stock/doctype/pick_list_item/pick_list_item/pick_list_item.py
From d9e482759c31a09ec55c16506937c470b137148a Mon Sep 17 00:00:00 2001
From: Faris Ansari
Date: Thu, 1 Aug 2019 12:53:19 +0530
Subject: [PATCH 177/484] style: Missing semicolon
---
.../page/bom_comparison_tool/bom_comparison_tool.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/manufacturing/page/bom_comparison_tool/bom_comparison_tool.js b/erpnext/manufacturing/page/bom_comparison_tool/bom_comparison_tool.js
index 11648226a8..7152d3dff6 100644
--- a/erpnext/manufacturing/page/bom_comparison_tool/bom_comparison_tool.js
+++ b/erpnext/manufacturing/page/bom_comparison_tool/bom_comparison_tool.js
@@ -171,7 +171,7 @@ erpnext.BOMComparisonTool = class BOMComparisonTool {
`;
}).join('');
- }
+ };
let added_by_fieldname = group_items(diff.added, change => change[0]);
let removed_by_fieldname = group_items(diff.removed, change => change[0]);
From e06f486aeed08c3236226b1c2f984bf8ada7f6a3 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Thu, 1 Aug 2019 12:54:33 +0530
Subject: [PATCH 178/484] fix: Rename methods
---
erpnext/selling/doctype/sales_order/sales_order.js | 6 +++---
erpnext/selling/doctype/sales_order/sales_order.py | 2 +-
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/erpnext/selling/doctype/sales_order/sales_order.js b/erpnext/selling/doctype/sales_order/sales_order.js
index 136ff55344..618adc4691 100644
--- a/erpnext/selling/doctype/sales_order/sales_order.js
+++ b/erpnext/selling/doctype/sales_order/sales_order.js
@@ -110,7 +110,7 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
let allow_delivery = false;
if (doc.docstatus==1) {
- this.frm.add_custom_button(__('Pick List'), () => this.make_pick_ticket(), __('Create'));
+ this.frm.add_custom_button(__('Pick List'), () => this.make_pick_list(), __('Create'));
if(this.frm.has_perm("submit")) {
if(doc.status === 'On Hold') {
@@ -235,9 +235,9 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
this.order_type(doc);
},
- make_pick_ticket() {
+ make_pick_list() {
frappe.model.open_mapped_doc({
- method: "erpnext.selling.doctype.sales_order.sales_order.make_pick_ticket",
+ method: "erpnext.selling.doctype.sales_order.sales_order.make_pick_list",
frm: this.frm
})
},
diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py
index 1d636e3c26..b79a2925e0 100755
--- a/erpnext/selling/doctype/sales_order/sales_order.py
+++ b/erpnext/selling/doctype/sales_order/sales_order.py
@@ -998,7 +998,7 @@ def make_inter_company_purchase_order(source_name, target_doc=None):
return make_inter_company_transaction("Sales Order", source_name, target_doc)
@frappe.whitelist()
-def make_pick_ticket(source_name, target_doc=None):
+def make_pick_list(source_name, target_doc=None):
doc = get_mapped_doc("Sales Order", source_name, {
"Sales Order": {
"doctype": "Pick List",
From c16ef32b6bf874d8d16f21ed11172032a9b59c2c Mon Sep 17 00:00:00 2001
From: deepeshgarg007
Date: Thu, 1 Aug 2019 13:24:48 +0530
Subject: [PATCH 179/484] fix: Payment Order link fix in bank dashboard
---
erpnext/accounts/doctype/bank/bank_dashboard.py | 3 +++
1 file changed, 3 insertions(+)
diff --git a/erpnext/accounts/doctype/bank/bank_dashboard.py b/erpnext/accounts/doctype/bank/bank_dashboard.py
index 432404155d..e047b9aad0 100644
--- a/erpnext/accounts/doctype/bank/bank_dashboard.py
+++ b/erpnext/accounts/doctype/bank/bank_dashboard.py
@@ -6,6 +6,9 @@ from frappe import _
def get_data():
return {
'fieldname': 'bank',
+ 'non_standard_fieldnames': {
+ 'Paymnet Order': 'company_bank'
+ },
'transactions': [
{
'label': _('Bank Deatils'),
From a7dc3735aec3492d038f96c3867df0dc2df545ad Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Thu, 1 Aug 2019 15:49:29 +0530
Subject: [PATCH 180/484] fix: Move folders to right location
---
.../stock/doctype/pick_list_item/{pick_list_item => }/__init__.py | 0
.../pick_list_item/{pick_list_item => }/pick_list_item.json | 0
.../doctype/pick_list_item/{pick_list_item => }/pick_list_item.py | 0
3 files changed, 0 insertions(+), 0 deletions(-)
rename erpnext/stock/doctype/pick_list_item/{pick_list_item => }/__init__.py (100%)
rename erpnext/stock/doctype/pick_list_item/{pick_list_item => }/pick_list_item.json (100%)
rename erpnext/stock/doctype/pick_list_item/{pick_list_item => }/pick_list_item.py (100%)
diff --git a/erpnext/stock/doctype/pick_list_item/pick_list_item/__init__.py b/erpnext/stock/doctype/pick_list_item/__init__.py
similarity index 100%
rename from erpnext/stock/doctype/pick_list_item/pick_list_item/__init__.py
rename to erpnext/stock/doctype/pick_list_item/__init__.py
diff --git a/erpnext/stock/doctype/pick_list_item/pick_list_item/pick_list_item.json b/erpnext/stock/doctype/pick_list_item/pick_list_item.json
similarity index 100%
rename from erpnext/stock/doctype/pick_list_item/pick_list_item/pick_list_item.json
rename to erpnext/stock/doctype/pick_list_item/pick_list_item.json
diff --git a/erpnext/stock/doctype/pick_list_item/pick_list_item/pick_list_item.py b/erpnext/stock/doctype/pick_list_item/pick_list_item.py
similarity index 100%
rename from erpnext/stock/doctype/pick_list_item/pick_list_item/pick_list_item.py
rename to erpnext/stock/doctype/pick_list_item/pick_list_item.py
From b35c0410b178cc0bf4532080630794ec4eec8913 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Fri, 2 Aug 2019 08:12:30 +0530
Subject: [PATCH 181/484] fix: Add option to get items from work order
---
.../doctype/work_order/work_order.js | 8 +++++++
.../doctype/work_order/work_order.py | 24 +++++++++++++++++++
erpnext/stock/doctype/pick_list/pick_list.js | 19 +++++++++++++--
erpnext/stock/doctype/pick_list/pick_list.py | 3 +--
4 files changed, 50 insertions(+), 4 deletions(-)
diff --git a/erpnext/manufacturing/doctype/work_order/work_order.js b/erpnext/manufacturing/doctype/work_order/work_order.js
index 22613cc8a4..a42fc65a8a 100644
--- a/erpnext/manufacturing/doctype/work_order/work_order.js
+++ b/erpnext/manufacturing/doctype/work_order/work_order.js
@@ -161,6 +161,10 @@ frappe.ui.form.on("Work Order", {
frm.add_custom_button(__('Create BOM'), () => {
frm.trigger("make_bom");
});
+
+ frm.add_custom_button(__('Pick List'), () => {
+ frm.trigger("make_bom");
+ }, __('Make'));
}
},
@@ -264,6 +268,10 @@ frappe.ui.form.on("Work Order", {
});
},
+ make_pick_list() {
+
+ },
+
show_progress: function(frm) {
var bars = [];
var message = '';
diff --git a/erpnext/manufacturing/doctype/work_order/work_order.py b/erpnext/manufacturing/doctype/work_order/work_order.py
index 2b70325d9f..c489fbcd55 100644
--- a/erpnext/manufacturing/doctype/work_order/work_order.py
+++ b/erpnext/manufacturing/doctype/work_order/work_order.py
@@ -19,6 +19,7 @@ from erpnext.stock.stock_balance import get_planned_qty, update_bin_qty
from frappe.utils.csvutils import getlink
from erpnext.stock.utils import get_bin, validate_warehouse_company, get_latest_stock_qty
from erpnext.utilities.transaction_base import validate_uom_is_integer
+from frappe.model.mapper import get_mapped_doc
class OverProductionError(frappe.ValidationError): pass
class StockOverProductionError(frappe.ValidationError): pass
@@ -707,3 +708,26 @@ def get_work_order_operation_data(work_order, operation, workstation):
for d in work_order.operations:
if d.operation == operation and d.workstation == workstation:
return d
+
+@frappe.whitelist()
+def make_pick_list(source_name, target_doc=None):
+ doc = get_mapped_doc("Work Order", source_name, {
+ "Work Order": {
+ "doctype": "Pick List",
+ "validation": {
+ "docstatus": ["=", 1]
+ }
+ },
+ "Work Order Item": {
+ "doctype": "Pick List Reference Item",
+ "field_map": {
+ "item_code": "item",
+ "required_qty": "qty",
+ "parenttype": "reference_doctype",
+ "parent": "reference_name",
+ "name": "reference_document_item"
+ },
+ },
+ }, target_doc)
+
+ return doc
diff --git a/erpnext/stock/doctype/pick_list/pick_list.js b/erpnext/stock/doctype/pick_list/pick_list.js
index 4cf4cdf78a..602b7e02dd 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.js
+++ b/erpnext/stock/doctype/pick_list/pick_list.js
@@ -14,13 +14,13 @@ frappe.ui.form.on('Pick List', {
},
refresh: (frm) => {
frm.add_custom_button(__('Delivery Note'), () => frm.trigger('make_delivery_note'), __('Create'));
- frm.add_custom_button(__('Sales Order'), function() {
+ frm.add_custom_button(__('Sales Order'), () => {
erpnext.utils.map_current_doc({
method: "erpnext.selling.doctype.sales_order.sales_order.make_pick_list",
source_doctype: "Sales Order",
target: frm,
setters: {
- company: frm.doc.company || undefined,
+ company: frm.doc.company,
},
get_query_filters: {
docstatus: 1,
@@ -28,6 +28,21 @@ frappe.ui.form.on('Pick List', {
});
}, __("Get items from"));
+ frm.add_custom_button(__('Work Order'), () => {
+ erpnext.utils.map_current_doc({
+ method: "erpnext.manufacturing.doctype.work_order.work_order.make_pick_list",
+ source_doctype: "Work Order",
+ target: frm,
+ setters: {
+ company: frm.doc.company,
+ },
+ date_field: 'creation',
+ get_query_filters: {
+ docstatus: 1,
+ }
+ });
+ }, __("Get items from"));
+
if (frm.doc.reference_items && frm.doc.reference_items.length) {
frm.add_custom_button(__('Get Item Locations'), () => {
frm.call('set_item_locations');
diff --git a/erpnext/stock/doctype/pick_list/pick_list.py b/erpnext/stock/doctype/pick_list/pick_list.py
index 3e45bddfd3..77dacd5144 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.py
+++ b/erpnext/stock/doctype/pick_list/pick_list.py
@@ -97,7 +97,6 @@ def set_batch_no(item_doc, parent_doc):
'item_code': item_doc.item,
'warehouse': item_doc.warehouse,
}, as_dict=1)
- print(batches)
required_qty = item_doc.qty
while required_qty > 0 and batches:
@@ -114,8 +113,8 @@ def set_batch_no(item_doc, parent_doc):
# split item if quantity of item in batch is less that required
# Look for another batch
- # set quantity of of item equal to batch quantity
required_qty -= batch.qty
+ # set quantity of current item equal to batch quantity
item_doc.set('qty', batch.qty)
item_doc = parent_doc.append('items', {
'item': item_doc.item,
From c57328669a4bba46ec9e1d003f4f052683116e30 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Fri, 2 Aug 2019 08:14:27 +0530
Subject: [PATCH 182/484] feat: Add pick list print format
---
erpnext/stock/print_format/__init__.py | 0
.../stock/print_format/pick_list/__init__.py | 0
.../print_format/pick_list/pick_list.json | 23 +++++++++++++++++++
3 files changed, 23 insertions(+)
create mode 100644 erpnext/stock/print_format/__init__.py
create mode 100644 erpnext/stock/print_format/pick_list/__init__.py
create mode 100644 erpnext/stock/print_format/pick_list/pick_list.json
diff --git a/erpnext/stock/print_format/__init__.py b/erpnext/stock/print_format/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/stock/print_format/pick_list/__init__.py b/erpnext/stock/print_format/pick_list/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/stock/print_format/pick_list/pick_list.json b/erpnext/stock/print_format/pick_list/pick_list.json
new file mode 100644
index 0000000000..56c819fc0c
--- /dev/null
+++ b/erpnext/stock/print_format/pick_list/pick_list.json
@@ -0,0 +1,23 @@
+{
+ "align_labels_right": 1,
+ "creation": "2019-08-02 07:27:42.533305",
+ "custom_format": 0,
+ "disabled": 0,
+ "doc_type": "Pick List",
+ "docstatus": 0,
+ "doctype": "Print Format",
+ "font": "Default",
+ "format_data": "[{\"fieldname\": \"print_heading_template\", \"fieldtype\": \"Custom HTML\", \"options\": \"\\t\\t\\t\\t
Pick List{{ doc.name }} \\t\\t\\t\\t
\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"company\", \"label\": \"Company\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"parent_warehouse\", \"label\": \"Parent Warehouse\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"visible_columns\": [{\"print_hide\": 0, \"fieldname\": \"item\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"item_name\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"description\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"warehouse\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"qty\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"serial_no\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"batch_no\", \"print_width\": \"\"}], \"print_hide\": 0, \"fieldname\": \"item_locations\", \"label\": \"Item Locations\"}]",
+ "idx": 0,
+ "line_breaks": 1,
+ "modified": "2019-08-02 07:58:35.504361",
+ "modified_by": "Administrator",
+ "module": "Stock",
+ "name": "Pick List",
+ "owner": "Administrator",
+ "print_format_builder": 1,
+ "print_format_type": "Jinja",
+ "raw_printing": 0,
+ "show_section_headings": 1,
+ "standard": "Yes"
+}
\ No newline at end of file
From 0313dc0f8cc07f1ba548495a1cb8ec0d8a429a39 Mon Sep 17 00:00:00 2001
From: Shivam Mishra
Date: Fri, 2 Aug 2019 14:12:36 +0530
Subject: [PATCH 183/484] fix: task not updated issue
---
erpnext/projects/doctype/task/task.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/projects/doctype/task/task.py b/erpnext/projects/doctype/task/task.py
index 50557f1551..492eabe89e 100755
--- a/erpnext/projects/doctype/task/task.py
+++ b/erpnext/projects/doctype/task/task.py
@@ -145,7 +145,7 @@ class Task(NestedSet):
def populate_depends_on(self):
if self.parent_task:
- parent = frappe.get_cached_doc('Task', self.parent_task)
+ parent = frappe.get_doc('Task', self.parent_task)
if not self.name in [row.task for row in parent.depends_on]:
parent.append("depends_on", {
"doctype": "Task Depends On",
From 968da1cd21e0b19a85b60e2b3b7bd494a51ab597 Mon Sep 17 00:00:00 2001
From: Sahil Khan
Date: Fri, 2 Aug 2019 14:47:59 +0550
Subject: [PATCH 184/484] bumped to version 12.0.4
---
erpnext/__init__.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/__init__.py b/erpnext/__init__.py
index 5e2669368b..260478f730 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__ = '12.0.3'
+__version__ = '12.0.4'
def get_default_company(user=None):
'''Get default company for user'''
From 6fd3a86012368e3f6039e1adbef071d9d88bac22 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Fri, 2 Aug 2019 16:48:31 +0530
Subject: [PATCH 185/484] fix: Option to create pick list from work order
---
erpnext/manufacturing/doctype/work_order/work_order.js | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/erpnext/manufacturing/doctype/work_order/work_order.js b/erpnext/manufacturing/doctype/work_order/work_order.js
index a42fc65a8a..d345c0bf3f 100644
--- a/erpnext/manufacturing/doctype/work_order/work_order.js
+++ b/erpnext/manufacturing/doctype/work_order/work_order.js
@@ -163,7 +163,10 @@ frappe.ui.form.on("Work Order", {
});
frm.add_custom_button(__('Pick List'), () => {
- frm.trigger("make_bom");
+ frappe.model.open_mapped_doc({
+ method: "erpnext.manufacturing.doctype.work_order.work_order.make_pick_list",
+ frm
+ });
}, __('Make'));
}
},
From dadd049cbf23f5e09b323d26c2cdf0763bae77e8 Mon Sep 17 00:00:00 2001
From: Rohit Waghchaure
Date: Fri, 2 Aug 2019 19:11:31 +0530
Subject: [PATCH 186/484] fix: add serial no button not working for the
delivery note
---
erpnext/public/js/utils.js | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/erpnext/public/js/utils.js b/erpnext/public/js/utils.js
index 0a363a04fd..ffc5e6ad36 100755
--- a/erpnext/public/js/utils.js
+++ b/erpnext/public/js/utils.js
@@ -60,7 +60,15 @@ $.extend(erpnext, {
var me = this;
$btn.on("click", function() {
- me.show_serial_batch_selector(grid_row.frm, grid_row.doc);
+ let callback = '';
+ let on_close = '';
+
+ if (grid_row.doc.serial_no) {
+ grid_row.doc.has_serial_no = true;
+ }
+
+ me.show_serial_batch_selector(grid_row.frm, grid_row.doc,
+ callback, on_close, true);
});
},
});
From e45102b91325d7fb64f97de8ee23e60527d56958 Mon Sep 17 00:00:00 2001
From: Suraj Shetty <13928957+surajshetty3416@users.noreply.github.com>
Date: Fri, 2 Aug 2019 21:46:28 +0530
Subject: [PATCH 187/484] fix: Show correct label instead of showing undefined
(#18560)
---
.../doctype/sales_order/sales_order.js | 55 ++++++++++++-------
1 file changed, 36 insertions(+), 19 deletions(-)
diff --git a/erpnext/selling/doctype/sales_order/sales_order.js b/erpnext/selling/doctype/sales_order/sales_order.js
index 39dda92e3e..2e5f255a90 100644
--- a/erpnext/selling/doctype/sales_order/sales_order.js
+++ b/erpnext/selling/doctype/sales_order/sales_order.js
@@ -255,27 +255,44 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
});
return;
} else {
- var fields = [
- {fieldtype:'Table', fieldname: 'items',
- description: __('Select BOM and Qty for Production'),
- fields: [
- {fieldtype:'Read Only', fieldname:'item_code',
- label: __('Item Code'), in_list_view:1},
- {fieldtype:'Link', fieldname:'bom', options: 'BOM', reqd: 1,
- label: __('Select BOM'), in_list_view:1, get_query: function(doc) {
- return {filters: {item: doc.item_code}};
- }},
- {fieldtype:'Float', fieldname:'pending_qty', reqd: 1,
- label: __('Qty'), in_list_view:1},
- {fieldtype:'Data', fieldname:'sales_order_item', reqd: 1,
- label: __('Sales Order Item'), hidden:1}
- ],
- data: r.message,
- get_data: function() {
- return r.message
+ const fields = [{
+ label: 'Items',
+ fieldtype: 'Table',
+ fieldname: 'items',
+ description: __('Select BOM and Qty for Production'),
+ fields: [{
+ fieldtype: 'Read Only',
+ fieldname: 'item_code',
+ label: __('Item Code'),
+ in_list_view: 1
+ }, {
+ fieldtype: 'Link',
+ fieldname: 'bom',
+ options: 'BOM',
+ reqd: 1,
+ label: __('Select BOM'),
+ in_list_view: 1,
+ get_query: function (doc) {
+ return { filters: { item: doc.item_code } };
}
+ }, {
+ fieldtype: 'Float',
+ fieldname: 'pending_qty',
+ reqd: 1,
+ label: __('Qty'),
+ in_list_view: 1
+ }, {
+ fieldtype: 'Data',
+ fieldname: 'sales_order_item',
+ reqd: 1,
+ label: __('Sales Order Item'),
+ hidden: 1
+ }],
+ data: r.message,
+ get_data: () => {
+ return r.message
}
- ]
+ }]
var d = new frappe.ui.Dialog({
title: __('Select Items to Manufacture'),
fields: fields,
From b0916a35dc0049105acb3b2b62a579353e57d33a Mon Sep 17 00:00:00 2001
From: deepeshgarg007
Date: Sat, 3 Aug 2019 10:17:44 +0530
Subject: [PATCH 188/484] fix: Remove payment order from bank dashboard
---
erpnext/accounts/doctype/bank/bank_dashboard.py | 3 ---
1 file changed, 3 deletions(-)
diff --git a/erpnext/accounts/doctype/bank/bank_dashboard.py b/erpnext/accounts/doctype/bank/bank_dashboard.py
index 432404155d..4a1dad8952 100644
--- a/erpnext/accounts/doctype/bank/bank_dashboard.py
+++ b/erpnext/accounts/doctype/bank/bank_dashboard.py
@@ -10,9 +10,6 @@ def get_data():
{
'label': _('Bank Deatils'),
'items': ['Bank Account', 'Bank Guarantee']
- },
- {
- 'items': ['Payment Order']
}
]
}
From a49907925067d899ea1058ef2daa6b1c96f4a038 Mon Sep 17 00:00:00 2001
From: deepeshgarg007
Date: Sat, 3 Aug 2019 10:27:33 +0530
Subject: [PATCH 189/484] fix: Remove non standard fieldname
---
erpnext/accounts/doctype/bank/bank_dashboard.py | 3 ---
1 file changed, 3 deletions(-)
diff --git a/erpnext/accounts/doctype/bank/bank_dashboard.py b/erpnext/accounts/doctype/bank/bank_dashboard.py
index 42838c9748..4a1dad8952 100644
--- a/erpnext/accounts/doctype/bank/bank_dashboard.py
+++ b/erpnext/accounts/doctype/bank/bank_dashboard.py
@@ -6,9 +6,6 @@ from frappe import _
def get_data():
return {
'fieldname': 'bank',
- 'non_standard_fieldnames': {
- 'Paymnet Order': 'company_bank'
- },
'transactions': [
{
'label': _('Bank Deatils'),
From 8bf19ce81a615227ce7b85252aabb41c28039c6e Mon Sep 17 00:00:00 2001
From: deepeshgarg007
Date: Sat, 3 Aug 2019 13:40:37 +0530
Subject: [PATCH 190/484] fix: Error handling in taxes and totals
---
erpnext/controllers/taxes_and_totals.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/controllers/taxes_and_totals.py b/erpnext/controllers/taxes_and_totals.py
index b774037266..d2db9d005a 100644
--- a/erpnext/controllers/taxes_and_totals.py
+++ b/erpnext/controllers/taxes_and_totals.py
@@ -82,7 +82,7 @@ class calculate_taxes_and_totals(object):
item.net_rate = item.rate
- if not item.qty and self.doc.is_return:
+ if not item.qty and self.doc.get("is_return"):
item.amount = flt(-1 * item.rate, item.precision("amount"))
else:
item.amount = flt(item.rate * item.qty, item.precision("amount"))
From c92e8236518944165c760bc2359db00eed78a514 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Mon, 5 Aug 2019 10:02:32 +0530
Subject: [PATCH 191/484] fix(employee-advance): update employee advance on
change in expense claim (#18590)
* fix(employee-advance): update employee advance on rejection/cancellation of expense claim
* fix(expense-claim): display appropriate buttons only if linked transactions are valid
---
.../employee_advance/employee_advance.py | 19 +++++++++++++------
.../hr/doctype/expense_claim/expense_claim.js | 4 ++--
2 files changed, 15 insertions(+), 8 deletions(-)
diff --git a/erpnext/hr/doctype/employee_advance/employee_advance.py b/erpnext/hr/doctype/employee_advance/employee_advance.py
index 1c8b5f9662..7b7c0a77e0 100644
--- a/erpnext/hr/doctype/employee_advance/employee_advance.py
+++ b/erpnext/hr/doctype/employee_advance/employee_advance.py
@@ -64,13 +64,20 @@ class EmployeeAdvance(Document):
def update_claimed_amount(self):
claimed_amount = frappe.db.sql("""
- select sum(ifnull(allocated_amount, 0))
- from `tabExpense Claim Advance`
- where employee_advance = %s and docstatus=1 and allocated_amount > 0
- """, self.name)[0][0] or 0
+ SELECT sum(ifnull(allocated_amount, 0))
+ FROM `tabExpense Claim Advance` eca, `tabExpense Claim` ec
+ WHERE
+ eca.employee_advance = %s
+ AND ec.approval_status="Approved"
+ AND ec.name = eca.parent
+ AND ec.docstatus=1
+ AND eca.allocated_amount > 0
+ """, self.name, debug=1)[0][0] or 0
- if claimed_amount:
- frappe.db.set_value("Employee Advance", self.name, "claimed_amount", flt(claimed_amount))
+ frappe.db.set_value("Employee Advance", self.name, "claimed_amount", flt(claimed_amount))
+ self.reload()
+ self.set_status()
+ frappe.db.set_value("Employee Advance", self.name, "status", self.status)
@frappe.whitelist()
def get_due_advance_amount(employee, posting_date):
diff --git a/erpnext/hr/doctype/expense_claim/expense_claim.js b/erpnext/hr/doctype/expense_claim/expense_claim.js
index 40bec6d4d7..6d3a28e5e2 100644
--- a/erpnext/hr/doctype/expense_claim/expense_claim.js
+++ b/erpnext/hr/doctype/expense_claim/expense_claim.js
@@ -183,7 +183,7 @@ frappe.ui.form.on("Expense Claim", {
refresh: function(frm) {
frm.trigger("toggle_fields");
- if(frm.doc.docstatus == 1) {
+ if(frm.doc.docstatus === 1 && frm.doc.approval_status !== "Rejected") {
frm.add_custom_button(__('Accounting Ledger'), function() {
frappe.route_options = {
voucher_no: frm.doc.name,
@@ -194,7 +194,7 @@ frappe.ui.form.on("Expense Claim", {
}, __("View"));
}
- if (frm.doc.docstatus===1
+ if (frm.doc.docstatus===1 && !cint(frm.doc.is_paid) && cint(frm.doc.grand_total) > 0
&& (cint(frm.doc.total_amount_reimbursed) < cint(frm.doc.total_sanctioned_amount))
&& frappe.model.can_create("Payment Entry")) {
frm.add_custom_button(__('Payment'),
From a813571c17de62714dfc3f8a64724983e899aed2 Mon Sep 17 00:00:00 2001
From: Nabin Hait
Date: Mon, 5 Aug 2019 10:05:28 +0530
Subject: [PATCH 192/484] Update employee_advance.py
---
erpnext/hr/doctype/employee_advance/employee_advance.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/hr/doctype/employee_advance/employee_advance.py b/erpnext/hr/doctype/employee_advance/employee_advance.py
index 7b7c0a77e0..7813da78ca 100644
--- a/erpnext/hr/doctype/employee_advance/employee_advance.py
+++ b/erpnext/hr/doctype/employee_advance/employee_advance.py
@@ -72,7 +72,7 @@ class EmployeeAdvance(Document):
AND ec.name = eca.parent
AND ec.docstatus=1
AND eca.allocated_amount > 0
- """, self.name, debug=1)[0][0] or 0
+ """, self.name)[0][0] or 0
frappe.db.set_value("Employee Advance", self.name, "claimed_amount", flt(claimed_amount))
self.reload()
From 580fa486420b6ed93b197ecd545e3fe8e63226e1 Mon Sep 17 00:00:00 2001
From: Suraj Shetty <13928957+surajshetty3416@users.noreply.github.com>
Date: Mon, 5 Aug 2019 10:08:35 +0530
Subject: [PATCH 193/484] fix: Quotation list in customer portal (#18579)
* fix: Quotation list in customer portal
Customers were not able to see their quotations because of
the recent customer field removal from quotation
* fix: Remove duplicate code
---
.../controllers/website_list_for_contact.py | 50 +++++++++++++------
1 file changed, 34 insertions(+), 16 deletions(-)
diff --git a/erpnext/controllers/website_list_for_contact.py b/erpnext/controllers/website_list_for_contact.py
index ed48fd1ab4..187eaed107 100644
--- a/erpnext/controllers/website_list_for_contact.py
+++ b/erpnext/controllers/website_list_for_contact.py
@@ -77,7 +77,7 @@ def get_list_for_transactions(doctype, txt, filters, limit_start, limit_page_len
if or_filters:
for r in frappe.get_list(doctype, fields=fields,filters=filters, or_filters=or_filters,
- limit_start=limit_start, limit_page_length=limit_page_length,
+ limit_start=limit_start, limit_page_length=limit_page_length,
ignore_permissions=ignore_permissions, order_by=order_by):
data.append(r)
@@ -130,38 +130,56 @@ def get_customers_suppliers(doctype, user):
suppliers = []
meta = frappe.get_meta(doctype)
+ customer_field_name = get_customer_field_name(doctype)
+
+ has_customer_field = meta.has_field(customer_field_name)
+ has_supplier_field = meta.has_field('supplier')
+
if has_common(["Supplier", "Customer"], frappe.get_roles(user)):
contacts = frappe.db.sql("""
- select
+ select
`tabContact`.email_id,
`tabDynamic Link`.link_doctype,
`tabDynamic Link`.link_name
- from
+ from
`tabContact`, `tabDynamic Link`
where
`tabContact`.name=`tabDynamic Link`.parent and `tabContact`.email_id =%s
""", user, as_dict=1)
- customers = [c.link_name for c in contacts if c.link_doctype == 'Customer'] \
- if meta.get_field("customer") else None
- suppliers = [c.link_name for c in contacts if c.link_doctype == 'Supplier'] \
- if meta.get_field("supplier") else None
+ customers = [c.link_name for c in contacts if c.link_doctype == 'Customer']
+ suppliers = [c.link_name for c in contacts if c.link_doctype == 'Supplier']
elif frappe.has_permission(doctype, 'read', user=user):
- customers = [customer.name for customer in frappe.get_list("Customer")] \
- if meta.get_field("customer") else None
- suppliers = [supplier.name for supplier in frappe.get_list("Customer")] \
- if meta.get_field("supplier") else None
+ customer_list = frappe.get_list("Customer")
+ customers = suppliers = [customer.name for customer in customer_list]
- return customers, suppliers
+ return customers if has_customer_field else None, \
+ suppliers if has_supplier_field else None
def has_website_permission(doc, ptype, user, verbose=False):
doctype = doc.doctype
customers, suppliers = get_customers_suppliers(doctype, user)
if customers:
- return frappe.get_all(doctype, filters=[(doctype, "customer", "in", customers),
- (doctype, "name", "=", doc.name)]) and True or False
+ return frappe.db.exists(doctype, filters=get_customer_filter(doc, customers))
elif suppliers:
fieldname = 'suppliers' if doctype == 'Request for Quotation' else 'supplier'
- return frappe.get_all(doctype, filters=[(doctype, fieldname, "in", suppliers),
- (doctype, "name", "=", doc.name)]) and True or False
+ return frappe.db.exists(doctype, filters={
+ 'name': doc.name,
+ fieldname: ["in", suppliers]
+ })
else:
return False
+
+def get_customer_filter(doc, customers):
+ doctype = doc.doctype
+ filters = frappe._dict()
+ filters.name = doc.name
+ filters[get_customer_field_name(doctype)] = ['in', customers]
+ if doctype == 'Quotation':
+ filters.party_type = 'Customer'
+ return filters
+
+def get_customer_field_name(doctype):
+ if doctype == 'Quotation':
+ return 'party_name'
+ else:
+ return 'customer'
\ No newline at end of file
From b4678d3f21f633e0c1c512d9d7759b3bb6459889 Mon Sep 17 00:00:00 2001
From: Faris Ansari
Date: Mon, 5 Aug 2019 10:09:32 +0530
Subject: [PATCH 194/484] chore: Remove package-lock.json (#18564)
Yarn uses yarn.lock
---
package-lock.json | 3 ---
1 file changed, 3 deletions(-)
delete mode 100644 package-lock.json
diff --git a/package-lock.json b/package-lock.json
deleted file mode 100644
index 48e341a095..0000000000
--- a/package-lock.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "lockfileVersion": 1
-}
From 65ad4287b646b93619bdd774c8f0aac7d1c9187f Mon Sep 17 00:00:00 2001
From: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com>
Date: Mon, 5 Aug 2019 10:10:38 +0530
Subject: [PATCH 195/484] fix: Customer price list not honored in shopping cart
(#18557)
---
erpnext/shopping_cart/cart.py | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/erpnext/shopping_cart/cart.py b/erpnext/shopping_cart/cart.py
index 62bde420a8..0922f3d1a0 100644
--- a/erpnext/shopping_cart/cart.py
+++ b/erpnext/shopping_cart/cart.py
@@ -251,13 +251,12 @@ def _get_cart_quotation(party=None):
if quotation:
qdoc = frappe.get_doc("Quotation", quotation[0].name)
else:
- [company, price_list] = frappe.db.get_value("Shopping Cart Settings", None, ["company", "price_list"])
+ company = frappe.db.get_value("Shopping Cart Settings", None, ["company"])
qdoc = frappe.get_doc({
"doctype": "Quotation",
"naming_series": get_shopping_cart_settings().quotation_series or "QTN-CART-",
"quotation_to": party.doctype,
"company": company,
- "selling_price_list": price_list,
"order_type": "Shopping Cart",
"status": "Draft",
"docstatus": 0,
From 713d4bb1ba94af8e34ba40736e3bc4b27116a87b Mon Sep 17 00:00:00 2001
From: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com>
Date: Mon, 5 Aug 2019 10:12:17 +0530
Subject: [PATCH 196/484] fix: Type error handling while getting material
request items (#18550)
* fix: Type error handling while getting material request items
* fix: Remove flt
---
.../doctype/production_plan/production_plan.py | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.py b/erpnext/manufacturing/doctype/production_plan/production_plan.py
index 3a77e2f209..8334f6b869 100644
--- a/erpnext/manufacturing/doctype/production_plan/production_plan.py
+++ b/erpnext/manufacturing/doctype/production_plan/production_plan.py
@@ -430,7 +430,7 @@ def download_raw_materials(production_plan):
continue
item_list.append(['', '', '', '', bin_dict.get('warehouse'),
- bin_dict.get('projected_qty'), bin_dict.get('actual_qty')])
+ bin_dict.get('projected_qty', 0), bin_dict.get('actual_qty', 0)])
build_csv_response(item_list, doc.name)
@@ -507,8 +507,8 @@ def get_material_request_items(row, sales_order,
required_qty = 0
if ignore_existing_ordered_qty or bin_dict.get("projected_qty", 0) < 0:
required_qty = total_qty
- elif total_qty > bin_dict.get("projected_qty"):
- required_qty = total_qty - bin_dict.get("projected_qty")
+ elif total_qty > bin_dict.get("projected_qty", 0):
+ required_qty = total_qty - bin_dict.get("projected_qty", 0)
if required_qty > 0 and required_qty < row['min_order_qty']:
required_qty = row['min_order_qty']
item_group_defaults = get_item_group_defaults(row.item_code, company)
From 8b0302bab9c4f91629654d1897d82f6f3bf3b244 Mon Sep 17 00:00:00 2001
From: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com>
Date: Mon, 5 Aug 2019 10:14:19 +0530
Subject: [PATCH 197/484] fix: Make conversion rate optional for non itemized
items (#18540)
---
erpnext/buying/utils.py | 14 ++++++++------
erpnext/controllers/buying_controller.py | 4 +++-
2 files changed, 11 insertions(+), 7 deletions(-)
diff --git a/erpnext/buying/utils.py b/erpnext/buying/utils.py
index 981ee5dcef..8c0a1e56f7 100644
--- a/erpnext/buying/utils.py
+++ b/erpnext/buying/utils.py
@@ -30,7 +30,9 @@ def update_last_purchase_rate(doc, is_submit):
# for it to be considered for latest purchase rate
if flt(d.conversion_factor):
last_purchase_rate = flt(d.base_rate) / flt(d.conversion_factor)
- else:
+ # Check if item code is present
+ # Conversion factor should not be mandatory for non itemized items
+ elif d.item_code:
frappe.throw(_("UOM Conversion factor is required in row {0}").format(d.idx))
# update last purchsae rate
@@ -84,13 +86,13 @@ def get_linked_material_requests(items):
items = json.loads(items)
mr_list = []
for item in items:
- material_request = frappe.db.sql("""SELECT distinct mr.name AS mr_name,
- (mr_item.qty - mr_item.ordered_qty) AS qty,
+ material_request = frappe.db.sql("""SELECT distinct mr.name AS mr_name,
+ (mr_item.qty - mr_item.ordered_qty) AS qty,
mr_item.item_code AS item_code,
- mr_item.name AS mr_item
+ mr_item.name AS mr_item
FROM `tabMaterial Request` mr, `tabMaterial Request Item` mr_item
WHERE mr.name = mr_item.parent
- AND mr_item.item_code = %(item)s
+ AND mr_item.item_code = %(item)s
AND mr.material_request_type = 'Purchase'
AND mr.per_ordered < 99.99
AND mr.docstatus = 1
@@ -98,6 +100,6 @@ def get_linked_material_requests(items):
ORDER BY mr_item.item_code ASC""",{"item": item}, as_dict=1)
if material_request:
mr_list.append(material_request)
-
+
return mr_list
diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py
index 0b4d38ce5c..588f74dbc9 100644
--- a/erpnext/controllers/buying_controller.py
+++ b/erpnext/controllers/buying_controller.py
@@ -395,7 +395,9 @@ class BuyingController(StockController):
def set_qty_as_per_stock_uom(self):
for d in self.get("items"):
if d.meta.get_field("stock_qty"):
- if not d.conversion_factor:
+ # Check if item code is present
+ # Conversion factor should not be mandatory for non itemized items
+ if not d.conversion_factor and d.item_code:
frappe.throw(_("Row {0}: Conversion Factor is mandatory").format(d.idx))
d.stock_qty = flt(d.qty) * flt(d.conversion_factor)
From 9accae3ddcaad03b0d8c4b1d38a882aa8a7b6385 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Mon, 5 Aug 2019 10:16:25 +0530
Subject: [PATCH 198/484] fix(sales-order): update items (#18536)
* fix(sales-order): update items
* fix: minor changes
---
erpnext/controllers/accounts_controller.py | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index 288aa082c5..4a89c5b123 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -1192,6 +1192,10 @@ def update_child_qty_rate(parent_doctype, trans_items, parent_doctype_name, chil
.format(child_item.idx, child_item.item_code))
else:
child_item.rate = flt(d.get("rate"))
+ if child_item.price_list_rate:
+ child_item.discount_percentage = flt((1 - flt(child_item.rate) / flt(child_item.price_list_rate)) * 100.0, \
+ child_item.precision("discount_percentage"))
+
child_item.flags.ignore_validate_update_after_submit = True
if new_child_flag:
child_item.idx = len(parent.items) + 1
From 7e1987ed48156571cdc6ae1745e9711366a069f2 Mon Sep 17 00:00:00 2001
From: Anurag Mishra <32095923+Anurag810@users.noreply.github.com>
Date: Mon, 5 Aug 2019 10:18:57 +0530
Subject: [PATCH 199/484] feat: validate cwip accounts for journal Entry
(#18518)
---
erpnext/accounts/general_ledger.py | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/erpnext/accounts/general_ledger.py b/erpnext/accounts/general_ledger.py
index 9a014840eb..be1448df3a 100644
--- a/erpnext/accounts/general_ledger.py
+++ b/erpnext/accounts/general_ledger.py
@@ -93,6 +93,7 @@ def check_if_in_list(gle, gl_map, dimensions=None):
def save_entries(gl_map, adv_adj, update_outstanding, from_repost=False):
if not from_repost:
validate_account_for_perpetual_inventory(gl_map)
+ validate_cwip_accounts(gl_map)
round_off_debit_credit(gl_map)
@@ -123,6 +124,16 @@ def validate_account_for_perpetual_inventory(gl_map):
frappe.throw(_("Account: {0} can only be updated via Stock Transactions")
.format(entry.account), StockAccountInvalidTransaction)
+def validate_cwip_accounts(gl_map):
+ if not cint(frappe.db.get_value("Asset Settings", None, "disable_cwip_accounting")) \
+ and gl_map[0].voucher_type == "Journal Entry":
+ cwip_accounts = [d[0] for d in frappe.db.sql("""select name from tabAccount
+ where account_type = 'Capital Work in Progress' and is_group=0""")]
+
+ for entry in gl_map:
+ if entry.account in cwip_accounts:
+ frappe.throw(_("Account: {0} is capital Work in progress and can not be updated by Journal Entry").format(entry.account))
+
def round_off_debit_credit(gl_map):
precision = get_field_precision(frappe.get_meta("GL Entry").get_field("debit"),
currency=frappe.get_cached_value('Company', gl_map[0].company, "default_currency"))
From 08df6bda41a1414a051e49f7a1f48a339b577890 Mon Sep 17 00:00:00 2001
From: Anurag Mishra <32095923+Anurag810@users.noreply.github.com>
Date: Mon, 5 Aug 2019 10:27:25 +0530
Subject: [PATCH 200/484] fix: query (#18468)
---
.../doctype/payment_entry/payment_entry.py | 16 +++++++++++-----
1 file changed, 11 insertions(+), 5 deletions(-)
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py
index 368389807d..da6b167880 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.py
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py
@@ -648,13 +648,18 @@ def get_orders_to_be_billed(posting_date, party_type, party,
orders = []
if voucher_type:
- ref_field = "base_grand_total" if party_account_currency == company_currency else "grand_total"
+ if party_account_currency == company_currency:
+ grand_total_field = "base_grand_total"
+ rounded_total_field = "base_rounded_total"
+ else:
+ grand_total_field = "grand_total"
+ rounded_total_field = "rounded_total"
orders = frappe.db.sql("""
select
name as voucher_no,
- {ref_field} as invoice_amount,
- ({ref_field} - advance_paid) as outstanding_amount,
+ if({rounded_total_field}, {rounded_total_field}, {grand_total_field}) as invoice_amount,
+ (if({rounded_total_field}, {rounded_total_field}, {grand_total_field}) - advance_paid) as outstanding_amount,
transaction_date as posting_date
from
`tab{voucher_type}`
@@ -663,13 +668,14 @@ def get_orders_to_be_billed(posting_date, party_type, party,
and docstatus = 1
and company = %s
and ifnull(status, "") != "Closed"
- and {ref_field} > advance_paid
+ and if({rounded_total_field}, {rounded_total_field}, {grand_total_field}) > advance_paid
and abs(100 - per_billed) > 0.01
{condition}
order by
transaction_date, name
""".format(**{
- "ref_field": ref_field,
+ "rounded_total_field": rounded_total_field,
+ "grand_total_field": grand_total_field,
"voucher_type": voucher_type,
"party_type": scrub(party_type),
"condition": condition
From 9601b6c60106690dccdaa499bfa54a4214ff6737 Mon Sep 17 00:00:00 2001
From: rohitwaghchaure
Date: Mon, 5 Aug 2019 10:40:23 +0530
Subject: [PATCH 201/484] feat: added checkbox 'Update Consumed Material Cost
In Project' in work order to don't update the consumed material cost in the
project for the subassembely work orders (#18533)
---
.../production_plan/production_plan.py | 3 +-
.../doctype/work_order/work_order.json | 986 +++++++++---------
.../stock/doctype/stock_entry/stock_entry.py | 4 +
3 files changed, 509 insertions(+), 484 deletions(-)
diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.py b/erpnext/manufacturing/doctype/production_plan/production_plan.py
index 8334f6b869..650ab137a0 100644
--- a/erpnext/manufacturing/doctype/production_plan/production_plan.py
+++ b/erpnext/manufacturing/doctype/production_plan/production_plan.py
@@ -320,7 +320,8 @@ class ProductionPlan(Document):
'qty': data.get("stock_qty") * item.get("qty"),
'production_plan': self.name,
'company': self.company,
- 'fg_warehouse': item.get("fg_warehouse")
+ 'fg_warehouse': item.get("fg_warehouse"),
+ 'update_consumed_material_cost_in_project': 0
})
work_order = self.create_work_order(data)
diff --git a/erpnext/manufacturing/doctype/work_order/work_order.json b/erpnext/manufacturing/doctype/work_order/work_order.json
index 1534b5929d..63c95e7c21 100644
--- a/erpnext/manufacturing/doctype/work_order/work_order.json
+++ b/erpnext/manufacturing/doctype/work_order/work_order.json
@@ -1,484 +1,504 @@
{
- "allow_import": 1,
- "autoname": "naming_series:",
- "creation": "2013-01-10 16:34:16",
- "doctype": "DocType",
- "document_type": "Setup",
- "field_order": [
- "item",
- "naming_series",
- "status",
- "production_item",
- "item_name",
- "image",
- "bom_no",
- "allow_alternative_item",
- "use_multi_level_bom",
- "skip_transfer",
- "column_break1",
- "company",
- "qty",
- "material_transferred_for_manufacturing",
- "produced_qty",
- "sales_order",
- "project",
- "from_wip_warehouse",
- "warehouses",
- "wip_warehouse",
- "fg_warehouse",
- "column_break_12",
- "scrap_warehouse",
- "required_items_section",
- "required_items",
- "time",
- "planned_start_date",
- "actual_start_date",
- "column_break_13",
- "planned_end_date",
- "actual_end_date",
- "expected_delivery_date",
- "operations_section",
- "transfer_material_against",
- "operations",
- "section_break_22",
- "planned_operating_cost",
- "actual_operating_cost",
- "additional_operating_cost",
- "column_break_24",
- "total_operating_cost",
- "more_info",
- "description",
- "stock_uom",
- "column_break2",
- "material_request",
- "material_request_item",
- "sales_order_item",
- "production_plan",
- "production_plan_item",
- "product_bundle_item",
- "amended_from"
- ],
- "fields": [
- {
- "fieldname": "item",
- "fieldtype": "Section Break",
- "options": "fa fa-gift"
- },
- {
- "fieldname": "naming_series",
- "fieldtype": "Select",
- "label": "Series",
- "options": "MFG-WO-.YYYY.-",
- "print_hide": 1,
- "reqd": 1,
- "set_only_once": 1
- },
- {
- "default": "Draft",
- "depends_on": "eval:!doc.__islocal",
- "fieldname": "status",
- "fieldtype": "Select",
- "label": "Status",
- "no_copy": 1,
- "oldfieldname": "status",
- "oldfieldtype": "Select",
- "options": "\nDraft\nSubmitted\nNot Started\nIn Process\nCompleted\nStopped\nCancelled",
- "read_only": 1,
- "reqd": 1,
- "search_index": 1
- },
- {
- "fieldname": "production_item",
- "fieldtype": "Link",
- "in_global_search": 1,
- "in_list_view": 1,
- "in_standard_filter": 1,
- "label": "Item To Manufacture",
- "oldfieldname": "production_item",
- "oldfieldtype": "Link",
- "options": "Item",
- "reqd": 1
- },
- {
- "depends_on": "eval:doc.production_item",
- "fieldname": "item_name",
- "fieldtype": "Data",
- "label": "Item Name",
- "read_only": 1
- },
- {
- "fetch_from": "production_item.image",
- "fieldname": "image",
- "fieldtype": "Attach Image",
- "hidden": 1,
- "label": "Image",
- "options": "image",
- "print_hide": 1,
- "read_only": 1
- },
- {
- "fieldname": "bom_no",
- "fieldtype": "Link",
- "label": "BOM No",
- "oldfieldname": "bom_no",
- "oldfieldtype": "Link",
- "options": "BOM",
- "reqd": 1
- },
- {
- "default": "0",
- "fieldname": "allow_alternative_item",
- "fieldtype": "Check",
- "label": "Allow Alternative Item"
- },
- {
- "default": "1",
- "description": "Plan material for sub-assemblies",
- "fieldname": "use_multi_level_bom",
- "fieldtype": "Check",
- "label": "Use Multi-Level BOM",
- "print_hide": 1
- },
- {
- "default": "0",
- "description": "Check if material transfer entry is not required",
- "fieldname": "skip_transfer",
- "fieldtype": "Check",
- "label": "Skip Material Transfer to WIP Warehouse"
- },
- {
- "fieldname": "column_break1",
- "fieldtype": "Column Break",
- "oldfieldtype": "Column Break",
- "width": "50%"
- },
- {
- "fieldname": "company",
- "fieldtype": "Link",
- "label": "Company",
- "oldfieldname": "company",
- "oldfieldtype": "Link",
- "options": "Company",
- "remember_last_selected_value": 1,
- "reqd": 1
- },
- {
- "fieldname": "qty",
- "fieldtype": "Float",
- "label": "Qty To Manufacture",
- "oldfieldname": "qty",
- "oldfieldtype": "Currency",
- "reqd": 1
- },
- {
- "default": "0",
- "depends_on": "eval:doc.docstatus==1 && doc.skip_transfer==0",
- "fieldname": "material_transferred_for_manufacturing",
- "fieldtype": "Float",
- "label": "Material Transferred for Manufacturing",
- "no_copy": 1,
- "read_only": 1
- },
- {
- "default": "0",
- "depends_on": "eval:doc.docstatus==1",
- "fieldname": "produced_qty",
- "fieldtype": "Float",
- "label": "Manufactured Qty",
- "no_copy": 1,
- "oldfieldname": "produced_qty",
- "oldfieldtype": "Currency",
- "read_only": 1
- },
- {
- "allow_on_submit": 1,
- "fieldname": "sales_order",
- "fieldtype": "Link",
- "in_global_search": 1,
- "label": "Sales Order",
- "options": "Sales Order"
- },
- {
- "fieldname": "project",
- "fieldtype": "Link",
- "label": "Project",
- "oldfieldname": "project",
- "oldfieldtype": "Link",
- "options": "Project"
- },
- {
- "default": "0",
- "depends_on": "skip_transfer",
- "fieldname": "from_wip_warehouse",
- "fieldtype": "Check",
- "label": "Backflush Raw Materials From Work-in-Progress Warehouse"
- },
- {
- "fieldname": "warehouses",
- "fieldtype": "Section Break",
- "label": "Warehouses",
- "options": "fa fa-building"
- },
- {
- "fieldname": "wip_warehouse",
- "fieldtype": "Link",
- "label": "Work-in-Progress Warehouse",
- "options": "Warehouse"
- },
- {
- "fieldname": "fg_warehouse",
- "fieldtype": "Link",
- "label": "Target Warehouse",
- "options": "Warehouse"
- },
- {
- "fieldname": "column_break_12",
- "fieldtype": "Column Break"
- },
- {
- "fieldname": "scrap_warehouse",
- "fieldtype": "Link",
- "label": "Scrap Warehouse",
- "options": "Warehouse"
- },
- {
- "fieldname": "required_items_section",
- "fieldtype": "Section Break",
- "label": "Required Items"
- },
- {
- "fieldname": "required_items",
- "fieldtype": "Table",
- "label": "Required Items",
- "no_copy": 1,
- "options": "Work Order Item",
- "print_hide": 1
- },
- {
- "fieldname": "time",
- "fieldtype": "Section Break",
- "label": "Time",
- "options": "fa fa-time"
- },
- {
- "allow_on_submit": 1,
- "default": "now",
- "fieldname": "planned_start_date",
- "fieldtype": "Datetime",
- "label": "Planned Start Date",
- "reqd": 1
- },
- {
- "fieldname": "actual_start_date",
- "fieldtype": "Datetime",
- "label": "Actual Start Date",
- "read_only": 1
- },
- {
- "fieldname": "column_break_13",
- "fieldtype": "Column Break"
- },
- {
- "fieldname": "planned_end_date",
- "fieldtype": "Datetime",
- "label": "Planned End Date",
- "no_copy": 1,
- "read_only": 1
- },
- {
- "fieldname": "actual_end_date",
- "fieldtype": "Datetime",
- "label": "Actual End Date",
- "read_only": 1
- },
- {
- "allow_on_submit": 1,
- "fieldname": "expected_delivery_date",
- "fieldtype": "Date",
- "label": "Expected Delivery Date"
- },
- {
- "fieldname": "operations_section",
- "fieldtype": "Section Break",
- "label": "Operations",
- "options": "fa fa-wrench"
- },
- {
- "default": "Work Order",
- "depends_on": "operations",
- "fieldname": "transfer_material_against",
- "fieldtype": "Select",
- "label": "Transfer Material Against",
- "options": "\nWork Order\nJob Card"
- },
- {
- "fieldname": "operations",
- "fieldtype": "Table",
- "label": "Operations",
- "options": "Work Order Operation",
- "read_only": 1
- },
- {
- "depends_on": "operations",
- "fieldname": "section_break_22",
- "fieldtype": "Section Break",
- "label": "Operation Cost"
- },
- {
- "fieldname": "planned_operating_cost",
- "fieldtype": "Currency",
- "label": "Planned Operating Cost",
- "options": "Company:company:default_currency",
- "read_only": 1
- },
- {
- "fieldname": "actual_operating_cost",
- "fieldtype": "Currency",
- "label": "Actual Operating Cost",
- "no_copy": 1,
- "options": "Company:company:default_currency",
- "read_only": 1
- },
- {
- "fieldname": "additional_operating_cost",
- "fieldtype": "Currency",
- "label": "Additional Operating Cost",
- "no_copy": 1,
- "options": "Company:company:default_currency"
- },
- {
- "fieldname": "column_break_24",
- "fieldtype": "Column Break"
- },
- {
- "fieldname": "total_operating_cost",
- "fieldtype": "Currency",
- "label": "Total Operating Cost",
- "no_copy": 1,
- "options": "Company:company:default_currency",
- "read_only": 1
- },
- {
- "collapsible": 1,
- "fieldname": "more_info",
- "fieldtype": "Section Break",
- "label": "More Information",
- "options": "fa fa-file-text"
- },
- {
- "fieldname": "description",
- "fieldtype": "Small Text",
- "label": "Item Description",
- "read_only": 1
- },
- {
- "fieldname": "stock_uom",
- "fieldtype": "Link",
- "label": "Stock UOM",
- "oldfieldname": "stock_uom",
- "oldfieldtype": "Data",
- "options": "UOM",
- "read_only": 1
- },
- {
- "fieldname": "column_break2",
- "fieldtype": "Column Break",
- "width": "50%"
- },
- {
- "description": "Manufacture against Material Request",
- "fieldname": "material_request",
- "fieldtype": "Link",
- "label": "Material Request",
- "options": "Material Request"
- },
- {
- "fieldname": "material_request_item",
- "fieldtype": "Data",
- "hidden": 1,
- "label": "Material Request Item",
- "read_only": 1
- },
- {
- "fieldname": "sales_order_item",
- "fieldtype": "Data",
- "hidden": 1,
- "label": "Sales Order Item",
- "read_only": 1
- },
- {
- "fieldname": "production_plan",
- "fieldtype": "Link",
- "label": "Production Plan",
- "no_copy": 1,
- "options": "Production Plan",
- "print_hide": 1,
- "read_only": 1
- },
- {
- "fieldname": "production_plan_item",
- "fieldtype": "Data",
- "label": "Production Plan Item",
- "no_copy": 1,
- "print_hide": 1,
- "read_only": 1
- },
- {
- "fieldname": "product_bundle_item",
- "fieldtype": "Link",
- "label": "Product Bundle Item",
- "no_copy": 1,
- "options": "Item",
- "print_hide": 1,
- "read_only": 1
- },
- {
- "fieldname": "amended_from",
- "fieldtype": "Link",
- "ignore_user_permissions": 1,
- "label": "Amended From",
- "no_copy": 1,
- "oldfieldname": "amended_from",
- "oldfieldtype": "Data",
- "options": "Work Order",
- "read_only": 1
- }
- ],
- "icon": "fa fa-cogs",
- "idx": 1,
- "image_field": "image",
- "is_submittable": 1,
- "modified": "2019-05-27 09:36:16.707719",
- "modified_by": "Administrator",
- "module": "Manufacturing",
- "name": "Work Order",
- "owner": "Administrator",
- "permissions": [
- {
- "amend": 1,
- "cancel": 1,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "import": 1,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Manufacturing User",
- "set_user_permissions": 1,
- "share": 1,
- "submit": 1,
- "write": 1
- },
- {
- "read": 1,
- "report": 1,
- "role": "Stock User"
- }
- ],
- "sort_order": "ASC",
- "title_field": "production_item",
- "track_changes": 1,
- "track_seen": 1
- }
\ No newline at end of file
+ "allow_import": 1,
+ "autoname": "naming_series:",
+ "creation": "2013-01-10 16:34:16",
+ "doctype": "DocType",
+ "document_type": "Setup",
+ "engine": "InnoDB",
+ "field_order": [
+ "item",
+ "naming_series",
+ "status",
+ "production_item",
+ "item_name",
+ "image",
+ "bom_no",
+ "column_break1",
+ "company",
+ "qty",
+ "material_transferred_for_manufacturing",
+ "produced_qty",
+ "sales_order",
+ "project",
+ "settings_section",
+ "allow_alternative_item",
+ "use_multi_level_bom",
+ "column_break_18",
+ "skip_transfer",
+ "from_wip_warehouse",
+ "update_consumed_material_cost_in_project",
+ "warehouses",
+ "wip_warehouse",
+ "fg_warehouse",
+ "column_break_12",
+ "scrap_warehouse",
+ "required_items_section",
+ "required_items",
+ "time",
+ "planned_start_date",
+ "actual_start_date",
+ "column_break_13",
+ "planned_end_date",
+ "actual_end_date",
+ "expected_delivery_date",
+ "operations_section",
+ "transfer_material_against",
+ "operations",
+ "section_break_22",
+ "planned_operating_cost",
+ "actual_operating_cost",
+ "additional_operating_cost",
+ "column_break_24",
+ "total_operating_cost",
+ "more_info",
+ "description",
+ "stock_uom",
+ "column_break2",
+ "material_request",
+ "material_request_item",
+ "sales_order_item",
+ "production_plan",
+ "production_plan_item",
+ "product_bundle_item",
+ "amended_from"
+ ],
+ "fields": [
+ {
+ "fieldname": "item",
+ "fieldtype": "Section Break",
+ "options": "fa fa-gift"
+ },
+ {
+ "fieldname": "naming_series",
+ "fieldtype": "Select",
+ "label": "Series",
+ "options": "MFG-WO-.YYYY.-",
+ "print_hide": 1,
+ "reqd": 1,
+ "set_only_once": 1
+ },
+ {
+ "default": "Draft",
+ "depends_on": "eval:!doc.__islocal",
+ "fieldname": "status",
+ "fieldtype": "Select",
+ "label": "Status",
+ "no_copy": 1,
+ "oldfieldname": "status",
+ "oldfieldtype": "Select",
+ "options": "\nDraft\nSubmitted\nNot Started\nIn Process\nCompleted\nStopped\nCancelled",
+ "read_only": 1,
+ "reqd": 1,
+ "search_index": 1
+ },
+ {
+ "fieldname": "production_item",
+ "fieldtype": "Link",
+ "in_global_search": 1,
+ "in_list_view": 1,
+ "in_standard_filter": 1,
+ "label": "Item To Manufacture",
+ "oldfieldname": "production_item",
+ "oldfieldtype": "Link",
+ "options": "Item",
+ "reqd": 1
+ },
+ {
+ "depends_on": "eval:doc.production_item",
+ "fieldname": "item_name",
+ "fieldtype": "Data",
+ "label": "Item Name",
+ "read_only": 1
+ },
+ {
+ "fetch_from": "production_item.image",
+ "fieldname": "image",
+ "fieldtype": "Attach Image",
+ "hidden": 1,
+ "label": "Image",
+ "options": "image",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "fieldname": "bom_no",
+ "fieldtype": "Link",
+ "label": "BOM No",
+ "oldfieldname": "bom_no",
+ "oldfieldtype": "Link",
+ "options": "BOM",
+ "reqd": 1
+ },
+ {
+ "default": "0",
+ "fieldname": "allow_alternative_item",
+ "fieldtype": "Check",
+ "label": "Allow Alternative Item"
+ },
+ {
+ "default": "1",
+ "description": "Plan material for sub-assemblies",
+ "fieldname": "use_multi_level_bom",
+ "fieldtype": "Check",
+ "label": "Use Multi-Level BOM",
+ "print_hide": 1
+ },
+ {
+ "default": "0",
+ "description": "Check if material transfer entry is not required",
+ "fieldname": "skip_transfer",
+ "fieldtype": "Check",
+ "label": "Skip Material Transfer to WIP Warehouse"
+ },
+ {
+ "fieldname": "column_break1",
+ "fieldtype": "Column Break",
+ "oldfieldtype": "Column Break",
+ "width": "50%"
+ },
+ {
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "label": "Company",
+ "oldfieldname": "company",
+ "oldfieldtype": "Link",
+ "options": "Company",
+ "remember_last_selected_value": 1,
+ "reqd": 1
+ },
+ {
+ "fieldname": "qty",
+ "fieldtype": "Float",
+ "label": "Qty To Manufacture",
+ "oldfieldname": "qty",
+ "oldfieldtype": "Currency",
+ "reqd": 1
+ },
+ {
+ "default": "0",
+ "depends_on": "eval:doc.docstatus==1 && doc.skip_transfer==0",
+ "fieldname": "material_transferred_for_manufacturing",
+ "fieldtype": "Float",
+ "label": "Material Transferred for Manufacturing",
+ "no_copy": 1,
+ "read_only": 1
+ },
+ {
+ "default": "0",
+ "depends_on": "eval:doc.docstatus==1",
+ "fieldname": "produced_qty",
+ "fieldtype": "Float",
+ "label": "Manufactured Qty",
+ "no_copy": 1,
+ "oldfieldname": "produced_qty",
+ "oldfieldtype": "Currency",
+ "read_only": 1
+ },
+ {
+ "allow_on_submit": 1,
+ "fieldname": "sales_order",
+ "fieldtype": "Link",
+ "in_global_search": 1,
+ "label": "Sales Order",
+ "options": "Sales Order"
+ },
+ {
+ "fieldname": "project",
+ "fieldtype": "Link",
+ "label": "Project",
+ "oldfieldname": "project",
+ "oldfieldtype": "Link",
+ "options": "Project"
+ },
+ {
+ "default": "0",
+ "depends_on": "skip_transfer",
+ "fieldname": "from_wip_warehouse",
+ "fieldtype": "Check",
+ "label": "Backflush Raw Materials From Work-in-Progress Warehouse"
+ },
+ {
+ "fieldname": "warehouses",
+ "fieldtype": "Section Break",
+ "label": "Warehouses",
+ "options": "fa fa-building"
+ },
+ {
+ "fieldname": "wip_warehouse",
+ "fieldtype": "Link",
+ "label": "Work-in-Progress Warehouse",
+ "options": "Warehouse"
+ },
+ {
+ "fieldname": "fg_warehouse",
+ "fieldtype": "Link",
+ "label": "Target Warehouse",
+ "options": "Warehouse"
+ },
+ {
+ "fieldname": "column_break_12",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "scrap_warehouse",
+ "fieldtype": "Link",
+ "label": "Scrap Warehouse",
+ "options": "Warehouse"
+ },
+ {
+ "fieldname": "required_items_section",
+ "fieldtype": "Section Break",
+ "label": "Required Items"
+ },
+ {
+ "fieldname": "required_items",
+ "fieldtype": "Table",
+ "label": "Required Items",
+ "no_copy": 1,
+ "options": "Work Order Item",
+ "print_hide": 1
+ },
+ {
+ "fieldname": "time",
+ "fieldtype": "Section Break",
+ "label": "Time",
+ "options": "fa fa-time"
+ },
+ {
+ "allow_on_submit": 1,
+ "default": "now",
+ "fieldname": "planned_start_date",
+ "fieldtype": "Datetime",
+ "label": "Planned Start Date",
+ "reqd": 1
+ },
+ {
+ "fieldname": "actual_start_date",
+ "fieldtype": "Datetime",
+ "label": "Actual Start Date",
+ "read_only": 1
+ },
+ {
+ "fieldname": "column_break_13",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "planned_end_date",
+ "fieldtype": "Datetime",
+ "label": "Planned End Date",
+ "no_copy": 1,
+ "read_only": 1
+ },
+ {
+ "fieldname": "actual_end_date",
+ "fieldtype": "Datetime",
+ "label": "Actual End Date",
+ "read_only": 1
+ },
+ {
+ "allow_on_submit": 1,
+ "fieldname": "expected_delivery_date",
+ "fieldtype": "Date",
+ "label": "Expected Delivery Date"
+ },
+ {
+ "fieldname": "operations_section",
+ "fieldtype": "Section Break",
+ "label": "Operations",
+ "options": "fa fa-wrench"
+ },
+ {
+ "default": "Work Order",
+ "depends_on": "operations",
+ "fieldname": "transfer_material_against",
+ "fieldtype": "Select",
+ "label": "Transfer Material Against",
+ "options": "\nWork Order\nJob Card"
+ },
+ {
+ "fieldname": "operations",
+ "fieldtype": "Table",
+ "label": "Operations",
+ "options": "Work Order Operation",
+ "read_only": 1
+ },
+ {
+ "depends_on": "operations",
+ "fieldname": "section_break_22",
+ "fieldtype": "Section Break",
+ "label": "Operation Cost"
+ },
+ {
+ "fieldname": "planned_operating_cost",
+ "fieldtype": "Currency",
+ "label": "Planned Operating Cost",
+ "options": "Company:company:default_currency",
+ "read_only": 1
+ },
+ {
+ "fieldname": "actual_operating_cost",
+ "fieldtype": "Currency",
+ "label": "Actual Operating Cost",
+ "no_copy": 1,
+ "options": "Company:company:default_currency",
+ "read_only": 1
+ },
+ {
+ "fieldname": "additional_operating_cost",
+ "fieldtype": "Currency",
+ "label": "Additional Operating Cost",
+ "no_copy": 1,
+ "options": "Company:company:default_currency"
+ },
+ {
+ "fieldname": "column_break_24",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "total_operating_cost",
+ "fieldtype": "Currency",
+ "label": "Total Operating Cost",
+ "no_copy": 1,
+ "options": "Company:company:default_currency",
+ "read_only": 1
+ },
+ {
+ "collapsible": 1,
+ "fieldname": "more_info",
+ "fieldtype": "Section Break",
+ "label": "More Information",
+ "options": "fa fa-file-text"
+ },
+ {
+ "fieldname": "description",
+ "fieldtype": "Small Text",
+ "label": "Item Description",
+ "read_only": 1
+ },
+ {
+ "fieldname": "stock_uom",
+ "fieldtype": "Link",
+ "label": "Stock UOM",
+ "oldfieldname": "stock_uom",
+ "oldfieldtype": "Data",
+ "options": "UOM",
+ "read_only": 1
+ },
+ {
+ "fieldname": "column_break2",
+ "fieldtype": "Column Break",
+ "width": "50%"
+ },
+ {
+ "description": "Manufacture against Material Request",
+ "fieldname": "material_request",
+ "fieldtype": "Link",
+ "label": "Material Request",
+ "options": "Material Request"
+ },
+ {
+ "fieldname": "material_request_item",
+ "fieldtype": "Data",
+ "hidden": 1,
+ "label": "Material Request Item",
+ "read_only": 1
+ },
+ {
+ "fieldname": "sales_order_item",
+ "fieldtype": "Data",
+ "hidden": 1,
+ "label": "Sales Order Item",
+ "read_only": 1
+ },
+ {
+ "fieldname": "production_plan",
+ "fieldtype": "Link",
+ "label": "Production Plan",
+ "no_copy": 1,
+ "options": "Production Plan",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "fieldname": "production_plan_item",
+ "fieldtype": "Data",
+ "label": "Production Plan Item",
+ "no_copy": 1,
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "fieldname": "product_bundle_item",
+ "fieldtype": "Link",
+ "label": "Product Bundle Item",
+ "no_copy": 1,
+ "options": "Item",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "fieldname": "amended_from",
+ "fieldtype": "Link",
+ "ignore_user_permissions": 1,
+ "label": "Amended From",
+ "no_copy": 1,
+ "oldfieldname": "amended_from",
+ "oldfieldtype": "Data",
+ "options": "Work Order",
+ "read_only": 1
+ },
+ {
+ "fieldname": "settings_section",
+ "fieldtype": "Section Break",
+ "label": "Settings"
+ },
+ {
+ "fieldname": "column_break_18",
+ "fieldtype": "Column Break"
+ },
+ {
+ "default": "1",
+ "fieldname": "update_consumed_material_cost_in_project",
+ "fieldtype": "Check",
+ "label": "Update Consumed Material Cost In Project"
+ }
+ ],
+ "icon": "fa fa-cogs",
+ "idx": 1,
+ "image_field": "image",
+ "is_submittable": 1,
+ "modified": "2019-07-31 00:13:38.218277",
+ "modified_by": "Administrator",
+ "module": "Manufacturing",
+ "name": "Work Order",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "amend": 1,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "import": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Manufacturing User",
+ "set_user_permissions": 1,
+ "share": 1,
+ "submit": 1,
+ "write": 1
+ },
+ {
+ "read": 1,
+ "report": 1,
+ "role": "Stock User"
+ }
+ ],
+ "sort_field": "modified",
+ "sort_order": "ASC",
+ "title_field": "production_item",
+ "track_changes": 1,
+ "track_seen": 1
+}
\ No newline at end of file
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py
index b5303327f6..6e81dd0ae2 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.py
@@ -145,6 +145,10 @@ class StockEntry(StockController):
self.precision("transfer_qty", item))
def update_cost_in_project(self):
+ if (self.work_order and not frappe.db.get_value("Work Order",
+ self.work_order, "update_consumed_material_cost_in_project")):
+ return
+
if self.project:
amount = frappe.db.sql(""" select ifnull(sum(sed.amount), 0)
from
From 23f30cdb8bd69934e5c9041c1e4f3168780dd360 Mon Sep 17 00:00:00 2001
From: deepeshgarg007
Date: Mon, 5 Aug 2019 12:40:50 +0530
Subject: [PATCH 202/484] fix: Aambigious column in query
---
erpnext/accounts/doctype/pricing_rule/utils.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/accounts/doctype/pricing_rule/utils.py b/erpnext/accounts/doctype/pricing_rule/utils.py
index 5795b8f808..bbabac4302 100644
--- a/erpnext/accounts/doctype/pricing_rule/utils.py
+++ b/erpnext/accounts/doctype/pricing_rule/utils.py
@@ -382,7 +382,7 @@ def get_qty_amount_data_for_cumulative(pr_doc, doc, items=[]):
`tab{child_doc}`.amount
FROM `tab{child_doc}`, `tab{parent_doc}`
WHERE
- `tab{child_doc}`.parent = `tab{parent_doc}`.name and {date_field}
+ `tab{child_doc}`.parent = `tab{parent_doc}`.name and `tab{parent_doc}`.{date_field}
between %s and %s and `tab{parent_doc}`.docstatus = 1
{condition} group by `tab{child_doc}`.name
""".format(parent_doc = doctype,
From e8f95a2adf33913fd2b4feee912faf97023b264e Mon Sep 17 00:00:00 2001
From: Himanshu Warekar
Date: Mon, 5 Aug 2019 14:21:09 +0530
Subject: [PATCH 203/484] fix: TreeView fixes
---
.../doctype/quality_procedure/quality_procedure.json | 10 +++++-----
.../doctype/quality_procedure/quality_procedure.py | 8 +++-----
.../quality_procedure/quality_procedure_tree.js | 10 +++-------
3 files changed, 11 insertions(+), 17 deletions(-)
diff --git a/erpnext/quality_management/doctype/quality_procedure/quality_procedure.json b/erpnext/quality_management/doctype/quality_procedure/quality_procedure.json
index 7b241ef787..472b75103c 100644
--- a/erpnext/quality_management/doctype/quality_procedure/quality_procedure.json
+++ b/erpnext/quality_management/doctype/quality_procedure/quality_procedure.json
@@ -1,11 +1,11 @@
{
- "autoname": "format:PRC-{procedure}",
+ "autoname": "format:PRC-{quality_procedure_name}",
"creation": "2018-10-06 00:06:29.756804",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
- "procedure",
+ "quality_procedure_name",
"parent_quality_procedure",
"is_group",
"sb_00",
@@ -62,14 +62,14 @@
"options": "Quality Procedure Process"
},
{
- "fieldname": "procedure",
+ "fieldname": "quality_procedure_name",
"fieldtype": "Data",
"in_list_view": 1,
- "label": "Procedure",
+ "label": "Quality Procedure",
"reqd": 1
}
],
- "modified": "2019-05-26 22:11:53.771428",
+ "modified": "2019-08-05 13:09:29.945082",
"modified_by": "Administrator",
"module": "Quality Management",
"name": "Quality Procedure",
diff --git a/erpnext/quality_management/doctype/quality_procedure/quality_procedure.py b/erpnext/quality_management/doctype/quality_procedure/quality_procedure.py
index 52c3320840..4d3c522956 100644
--- a/erpnext/quality_management/doctype/quality_procedure/quality_procedure.py
+++ b/erpnext/quality_management/doctype/quality_procedure/quality_procedure.py
@@ -36,12 +36,10 @@ class QualityProcedure(NestedSet):
doc.load_from_db()
for process in doc.processes:
- if process.procedure:
- flag_is_group = 1
+ flag_is_group = 1 if process.procedure else 0
- if flag_is_group == 0:
- doc.is_group = 0
- doc.save(ignore_permissions=True)
+ doc.is_group = 0 if flag_is_group == 0 else 1
+ doc.save(ignore_permissions=True)
def set_parent(self):
for process in self.processes:
diff --git a/erpnext/quality_management/doctype/quality_procedure/quality_procedure_tree.js b/erpnext/quality_management/doctype/quality_procedure/quality_procedure_tree.js
index 15b7784dbd..8fd785f205 100644
--- a/erpnext/quality_management/doctype/quality_procedure/quality_procedure_tree.js
+++ b/erpnext/quality_management/doctype/quality_procedure/quality_procedure_tree.js
@@ -6,8 +6,8 @@ frappe.treeview_settings["Quality Procedure"] = {
add_tree_node: 'erpnext.quality_management.doctype.quality_procedure.quality_procedure.add_node',
filters: [
{
- fieldname: "Quality Procedure",
- fieldtype:"Link",
+ fieldname: "quality_procedure",
+ fieldtype: "Link",
options: "Quality Procedure",
label: __("Quality Procedure"),
get_query: function() {
@@ -19,7 +19,7 @@ frappe.treeview_settings["Quality Procedure"] = {
],
breadcrumb: "Setup",
root_label: "All Quality Procedures",
- get_tree_root: false,
+ get_tree_root: true,
menu_items: [
{
label: __("New Quality Procedure"),
@@ -32,8 +32,4 @@ frappe.treeview_settings["Quality Procedure"] = {
onload: function(treeview) {
treeview.make_tree();
},
- onrender: function() {
- $("button:contains('Add Child')").remove();
- $("button:contains('New')").remove();
- }
};
\ No newline at end of file
From f281f00d4393c5edff7b1e05a27c85662351dc70 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Mon, 5 Aug 2019 14:47:02 +0530
Subject: [PATCH 204/484] feat: auto leave encashment
---
erpnext/hooks.py | 5 +++--
erpnext/hr/doctype/hr_settings/hr_settings.json | 9 ++++++++-
.../doctype/leave_encashment/leave_encashment.py | 16 +++++++++++++++-
erpnext/hr/utils.py | 15 ++++++++++++++-
4 files changed, 40 insertions(+), 5 deletions(-)
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index 4f89533ef8..3a73e23991 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -271,11 +271,12 @@ scheduler_events = {
"erpnext.projects.doctype.project.project.update_project_sales_billing",
"erpnext.projects.doctype.project.project.send_project_status_email_to_users",
"erpnext.quality_management.doctype.quality_review.quality_review.review",
- "erpnext.hr.doctype.leave_ledger_entry.leave_ledger_entry.process_expired_allocation"
"erpnext.support.doctype.service_level_agreement.service_level_agreement.check_agreement_status",
],
"daily_long": [
- "erpnext.manufacturing.doctype.bom_update_tool.bom_update_tool.update_latest_price_in_all_boms"
+ "erpnext.manufacturing.doctype.bom_update_tool.bom_update_tool.update_latest_price_in_all_boms",
+ "erpnext.hr.doctype.leave_ledger_entry.leave_ledger_entry.process_expired_allocation",
+ "erpnext.hr.utils.generate_leave_encashment"
],
"monthly_long": [
"erpnext.accounts.deferred_revenue.convert_deferred_revenue_to_income",
diff --git a/erpnext/hr/doctype/hr_settings/hr_settings.json b/erpnext/hr/doctype/hr_settings/hr_settings.json
index 8dd0acf455..a41c887852 100644
--- a/erpnext/hr/doctype/hr_settings/hr_settings.json
+++ b/erpnext/hr/doctype/hr_settings/hr_settings.json
@@ -24,6 +24,7 @@
"column_break_18",
"leave_approver_mandatory_in_leave_application",
"show_leaves_of_all_department_members_in_calendar",
+ "auto_leave_encashment",
"hiring_settings",
"check_vacancies"
],
@@ -153,12 +154,18 @@
"fieldname": "check_vacancies",
"fieldtype": "Check",
"label": "Check Vacancies On Job Offer Creation"
+ },
+ {
+ "default": "0",
+ "fieldname": "auto_leave_encashment",
+ "fieldtype": "Check",
+ "label": "Auto Leave Encashment"
}
],
"icon": "fa fa-cog",
"idx": 1,
"issingle": 1,
- "modified": "2019-07-01 18:59:55.256878",
+ "modified": "2019-08-05 13:07:17.993968",
"modified_by": "Administrator",
"module": "HR",
"name": "HR Settings",
diff --git a/erpnext/hr/doctype/leave_encashment/leave_encashment.py b/erpnext/hr/doctype/leave_encashment/leave_encashment.py
index c47ff85717..d256c7f369 100644
--- a/erpnext/hr/doctype/leave_encashment/leave_encashment.py
+++ b/erpnext/hr/doctype/leave_encashment/leave_encashment.py
@@ -64,7 +64,7 @@ class LeaveEncashment(Document):
allocation = self.get_leave_allocation()
- self.leave_balance = allocation.total_leaves_allocated - get_unused_leaves(self.employee, self.leave_type, allocation.from_date, self.encashment_date)
+ self.leave_balance = allocation.total_leaves_allocated - get_unused_leaves(self.employee, self.leave_type, self.encashment_date)
encashable_days = self.leave_balance - frappe.db.get_value('Leave Type', self.leave_type, 'encashment_threshold_days')
self.encashable_days = encashable_days if encashable_days > 0 else 0
@@ -102,3 +102,17 @@ class LeaveEncashment(Document):
)
create_leave_ledger_entry(self, args, submit)
+
+def create_leave_encashment(leave_allocation):
+ ''' Creates leave encashment for the given allocations '''
+ for allocation in leave_allocation:
+ if not get_assigned_salary_structure(allocation.employee, allocation.to_date):
+ continue
+ leave_encashment = frappe.get_doc(dict(
+ doctype="Leave Encashment",
+ leave_period=allocation.leave_period,
+ employee=allocation.employee,
+ leave_type=allocation.leave_type,
+ encashment_date=allocation.to_date
+ ))
+ leave_encashment.insert(ignore_permissions=True)
\ No newline at end of file
diff --git a/erpnext/hr/utils.py b/erpnext/hr/utils.py
index 1d9db07157..bf09de86e7 100644
--- a/erpnext/hr/utils.py
+++ b/erpnext/hr/utils.py
@@ -4,7 +4,7 @@
from __future__ import unicode_literals
import frappe, erpnext
from frappe import _
-from frappe.utils import formatdate, format_datetime, getdate, get_datetime, nowdate, flt, cstr
+from frappe.utils import formatdate, format_datetime, getdate, get_datetime, nowdate, flt, cstr, add_days, today
from frappe.model.document import Document
from frappe.desk.form import assign_to
from erpnext.hr.doctype.employee.employee import get_holiday_list_for_employee
@@ -263,6 +263,19 @@ def get_leave_period(from_date, to_date, company):
if leave_period:
return leave_period
+def generate_leave_encashment():
+ ''' Generates a draft leave encashment on allocation expiry '''
+ from erpnext.hr.doctype.leave_encashment.leave_encashment import create_leave_encashment
+ if frappe.db.get_single_value('HR Settings', 'auto_leave_encashment'):
+ leave_type = frappe.db.sql_list("SELECT name FROM `tabLeave Type` WHERE `allow_encashment`=1")
+
+ leave_allocation = frappe.get_all("Leave Allocation", filters={
+ 'to_date': add_days(today(), -1),
+ 'leave_type': ('in', leave_type)
+ }, fields=['employee', 'leave_period', 'leave_type', 'to_date', 'total_leaves_allocated', 'new_leaves_allocated'])
+
+ create_leave_encashment(leave_allocation=leave_allocation)
+
def allocate_earned_leaves():
'''Allocate earned leaves to Employees'''
e_leave_types = frappe.get_all("Leave Type",
From 6bed870dfa368d7b96d57a3f9ddcf40ac5790d80 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Mon, 5 Aug 2019 14:47:37 +0530
Subject: [PATCH 205/484] feat: pro-rata leave allocation
---
.../leave_application/leave_application.py | 2 +-
.../hr/doctype/leave_period/leave_period.js | 2 +-
.../hr/doctype/leave_period/leave_period.py | 59 +++++++++++--------
3 files changed, 36 insertions(+), 27 deletions(-)
diff --git a/erpnext/hr/doctype/leave_application/leave_application.py b/erpnext/hr/doctype/leave_application/leave_application.py
index 36a4145467..2e43721a58 100755
--- a/erpnext/hr/doctype/leave_application/leave_application.py
+++ b/erpnext/hr/doctype/leave_application/leave_application.py
@@ -515,7 +515,7 @@ def get_remaining_leaves(allocation, leaves_taken, date, expiry):
return remaining_leaves
- if expiry:
+ if expiry and allocation.carry_forwarded_leaves:
remaining_leaves = _get_remaining_leaves(allocation.carry_forwarded_leaves, expiry)
return flt(allocation.new_leaves_allocated) + flt(remaining_leaves)
diff --git a/erpnext/hr/doctype/leave_period/leave_period.js b/erpnext/hr/doctype/leave_period/leave_period.js
index b8c5f716f5..bad2b8766c 100644
--- a/erpnext/hr/doctype/leave_period/leave_period.js
+++ b/erpnext/hr/doctype/leave_period/leave_period.js
@@ -68,7 +68,7 @@ frappe.ui.form.on('Leave Period', {
},
{
"label": "Add unused leaves from previous allocations",
- "fieldname": "carry_forward_leaves",
+ "fieldname": "carry_forward",
"fieldtype": "Check"
}
],
diff --git a/erpnext/hr/doctype/leave_period/leave_period.py b/erpnext/hr/doctype/leave_period/leave_period.py
index f37efeba0b..7b0f882035 100644
--- a/erpnext/hr/doctype/leave_period/leave_period.py
+++ b/erpnext/hr/doctype/leave_period/leave_period.py
@@ -5,7 +5,7 @@
from __future__ import unicode_literals
import frappe
from frappe import _
-from frappe.utils import getdate, cstr, add_days
+from frappe.utils import getdate, cstr, add_days, date_diff, getdate, ceil
from frappe.model.document import Document
from erpnext.hr.utils import validate_overlap, get_employee_leave_policy
from erpnext.hr.doctype.leave_allocation.leave_allocation import get_carry_forwarded_leaves
@@ -22,8 +22,8 @@ class LeavePeriod(Document):
condition_str = " and " + " and ".join(conditions) if len(conditions) else ""
- employees = frappe.db.sql_list("select name from tabEmployee where status='Active' {condition}"
- .format(condition=condition_str), tuple(values))
+ employees = frappe._dict(frappe.db.sql("select name, date_of_joining from tabEmployee where status='Active' {condition}"
+ .format(condition=condition_str), tuple(values)))
return employees
@@ -37,29 +37,29 @@ class LeavePeriod(Document):
def grant_leave_allocation(self, grade=None, department=None, designation=None,
- employee=None, carry_forward_leaves=0):
- employees = self.get_employees({
+ employee=None, carry_forward=0):
+ employee_records = self.get_employees({
"grade": grade,
"department": department,
"designation": designation,
"name": employee
})
- if employees:
- if len(employees) > 20:
+ if employee_records:
+ if len(employee_records) > 20:
frappe.enqueue(grant_leave_alloc_for_employees, timeout=600,
- employees=employees, leave_period=self, carry_forward_leaves=carry_forward_leaves)
+ employee_records=employee_records, leave_period=self, carry_forward=carry_forward)
else:
- grant_leave_alloc_for_employees(employees, self, carry_forward_leaves)
+ grant_leave_alloc_for_employees(employee_records, self, carry_forward)
else:
frappe.msgprint(_("No Employee Found"))
-def grant_leave_alloc_for_employees(employees, leave_period, carry_forward_leaves=0):
+def grant_leave_alloc_for_employees(employee_records, leave_period, carry_forward=0):
leave_allocations = []
- existing_allocations_for = get_existing_allocations(employees, leave_period.name)
+ existing_allocations_for = get_existing_allocations(list(employee_records.keys()), leave_period.name)
leave_type_details = get_leave_type_details()
count = 0
- for employee in employees:
+ for employee in employee_records.keys():
if employee in existing_allocations_for:
continue
count +=1
@@ -68,10 +68,10 @@ def grant_leave_alloc_for_employees(employees, leave_period, carry_forward_leave
for leave_policy_detail in leave_policy.leave_policy_details:
if not leave_type_details.get(leave_policy_detail.leave_type).is_lwp:
leave_allocation = create_leave_allocation(employee, leave_policy_detail.leave_type,
- leave_policy_detail.annual_allocation, leave_type_details, leave_period, carry_forward_leaves)
+ leave_policy_detail.annual_allocation, leave_type_details, leave_period, carry_forward, employee_records.get(employee))
leave_allocations.append(leave_allocation)
frappe.db.commit()
- frappe.publish_progress(count*100/len(set(employees) - set(existing_allocations_for)), title = _("Allocating leaves..."))
+ frappe.publish_progress(count*100/len(set(employee_records.keys()) - set(existing_allocations_for)), title = _("Allocating leaves..."))
if leave_allocations:
frappe.msgprint(_("Leaves has been granted sucessfully"))
@@ -100,21 +100,30 @@ def get_leave_type_details():
leave_type_details.setdefault(d.name, d)
return leave_type_details
-def create_leave_allocation(employee, leave_type, new_leaves_allocated, leave_type_details, leave_period, carry_forward_leaves):
- allocation = frappe.new_doc("Leave Allocation")
- allocation.employee = employee
- allocation.leave_type = leave_type
- allocation.from_date = leave_period.from_date
- allocation.to_date = leave_period.to_date
+def create_leave_allocation(employee, leave_type, new_leaves_allocated, leave_type_details, leave_period, carry_forward, date_of_joining):
+ ''' Creates leave allocation for the given employee in the provided leave period '''
+ if carry_forward and not leave_type_details.get(leave_type).is_carry_forward:
+ carry_forward = 0
+
+ # Calculate leaves at pro-rata basis for employees joining after the beginning of the given leave period
+ if getdate(date_of_joining) > getdate(leave_period.from_date):
+ remaining_period = ((date_diff(leave_period.to_date, date_of_joining) + 1) / (date_diff(leave_period.to_date, leave_period.from_date) + 1))
+ new_leaves_allocated = ceil(new_leaves_allocated * remaining_period)
+
# Earned Leaves and Compensatory Leaves are allocated by scheduler, initially allocate 0
if leave_type_details.get(leave_type).is_earned_leave == 1 or leave_type_details.get(leave_type).is_compensatory == 1:
new_leaves_allocated = 0
- allocation.new_leaves_allocated = new_leaves_allocated
- allocation.leave_period = leave_period.name
- if carry_forward_leaves:
- if leave_type_details.get(leave_type).is_carry_forward:
- allocation.carry_forward = carry_forward_leaves
+ allocation = frappe.get_doc(dict(
+ doctype="Leave Allocation",
+ employee=employee,
+ leave_type=leave_type,
+ from_date=leave_period.from_date,
+ to_date=leave_period.to_date,
+ new_leaves_allocated=new_leaves_allocated,
+ leave_period=leave_period.name,
+ carry_forward=carry_forward
+ ))
allocation.save(ignore_permissions = True)
allocation.submit()
return allocation.name
\ No newline at end of file
From 314647572cc0824dddc34d3057f2e321fa3d9176 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Mon, 5 Aug 2019 15:35:19 +0530
Subject: [PATCH 206/484] fix: check for old unexpired allocation
---
.../leave_encashment/leave_encashment.py | 2 +-
.../leave_ledger_entry/leave_ledger_entry.py | 28 +++++++++++++------
2 files changed, 20 insertions(+), 10 deletions(-)
diff --git a/erpnext/hr/doctype/leave_encashment/leave_encashment.py b/erpnext/hr/doctype/leave_encashment/leave_encashment.py
index d256c7f369..30529b6241 100644
--- a/erpnext/hr/doctype/leave_encashment/leave_encashment.py
+++ b/erpnext/hr/doctype/leave_encashment/leave_encashment.py
@@ -64,7 +64,7 @@ class LeaveEncashment(Document):
allocation = self.get_leave_allocation()
- self.leave_balance = allocation.total_leaves_allocated - get_unused_leaves(self.employee, self.leave_type, self.encashment_date)
+ self.leave_balance = allocation.total_leaves_allocated - get_unused_leaves(self.employee, self.leave_type, allocation.from_date, self.encashment_date)
encashable_days = self.leave_balance - frappe.db.get_value('Leave Type', self.leave_type, 'encashment_threshold_days')
self.encashable_days = encashable_days if encashable_days > 0 else 0
diff --git a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
index d19e15cf1a..8fca24127b 100644
--- a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
+++ b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
@@ -72,8 +72,11 @@ def get_previous_expiry_ledger_entry(ledger):
''' Returns the expiry ledger entry having same creation date as the ledger entry to be cancelled '''
creation_date = frappe.db.get_value("Leave Ledger Entry", filters={
'transaction_name': ledger.transaction_name,
- 'is_expired': 0
- }, fieldname=['creation']).strftime(DATE_FORMAT)
+ 'is_expired': 0,
+ 'transaction_type': 'Leave Allocation'
+ }, fieldname=['creation'])
+
+ creation_date = creation_date.strftime(DATE_FORMAT) if creation_date else ''
return frappe.db.get_value("Leave Ledger Entry", filters={
'creation': ('like', creation_date+"%"),
@@ -94,24 +97,31 @@ def process_expired_allocation():
if leave_type_records:
leave_type = [record[0] for record in leave_type_records]
- expired_allocation = frappe.get_all("Leave Ledger Entry",
+
+ expired_allocation = frappe.db.sql_list("""SELECT name
+ FROM `tabLeave Ledger Entry`
+ WHERE
+ `transaction_type`='Leave Allocation'
+ AND `is_expired`=1""")
+
+ expire_allocation = frappe.get_all("Leave Ledger Entry",
fields=['leaves', 'to_date', 'employee', 'leave_type', 'is_carry_forward', 'transaction_name as name', 'transaction_type'],
filters={
- 'to_date': add_days(today(), -1),
+ 'to_date': ("<", today()),
'transaction_type': 'Leave Allocation',
+ 'transaction_name': ('not in', expired_allocation)
},
or_filters={
'is_carry_forward': 0,
'leave_type': ('in', leave_type)
})
- if expired_allocation:
- create_expiry_ledger_entry(expired_allocation)
+ if expire_allocation:
+ create_expiry_ledger_entry(expire_allocation)
-def create_expiry_ledger_entry(expired_allocation):
+def create_expiry_ledger_entry(expire_allocation):
''' Create ledger entry for expired allocation '''
- for allocation in expired_allocation:
-
+ for allocation in expire_allocation:
if allocation.is_carry_forward:
expire_carried_forward_allocation(allocation)
else:
From 0c699f0726c133433402b43222ac47a290e436dd Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Wed, 7 Aug 2019 10:17:05 +0530
Subject: [PATCH 207/484] fix: Paid amount 0 while creating advanced payment
entry
Paid amount is set 0 while creating advanced payment entry
against multi-currency purchase order.
Solution: Populate paid amount value after applying conversion rate
---
erpnext/accounts/doctype/payment_entry/payment_entry.py | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py
index da6b167880..fd3f28f901 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.py
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py
@@ -933,10 +933,15 @@ def get_payment_entry(dt, dn, party_amount=None, bank_account=None, bank_amount=
paid_amount = abs(outstanding_amount)
if bank_amount:
received_amount = bank_amount
+ else:
+ received_amount = paid_amount * doc.conversion_rate
else:
received_amount = abs(outstanding_amount)
if bank_amount:
paid_amount = bank_amount
+ else:
+ # if party account currency and bank currency is different then populate paid amount as well
+ paid_amount = received_amount * doc.conversion_rate
pe = frappe.new_doc("Payment Entry")
pe.payment_type = payment_type
From cab8e9be891dfa102656723a7851eab5454938b5 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Wed, 7 Aug 2019 10:40:29 +0530
Subject: [PATCH 208/484] fix(timesheet): Hours automatically used to set 0
- Case: If the company had standard working hour set
and when the user creates a timesheet with same date for
"To" and "From" then the hours field automatically used to
get reset to 0 after saving the form.
---
erpnext/projects/doctype/timesheet/timesheet.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/projects/doctype/timesheet/timesheet.py b/erpnext/projects/doctype/timesheet/timesheet.py
index df9a6baf38..3c719227bd 100644
--- a/erpnext/projects/doctype/timesheet/timesheet.py
+++ b/erpnext/projects/doctype/timesheet/timesheet.py
@@ -96,7 +96,7 @@ class Timesheet(Document):
for time in self.time_logs:
if time.from_time and time.to_time:
- if flt(std_working_hours) > 0:
+ if flt(std_working_hours) and date_diff(time.to_time, time.from_time):
time.hours = flt(std_working_hours) * date_diff(time.to_time, time.from_time)
else:
if not time.hours:
From c5ae3cc120838341db71405ec228700873e066bb Mon Sep 17 00:00:00 2001
From: Sahil Khan
Date: Wed, 7 Aug 2019 16:41:13 +0550
Subject: [PATCH 209/484] bumped to version 12.0.5
---
erpnext/__init__.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/__init__.py b/erpnext/__init__.py
index 260478f730..0a735a1da1 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__ = '12.0.4'
+__version__ = '12.0.5'
def get_default_company(user=None):
'''Get default company for user'''
From 226083893392546b2cb4133cdce078fe62077817 Mon Sep 17 00:00:00 2001
From: Faris Ansari
Date: Wed, 7 Aug 2019 17:21:22 +0530
Subject: [PATCH 210/484] fix(Item Template): Fallback description string
Fixes #18572
---
erpnext/templates/generators/item/item_details.html | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/erpnext/templates/generators/item/item_details.html b/erpnext/templates/generators/item/item_details.html
index 8e560333ae..4cbecb0215 100644
--- a/erpnext/templates/generators/item/item_details.html
+++ b/erpnext/templates/generators/item/item_details.html
@@ -9,9 +9,9 @@
-{% if frappe.utils.strip_html(doc.web_long_description) %}
+{% if frappe.utils.strip_html(doc.web_long_description or '') %}
{{ doc.web_long_description | safe }}
-{% elif frappe.utils.strip_html(doc.description) %}
+{% elif frappe.utils.strip_html(doc.description or '') %}
{{ doc.description | safe }}
{% else %}
{{ _("No description given") }}
From b9f2a6048be8f448c7d6ba792c80786c712aa295 Mon Sep 17 00:00:00 2001
From: Himanshu Warekar
Date: Wed, 7 Aug 2019 18:21:38 +0530
Subject: [PATCH 211/484] test: fix test cases
---
.../doctype/quality_procedure/test_quality_procedure.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/erpnext/quality_management/doctype/quality_procedure/test_quality_procedure.py b/erpnext/quality_management/doctype/quality_procedure/test_quality_procedure.py
index 79f8771395..3289bb5a37 100644
--- a/erpnext/quality_management/doctype/quality_procedure/test_quality_procedure.py
+++ b/erpnext/quality_management/doctype/quality_procedure/test_quality_procedure.py
@@ -18,7 +18,7 @@ class TestQualityProcedure(unittest.TestCase):
def create_procedure():
procedure = frappe.get_doc({
"doctype": "Quality Procedure",
- "procedure": "_Test Quality Procedure",
+ "quality_procedure_name": "_Test Quality Procedure",
"processes": [
{
"process_description": "_Test Quality Procedure Table",
@@ -37,7 +37,7 @@ def create_procedure():
def create_nested_procedure():
nested_procedure = frappe.get_doc({
"doctype": "Quality Procedure",
- "procedure": "_Test Nested Quality Procedure",
+ "quality_procedure_name": "_Test Nested Quality Procedure",
"processes": [
{
"procedure": "PRC-_Test Quality Procedure"
From e5c733bdb399ba1a7d206207f7784297c9b7b3f1 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Thu, 8 Aug 2019 15:44:11 +0530
Subject: [PATCH 212/484] fix: Accounting period (#18630)
* fix: accounting period
* test: accounting period
* fix: account period creation
* fix: remove status field from accounting period
---
.../accounting_period/accounting_period.json | 36 +-----------
.../accounting_period/accounting_period.py | 11 ++--
.../test_accounting_period.py | 57 ++++++++++++-------
erpnext/accounts/general_ledger.py | 23 ++++++++
4 files changed, 70 insertions(+), 57 deletions(-)
diff --git a/erpnext/accounts/doctype/accounting_period/accounting_period.json b/erpnext/accounts/doctype/accounting_period/accounting_period.json
index ed30b83c26..57f8e32dc6 100644
--- a/erpnext/accounts/doctype/accounting_period/accounting_period.json
+++ b/erpnext/accounts/doctype/accounting_period/accounting_period.json
@@ -167,39 +167,7 @@
"set_only_once": 0,
"translatable": 0,
"unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "status",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Status",
- "length": 0,
- "no_copy": 0,
- "options": "Open\nClosed",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ },
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
@@ -273,7 +241,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2018-04-13 19:14:47.593753",
+ "modified": "2019-08-01 19:14:47.593753",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Accounting Period",
diff --git a/erpnext/accounts/doctype/accounting_period/accounting_period.py b/erpnext/accounts/doctype/accounting_period/accounting_period.py
index de45f3a252..180460c091 100644
--- a/erpnext/accounts/doctype/accounting_period/accounting_period.py
+++ b/erpnext/accounts/doctype/accounting_period/accounting_period.py
@@ -7,6 +7,8 @@ import frappe
from frappe.model.document import Document
from frappe import _
+class OverlapError(frappe.ValidationError): pass
+
class AccountingPeriod(Document):
def validate(self):
self.validate_overlap()
@@ -34,12 +36,13 @@ class AccountingPeriod(Document):
}, as_dict=True)
if len(existing_accounting_period) > 0:
- frappe.throw(_("Accounting Period overlaps with {0}".format(existing_accounting_period[0].get("name"))))
+ frappe.throw(_("Accounting Period overlaps with {0}")
+ .format(existing_accounting_period[0].get("name")), OverlapError)
def get_doctypes_for_closing(self):
docs_for_closing = []
- #if not self.closed_documents or len(self.closed_documents) == 0:
- doctypes = ["Sales Invoice", "Purchase Invoice", "Journal Entry", "Payroll Entry", "Bank Reconciliation", "Asset", "Purchase Order", "Sales Order", "Leave Application", "Leave Allocation", "Stock Entry"]
+ doctypes = ["Sales Invoice", "Purchase Invoice", "Journal Entry", "Payroll Entry", "Bank Reconciliation",
+ "Asset", "Purchase Order", "Sales Order", "Leave Application", "Leave Allocation", "Stock Entry"]
closed_doctypes = [{"document_type": doctype, "closed": 1} for doctype in doctypes]
for closed_doctype in closed_doctypes:
docs_for_closing.append(closed_doctype)
@@ -52,4 +55,4 @@ class AccountingPeriod(Document):
self.append('closed_documents', {
"document_type": doctype_for_closing.document_type,
"closed": doctype_for_closing.closed
- })
+ })
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/accounting_period/test_accounting_period.py b/erpnext/accounts/doctype/accounting_period/test_accounting_period.py
index 29deefdbed..022d7a7e80 100644
--- a/erpnext/accounts/doctype/accounting_period/test_accounting_period.py
+++ b/erpnext/accounts/doctype/accounting_period/test_accounting_period.py
@@ -5,23 +5,42 @@ from __future__ import unicode_literals
import frappe
import unittest
+from frappe.utils import nowdate, add_months
+from erpnext.accounts.general_ledger import ClosedAccountingPeriod
+from erpnext.accounts.doctype.accounting_period.accounting_period import OverlapError
+from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
-# class TestAccountingPeriod(unittest.TestCase):
-# def test_overlap(self):
-# ap1 = create_accounting_period({"start_date":"2018-04-01", "end_date":"2018-06-30", "company":"Wind Power LLC"})
-# ap1.save()
-# ap2 = create_accounting_period({"start_date":"2018-06-30", "end_date":"2018-07-10", "company":"Wind Power LLC"})
-# self.assertRaises(frappe.OverlapError, accounting_period_2.save())
-#
-# def tearDown(self):
-# pass
-#
-#
-# def create_accounting_period(**args):
-# accounting_period = frappe.new_doc("Accounting Period")
-# accounting_period.start_date = args.start_date or frappe.utils.datetime.date(2018, 4, 1)
-# accounting_period.end_date = args.end_date or frappe.utils.datetime.date(2018, 6, 30)
-# accounting_period.company = args.company
-# accounting_period.period_name = "_Test_Period_Name_1"
-#
-# return accounting_period
+class TestAccountingPeriod(unittest.TestCase):
+ def test_overlap(self):
+ ap1 = create_accounting_period(start_date = "2018-04-01",
+ end_date = "2018-06-30", company = "Wind Power LLC")
+ ap1.save()
+
+ ap2 = create_accounting_period(start_date = "2018-06-30",
+ end_date = "2018-07-10", company = "Wind Power LLC", period_name = "Test Accounting Period 1")
+ self.assertRaises(OverlapError, ap2.save)
+
+ def test_accounting_period(self):
+ ap1 = create_accounting_period(period_name = "Test Accounting Period 2")
+ ap1.save()
+
+ doc = create_sales_invoice(do_not_submit=1, cost_center = "_Test Company - _TC", warehouse = "Stores - _TC")
+ self.assertRaises(ClosedAccountingPeriod, doc.submit)
+
+ def tearDown(self):
+ for d in frappe.get_all("Accounting Period"):
+ frappe.delete_doc("Accounting Period", d.name)
+
+def create_accounting_period(**args):
+ args = frappe._dict(args)
+
+ accounting_period = frappe.new_doc("Accounting Period")
+ accounting_period.start_date = args.start_date or nowdate()
+ accounting_period.end_date = args.end_date or add_months(nowdate(), 1)
+ accounting_period.company = args.company or "_Test Company"
+ accounting_period.period_name =args.period_name or "_Test_Period_Name_1"
+ accounting_period.append("closed_documents", {
+ "document_type": 'Sales Invoice', "closed": 1
+ })
+
+ return accounting_period
\ No newline at end of file
diff --git a/erpnext/accounts/general_ledger.py b/erpnext/accounts/general_ledger.py
index be1448df3a..5c9e93d019 100644
--- a/erpnext/accounts/general_ledger.py
+++ b/erpnext/accounts/general_ledger.py
@@ -10,11 +10,13 @@ from erpnext.accounts.doctype.budget.budget import validate_expense_against_budg
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions
+class ClosedAccountingPeriod(frappe.ValidationError): pass
class StockAccountInvalidTransaction(frappe.ValidationError): pass
def make_gl_entries(gl_map, cancel=False, adv_adj=False, merge_entries=True, update_outstanding='Yes', from_repost=False):
if gl_map:
if not cancel:
+ validate_accounting_period(gl_map)
gl_map = process_gl_map(gl_map, merge_entries)
if gl_map and len(gl_map) > 1:
save_entries(gl_map, adv_adj, update_outstanding, from_repost)
@@ -23,6 +25,27 @@ def make_gl_entries(gl_map, cancel=False, adv_adj=False, merge_entries=True, upd
else:
delete_gl_entries(gl_map, adv_adj=adv_adj, update_outstanding=update_outstanding)
+def validate_accounting_period(gl_map):
+ accounting_periods = frappe.db.sql(""" SELECT
+ ap.name as name
+ FROM
+ `tabAccounting Period` ap, `tabClosed Document` cd
+ WHERE
+ ap.name = cd.parent
+ AND ap.company = %(company)s
+ AND cd.closed = 1
+ AND cd.document_type = %(voucher_type)s
+ AND %(date)s between ap.start_date and ap.end_date
+ """, {
+ 'date': gl_map[0].posting_date,
+ 'company': gl_map[0].company,
+ 'voucher_type': gl_map[0].voucher_type
+ }, as_dict=1)
+
+ if accounting_periods:
+ frappe.throw(_("You can't create accounting entries in the closed accounting period {0}")
+ .format(accounting_periods[0].name), ClosedAccountingPeriod)
+
def process_gl_map(gl_map, merge_entries=True):
if merge_entries:
gl_map = merge_similar_entries(gl_map)
From f19b7b9122061ac7400e12d6371aa04486a24c92 Mon Sep 17 00:00:00 2001
From: Aditya Hase
Date: Thu, 8 Aug 2019 15:48:09 +0530
Subject: [PATCH 213/484] fix(quickbooks): Do not build global search for
QuickBooks Migrator (#18627)
---
.../quickbooks_migrator.json | 734 ++----------------
1 file changed, 52 insertions(+), 682 deletions(-)
diff --git a/erpnext/erpnext_integrations/doctype/quickbooks_migrator/quickbooks_migrator.json b/erpnext/erpnext_integrations/doctype/quickbooks_migrator/quickbooks_migrator.json
index b156006e28..5428177914 100644
--- a/erpnext/erpnext_integrations/doctype/quickbooks_migrator/quickbooks_migrator.json
+++ b/erpnext/erpnext_integrations/doctype/quickbooks_migrator/quickbooks_migrator.json
@@ -1,843 +1,213 @@
{
- "allow_copy": 0,
- "allow_events_in_timeline": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
"beta": 1,
"creation": "2018-07-10 14:48:16.757030",
- "custom": 0,
- "docstatus": 0,
"doctype": "DocType",
- "document_type": "",
"editable_grid": 1,
"engine": "InnoDB",
+ "field_order": [
+ "status",
+ "application_settings",
+ "client_id",
+ "redirect_url",
+ "token_endpoint",
+ "application_column_break",
+ "client_secret",
+ "scope",
+ "api_endpoint",
+ "authorization_settings",
+ "authorization_endpoint",
+ "refresh_token",
+ "code",
+ "authorization_column_break",
+ "authorization_url",
+ "access_token",
+ "quickbooks_company_id",
+ "company_settings",
+ "company",
+ "default_shipping_account",
+ "default_warehouse",
+ "company_column_break",
+ "default_cost_center",
+ "undeposited_funds_account"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "status",
"fieldtype": "Select",
"hidden": 1,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Status",
- "length": 0,
- "no_copy": 0,
- "options": "Connecting to QuickBooks\nConnected to QuickBooks\nIn Progress\nComplete\nFailed",
- "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,
- "translatable": 0,
- "unique": 0
+ "options": "Connecting to QuickBooks\nConnected to QuickBooks\nIn Progress\nComplete\nFailed"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
"collapsible": 1,
"collapsible_depends_on": "eval:doc.client_id && doc.client_secret && doc.redirect_url",
- "columns": 0,
"fieldname": "application_settings",
"fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Application Settings",
- "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,
- "translatable": 0,
- "unique": 0
+ "label": "Application Settings"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "",
"fieldname": "client_id",
"fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
"in_list_view": 1,
- "in_standard_filter": 0,
"label": "Client ID",
- "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": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "reqd": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "",
"fieldname": "redirect_url",
"fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
"in_list_view": 1,
- "in_standard_filter": 0,
"label": "Redirect URL",
- "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": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "reqd": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"default": "https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer",
"fieldname": "token_endpoint",
"fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Token Endpoint",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
"read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "reqd": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "application_column_break",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 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,
- "translatable": 0,
- "unique": 0
+ "fieldtype": "Column Break"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "",
"fieldname": "client_secret",
"fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
"in_list_view": 1,
- "in_standard_filter": 0,
"label": "Client Secret",
- "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": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "reqd": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"default": "com.intuit.quickbooks.accounting",
"fieldname": "scope",
"fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
"in_list_view": 1,
- "in_standard_filter": 0,
"label": "Scope",
- "length": 0,
- "no_copy": 0,
- "options": "",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
"read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "reqd": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"default": "https://quickbooks.api.intuit.com/v3",
"fieldname": "api_endpoint",
"fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "API Endpoint",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
"read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "reqd": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
"collapsible": 1,
- "columns": 0,
"fieldname": "authorization_settings",
"fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Authorization Settings",
- "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,
- "translatable": 0,
- "unique": 0
+ "label": "Authorization Settings"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"default": "https://appcenter.intuit.com/connect/oauth2",
"fieldname": "authorization_endpoint",
"fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Authorization Endpoint",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
"read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "reqd": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "refresh_token",
"fieldtype": "Small Text",
"hidden": 1,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Refresh Token",
- "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,
- "translatable": 0,
- "unique": 0
+ "label": "Refresh Token"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "code",
"fieldtype": "Data",
"hidden": 1,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Code",
- "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,
- "translatable": 0,
- "unique": 0
+ "label": "Code"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "authorization_column_break",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 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,
- "translatable": 0,
- "unique": 0
+ "fieldtype": "Column Break"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "authorization_url",
"fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Authorization URL",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
"read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "reqd": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "access_token",
"fieldtype": "Small Text",
"hidden": 1,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Access Token",
- "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,
- "translatable": 0,
- "unique": 0
+ "label": "Access Token"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "quickbooks_company_id",
"fieldtype": "Data",
"hidden": 1,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Quickbooks Company ID",
- "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,
- "translatable": 0,
- "unique": 0
+ "label": "Quickbooks Company ID"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "company_settings",
"fieldtype": "Section Break",
"hidden": 1,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Company Settings",
- "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,
- "translatable": 0,
- "unique": 0
+ "label": "Company Settings"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "company",
"fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Company",
- "length": 0,
- "no_copy": 0,
- "options": "Company",
- "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,
- "translatable": 0,
- "unique": 0
+ "options": "Company"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "default_shipping_account",
"fieldtype": "Link",
"hidden": 1,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Default Shipping Account",
- "length": 0,
- "no_copy": 0,
- "options": "Account",
- "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,
- "translatable": 0,
- "unique": 0
+ "options": "Account"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "default_warehouse",
"fieldtype": "Link",
"hidden": 1,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Default Warehouse",
- "length": 0,
- "no_copy": 0,
- "options": "Warehouse",
- "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,
- "translatable": 0,
- "unique": 0
+ "options": "Warehouse"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "company_column_break",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 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,
- "translatable": 0,
- "unique": 0
+ "fieldtype": "Column Break"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "default_cost_center",
"fieldtype": "Link",
"hidden": 1,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Default Cost Center",
- "length": 0,
- "no_copy": 0,
- "options": "Cost Center",
- "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,
- "translatable": 0,
- "unique": 0
+ "options": "Cost Center"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "undeposited_funds_account",
"fieldtype": "Link",
"hidden": 1,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Undeposited Funds Account",
- "length": 0,
- "no_copy": 0,
- "options": "Account",
- "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,
- "translatable": 0,
- "unique": 0
+ "options": "Account"
}
],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
"issingle": 1,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2018-10-17 03:12:53.506229",
+ "modified": "2019-08-07 15:26:00.653433",
"modified_by": "Administrator",
"module": "ERPNext Integrations",
"name": "QuickBooks Migrator",
- "name_case": "",
"owner": "Administrator",
"permissions": [
{
- "amend": 0,
- "cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
"print": 1,
"read": 1,
- "report": 0,
"role": "System Manager",
- "set_user_permissions": 0,
"share": 1,
- "submit": 0,
"write": 1
}
],
"quick_entry": 1,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 1,
"sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 0,
- "track_seen": 0,
- "track_views": 0
+ "sort_order": "DESC"
}
\ No newline at end of file
From df7644a96d8b2d91d7b882c3f8e18949c354681d Mon Sep 17 00:00:00 2001
From: Faris Ansari
Date: Thu, 8 Aug 2019 15:50:24 +0530
Subject: [PATCH 214/484] fix: Show created serial nos as links in message
(#18635)
Fixes #18623
---
erpnext/stock/doctype/serial_no/serial_no.py | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/erpnext/stock/doctype/serial_no/serial_no.py b/erpnext/stock/doctype/serial_no/serial_no.py
index c203f8baa3..409a864678 100644
--- a/erpnext/stock/doctype/serial_no/serial_no.py
+++ b/erpnext/stock/doctype/serial_no/serial_no.py
@@ -369,10 +369,11 @@ def auto_make_serial_nos(args):
elif args.get('actual_qty', 0) > 0:
created_numbers.append(make_serial_no(serial_no, args))
- if len(created_numbers) == 1:
- frappe.msgprint(_("Serial No {0} created").format(created_numbers[0]))
- elif len(created_numbers) > 0:
- frappe.msgprint(_("The following serial numbers were created: {0}").format(', '.join(created_numbers)))
+ form_links = list(map(lambda d: frappe.utils.get_link_to_form('Serial No', d), created_numbers))
+ if len(form_links) == 1:
+ frappe.msgprint(_("Serial No {0} created").format(form_links[0]))
+ elif len(form_links) > 0:
+ frappe.msgprint(_("The following serial numbers were created: {0}").format(', '.join(form_links)))
def get_item_details(item_code):
return frappe.db.sql("""select name, has_batch_no, docstatus,
From 04b42600b094a8ac10e31308aa6f3f4c779f470c Mon Sep 17 00:00:00 2001
From: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com>
Date: Thu, 8 Aug 2019 15:51:50 +0530
Subject: [PATCH 215/484] fix: Changes in print format due to attribute name
changes in frappe (#18641)
---
.../sales_invoice_return/sales_invoice_return.html | 8 ++++----
erpnext/templates/print_formats/includes/taxes.html | 4 ++--
erpnext/templates/print_formats/includes/total.html | 4 ++--
3 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/erpnext/accounts/print_format/sales_invoice_return/sales_invoice_return.html b/erpnext/accounts/print_format/sales_invoice_return/sales_invoice_return.html
index 889b7f71aa..2c015192c4 100644
--- a/erpnext/accounts/print_format/sales_invoice_return/sales_invoice_return.html
+++ b/erpnext/accounts/print_format/sales_invoice_return/sales_invoice_return.html
@@ -4,7 +4,7 @@
{%- macro render_currency(df, doc) -%}
+ {%- if doc.align_labels_right %} text-right{%- endif -%}">
{{ _(df.label) }}
@@ -23,7 +23,7 @@
{%- for charge in data -%}
{%- if (charge.tax_amount or doc.flags.print_taxes_with_zero_amount) and (not charge.included_in_print_rate or doc.flags.show_inclusive_tax_in_print) -%}
-
+
{{ charge.get_formatted("description") }}
{{ frappe.utils.fmt_money((charge.tax_amount)|int|abs, currency=doc.currency) }}
@@ -103,8 +103,8 @@
{% for section in page %}
{% if section.columns.fields %}
- {%- if doc._line_breaks and loop.index != 1 -%}
{%- endif -%}
- {%- if doc._show_section_headings and section.label and section.has_data -%}
+ {%- if doc.print_line_breaks and loop.index != 1 -%}
{%- endif -%}
+ {%- if doc.print_section_headings and section.label and section.has_data -%}
{{ _(section.label) }}
{% endif %}
{%- endif -%}
diff --git a/erpnext/templates/print_formats/includes/taxes.html b/erpnext/templates/print_formats/includes/taxes.html
index 377f9a34bd..6e984f3901 100644
--- a/erpnext/templates/print_formats/includes/taxes.html
+++ b/erpnext/templates/print_formats/includes/taxes.html
@@ -1,7 +1,7 @@
{%- macro render_discount_amount(doc) -%}
{%- if doc.discount_amount -%}
-
+
{{ _(doc.meta.get_label('discount_amount')) }}
- {{ doc.get_formatted("discount_amount", doc) }}
@@ -19,7 +19,7 @@
{%- for charge in data -%}
{%- if (charge.tax_amount or doc.flags.print_taxes_with_zero_amount) and (not charge.included_in_print_rate or doc.flags.show_inclusive_tax_in_print) -%}
-
+
{{ charge.get_formatted("description") }}
{{ frappe.format_value(frappe.utils.flt(charge.tax_amount),
diff --git a/erpnext/templates/print_formats/includes/total.html b/erpnext/templates/print_formats/includes/total.html
index c13bf92760..81799809ba 100644
--- a/erpnext/templates/print_formats/includes/total.html
+++ b/erpnext/templates/print_formats/includes/total.html
@@ -1,12 +1,12 @@
{% if doc.flags.show_inclusive_tax_in_print %}
-
+
{{ _("Total (Without Tax)") }}
{{ doc.get_formatted("net_total", doc) }}
{% else %}
-
+
{{ _(doc.meta.get_label('total')) }}
{{ doc.get_formatted("total", doc) }}
From f729eed03563b44e64603450af38b6c8675d4d52 Mon Sep 17 00:00:00 2001
From: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com>
Date: Thu, 8 Aug 2019 15:52:25 +0530
Subject: [PATCH 216/484] fix: Show Cr or Dr symbol in chart of accounts based
on balance (#18654)
* fix: Show Cr or Dr symbol in chart of accounts based on balance
* fix: Typo fix in comment
---
erpnext/accounts/doctype/account/account_tree.js | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/erpnext/accounts/doctype/account/account_tree.js b/erpnext/accounts/doctype/account/account_tree.js
index b70c6d2b27..6fdd797437 100644
--- a/erpnext/accounts/doctype/account/account_tree.js
+++ b/erpnext/accounts/doctype/account/account_tree.js
@@ -121,7 +121,10 @@ frappe.treeview_settings["Account"] = {
},
onrender: function(node) {
if(frappe.boot.user.can_read.indexOf("GL Entry") !== -1){
- var dr_or_cr = in_list(["Liability", "Income", "Equity"], node.data.root_type) ? "Cr" : "Dr";
+
+ // show Dr if positive since balance is calculated as debit - credit else show Cr
+ let dr_or_cr = node.data.balance_in_account_currency > 0 ? "Dr": "Cr";
+
if (node.data && node.data.balance!==undefined) {
$('
'
+ (node.data.balance_in_account_currency ?
From 5cbe6160cade4236894af6bcd41f1e195145042c Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Thu, 8 Aug 2019 17:06:15 +0530
Subject: [PATCH 217/484] feat: consider carry forwarded leaves on creation of
encashment
---
.../leave_allocation/leave_allocation.js | 8 ++--
.../leave_allocation/leave_allocation.json | 26 ++++++++-----
.../leave_allocation/leave_allocation.py | 39 ++++++++++++-------
.../leave_encashment/leave_encashment.py | 7 ++--
.../leave_ledger_entry/leave_ledger_entry.py | 9 +++--
.../hr/doctype/leave_period/leave_period.py | 2 +-
erpnext/hr/utils.py | 2 +-
.../v12_0/generate_leave_ledger_entries.py | 13 ++++++-
8 files changed, 69 insertions(+), 37 deletions(-)
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.js b/erpnext/hr/doctype/leave_allocation/leave_allocation.js
index 8c910a200a..210a73cfe5 100755
--- a/erpnext/hr/doctype/leave_allocation/leave_allocation.js
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.js
@@ -63,14 +63,14 @@ frappe.ui.form.on("Leave Allocation", {
frm.trigger("calculate_total_leaves_allocated");
},
- carry_forwarded_leaves: function(frm) {
+ unused_leaves: function(frm) {
frm.set_value("total_leaves_allocated",
- flt(frm.doc.carry_forwarded_leaves) + flt(frm.doc.new_leaves_allocated));
+ flt(frm.doc.unused_leaves) + flt(frm.doc.new_leaves_allocated));
},
new_leaves_allocated: function(frm) {
frm.set_value("total_leaves_allocated",
- flt(frm.doc.carry_forwarded_leaves) + flt(frm.doc.new_leaves_allocated));
+ flt(frm.doc.unused_leaves) + flt(frm.doc.new_leaves_allocated));
},
leave_policy: function(frm) {
@@ -93,7 +93,7 @@ frappe.ui.form.on("Leave Allocation", {
}
})
} else if (cint(frm.doc.carry_forward) == 0) {
- frm.set_value("carry_forwarded_leaves", 0);
+ frm.set_value("unused_leaves", 0);
frm.set_value("total_leaves_allocated", flt(frm.doc.new_leaves_allocated));
}
}
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.json b/erpnext/hr/doctype/leave_allocation/leave_allocation.json
index 1618c67d3d..007497e34a 100644
--- a/erpnext/hr/doctype/leave_allocation/leave_allocation.json
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.json
@@ -17,13 +17,14 @@
"section_break_6",
"new_leaves_allocated",
"carry_forward",
- "carry_forwarded_leaves",
+ "unused_leaves",
"total_leaves_allocated",
"total_leaves_encashed",
"column_break_10",
"compensatory_request",
"leave_period",
"leave_policy",
+ "carry_forwarded_leaves_count",
"expired",
"amended_from",
"notes",
@@ -119,7 +120,7 @@
},
{
"depends_on": "carry_forward",
- "fieldname": "carry_forwarded_leaves",
+ "fieldname": "unused_leaves",
"fieldtype": "Float",
"label": "Unused leaves",
"read_only": 1
@@ -167,6 +168,15 @@
"options": "Leave Policy",
"read_only": 1
},
+ {
+ "default": "0",
+ "fieldname": "expired",
+ "fieldtype": "Check",
+ "hidden": 1,
+ "in_standard_filter": 1,
+ "label": "Expired",
+ "read_only": 1
+ },
{
"fieldname": "amended_from",
"fieldtype": "Link",
@@ -194,19 +204,17 @@
"width": "300px"
},
{
- "default": "0",
- "fieldname": "expired",
- "fieldtype": "Check",
- "hidden": 1,
- "in_standard_filter": 1,
- "label": "Expired",
+ "depends_on": "carry_forwarded_leaves_count",
+ "fieldname": "carry_forwarded_leaves_count",
+ "fieldtype": "Float",
+ "label": "Carry Forwarded Leaves",
"read_only": 1
}
],
"icon": "fa fa-ok",
"idx": 1,
"is_submittable": 1,
- "modified": "2019-07-22 17:50:39.591195",
+ "modified": "2019-08-08 15:08:42.440909",
"modified_by": "Administrator",
"module": "HR",
"name": "Leave Allocation",
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.py b/erpnext/hr/doctype/leave_allocation/leave_allocation.py
index 2374e469a5..5e81999765 100755
--- a/erpnext/hr/doctype/leave_allocation/leave_allocation.py
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.py
@@ -50,6 +50,8 @@ class LeaveAllocation(Document):
def on_cancel(self):
self.create_leave_ledger_entry(submit=False)
+ if self.carry_forward:
+ self.set_carry_forwarded_leaves_in_previous_allocation(on_cancel=True)
def validate_period(self):
if date_diff(self.to_date, self.from_date) <= 0:
@@ -89,24 +91,33 @@ class LeaveAllocation(Document):
BackDatedAllocationError)
def set_total_leaves_allocated(self):
- self.carry_forwarded_leaves = get_carry_forwarded_leaves(self.employee,
+ self.unused_leaves = get_carry_forwarded_leaves(self.employee,
self.leave_type, self.from_date, self.carry_forward)
- self.total_leaves_allocated = flt(self.carry_forwarded_leaves) + flt(self.new_leaves_allocated)
- self.maintain_carry_forwarded_leaves()
+ self.total_leaves_allocated = flt(self.unused_leaves) + flt(self.new_leaves_allocated)
+
+ if self.carry_forward:
+ self.maintain_carry_forwarded_leaves()
+ self.set_carry_forwarded_leaves_in_previous_allocation()
if not self.total_leaves_allocated and not frappe.db.get_value("Leave Type", self.leave_type, "is_earned_leave") and not frappe.db.get_value("Leave Type", self.leave_type, "is_compensatory"):
- frappe.throw(_("Total leaves allocated is mandatory for Leave Type {0}".format(self.leave_type)))
+ frappe.throw(_("Total leaves allocated is mandatory for Leave Type {0}").format(self.leave_type))
def maintain_carry_forwarded_leaves(self):
- ''' reduce the carry forwarded leaves to be within the maximum allowed leaves '''
- if not self.carry_forward:
- return
+ ''' Reduce the carry forwarded leaves to be within the maximum allowed leaves '''
+
max_leaves_allowed = frappe.db.get_value("Leave Type", self.leave_type, "max_leaves_allowed")
if self.new_leaves_allocated <= max_leaves_allowed <= self.total_leaves_allocated:
- self.carry_forwarded_leaves = max_leaves_allowed - flt(self.new_leaves_allocated)
+ self.unused_leaves = max_leaves_allowed - flt(self.new_leaves_allocated)
self.total_leaves_allocated = flt(max_leaves_allowed)
+ def set_carry_forwarded_leaves_in_previous_allocation(self, on_cancel=False):
+ ''' Set carry forwarded leaves in previous allocation '''
+ previous_allocation = get_previous_allocation(self.from_date, self.leave_type, self.employee)
+ if on_cancel:
+ self.unused_leaves = 0.0
+ frappe.db.set_value("Leave Allocation", previous_allocation.name, 'carry_forwarded_leaves_count', self.unused_leaves)
+
def validate_total_leaves_allocated(self):
# Adding a day to include To Date in the difference
date_difference = date_diff(self.to_date, self.from_date) + 1
@@ -114,10 +125,10 @@ class LeaveAllocation(Document):
frappe.throw(_("Total allocated leaves are more than days in the period"), OverAllocationError)
def create_leave_ledger_entry(self, submit=True):
- if self.carry_forwarded_leaves:
+ if self.unused_leaves:
expiry_days = frappe.db.get_value("Leave Type", self.leave_type, "expire_carried_forward_leaves")
args = dict(
- leaves=self.carry_forwarded_leaves,
+ leaves=self.unused_leaves,
from_date=self.from_date,
to_date=add_days(self.from_date, expiry_days - 1) if expiry_days else self.to_date,
is_carry_forward=1
@@ -142,7 +153,7 @@ def get_previous_allocation(from_date, leave_type, employee):
'docstatus': 1
},
order_by='to_date DESC',
- fieldname=['name', 'from_date', 'to_date'], as_dict=1)
+ fieldname=['name', 'from_date', 'to_date', 'employee', 'leave_type'], as_dict=1)
def get_leave_allocation_for_period(employee, leave_type, from_date, to_date):
leave_allocated = 0
@@ -170,13 +181,13 @@ def get_leave_allocation_for_period(employee, leave_type, from_date, to_date):
@frappe.whitelist()
def get_carry_forwarded_leaves(employee, leave_type, date, carry_forward=None):
''' Returns carry forwarded leaves for the given employee '''
- carry_forwarded_leaves = 0.0
+ unused_leaves = 0.0
previous_allocation = get_previous_allocation(date, leave_type, employee)
if carry_forward and previous_allocation:
validate_carry_forward(leave_type)
- carry_forwarded_leaves = get_unused_leaves(employee, leave_type, previous_allocation.from_date, previous_allocation.to_date)
+ unused_leaves = get_unused_leaves(employee, leave_type, previous_allocation.from_date, previous_allocation.to_date)
- return carry_forwarded_leaves
+ return unused_leaves
def get_unused_leaves(employee, leave_type, from_date, to_date):
''' Returns unused leaves between the given period while skipping leave allocation expiry '''
diff --git a/erpnext/hr/doctype/leave_encashment/leave_encashment.py b/erpnext/hr/doctype/leave_encashment/leave_encashment.py
index 30529b6241..42f0179baf 100644
--- a/erpnext/hr/doctype/leave_encashment/leave_encashment.py
+++ b/erpnext/hr/doctype/leave_encashment/leave_encashment.py
@@ -64,7 +64,8 @@ class LeaveEncashment(Document):
allocation = self.get_leave_allocation()
- self.leave_balance = allocation.total_leaves_allocated - get_unused_leaves(self.employee, self.leave_type, allocation.from_date, self.encashment_date)
+ self.leave_balance = allocation.total_leaves_allocated - allocation.carry_forwarded_leaves_count\
+ - get_unused_leaves(self.employee, self.leave_type, allocation.from_date, self.encashment_date)
encashable_days = self.leave_balance - frappe.db.get_value('Leave Type', self.leave_type, 'encashment_threshold_days')
self.encashable_days = encashable_days if encashable_days > 0 else 0
@@ -76,9 +77,9 @@ class LeaveEncashment(Document):
return True
def get_leave_allocation(self):
- leave_allocation = frappe.db.sql("""select name, to_date, total_leaves_allocated from `tabLeave Allocation` where '{0}'
+ leave_allocation = frappe.db.sql("""select name, to_date, total_leaves_allocated, carry_forwarded_leaves_count from `tabLeave Allocation` where '{0}'
between from_date and to_date and docstatus=1 and leave_type='{1}'
- and employee= '{2}'""".format(self.encashment_date or getdate(nowdate()), self.leave_type, self.employee), as_dict=1)
+ and employee= '{2}'""".format(self.encashment_date or getdate(nowdate()), self.leave_type, self.employee), as_dict=1) #nosec
return leave_allocation[0] if leave_allocation else None
diff --git a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
index 8fca24127b..33e4ea0909 100644
--- a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
+++ b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
@@ -104,7 +104,7 @@ def process_expired_allocation():
`transaction_type`='Leave Allocation'
AND `is_expired`=1""")
- expire_allocation = frappe.get_all("Leave Ledger Entry",
+ expire_allocation = frappe.get_all("Leave Ledger Entry",
fields=['leaves', 'to_date', 'employee', 'leave_type', 'is_carry_forward', 'transaction_name as name', 'transaction_type'],
filters={
'to_date': ("<", today()),
@@ -119,9 +119,9 @@ def process_expired_allocation():
if expire_allocation:
create_expiry_ledger_entry(expire_allocation)
-def create_expiry_ledger_entry(expire_allocation):
+def create_expiry_ledger_entry(allocations):
''' Create ledger entry for expired allocation '''
- for allocation in expire_allocation:
+ for allocation in allocations:
if allocation.is_carry_forward:
expire_carried_forward_allocation(allocation)
else:
@@ -138,7 +138,7 @@ def get_remaining_leaves(allocation):
@frappe.whitelist()
def expire_allocation(allocation, expiry_date=None):
- ''' expires allocation '''
+ ''' expires non-carry forwarded allocation '''
leaves = get_remaining_leaves(allocation)
expiry_date = expiry_date if expiry_date else allocation.to_date
@@ -146,6 +146,7 @@ def expire_allocation(allocation, expiry_date=None):
args = dict(
leaves=flt(leaves) * -1,
transaction_name=allocation.name,
+ transaction_type='Leave Allocation',
from_date=expiry_date,
to_date=expiry_date,
is_carry_forward=0,
diff --git a/erpnext/hr/doctype/leave_period/leave_period.py b/erpnext/hr/doctype/leave_period/leave_period.py
index 7b0f882035..a7de7185c9 100644
--- a/erpnext/hr/doctype/leave_period/leave_period.py
+++ b/erpnext/hr/doctype/leave_period/leave_period.py
@@ -22,7 +22,7 @@ class LeavePeriod(Document):
condition_str = " and " + " and ".join(conditions) if len(conditions) else ""
- employees = frappe._dict(frappe.db.sql("select name, date_of_joining from tabEmployee where status='Active' {condition}"
+ employees = frappe._dict(frappe.db.sql("select name, date_of_joining from tabEmployee where status='Active' {condition}" #nosec
.format(condition=condition_str), tuple(values)))
return employees
diff --git a/erpnext/hr/utils.py b/erpnext/hr/utils.py
index bf09de86e7..4fe9f6b285 100644
--- a/erpnext/hr/utils.py
+++ b/erpnext/hr/utils.py
@@ -318,7 +318,7 @@ def create_earned_leave_ledger_entry(allocation, earned_leaves, date):
''' Create leave ledger entry based on the earned leave frequency '''
allocation.new_leaves_allocated = earned_leaves
allocation.from_date = date
- allocation.carry_forwarded_leaves = 0
+ allocation.unused_leaves = 0
allocation.create_leave_ledger_entry()
def check_frequency_hit(from_date, to_date, frequency):
diff --git a/erpnext/patches/v12_0/generate_leave_ledger_entries.py b/erpnext/patches/v12_0/generate_leave_ledger_entries.py
index 7dfdcc162b..c1e1b4f3b2 100644
--- a/erpnext/patches/v12_0/generate_leave_ledger_entries.py
+++ b/erpnext/patches/v12_0/generate_leave_ledger_entries.py
@@ -13,11 +13,22 @@ def execute():
if frappe.db.a_row_exists("Leave Ledger Entry"):
return
+ if not frappe.get_meta("Leave Allocation").has_field("unused_leaves"):
+ frappe.reload_doc("HR", "doctype", "Leave Allocation")
+ update_leave_allocation_fieldname()
+
generate_allocation_ledger_entries()
generate_application_leave_ledger_entries()
generate_encashment_leave_ledger_entries()
generate_expiry_allocation_ledger_entries()
+def update_leave_allocation_fieldname():
+ ''' maps data from old field to the new field '''
+ frappe.db.sql("""
+ UPDATE `tabLeave Allocation`
+ SET `unused_leaves` = `carry_forwarded_leaves`
+ """)
+
def generate_allocation_ledger_entries():
''' fix ledger entries for missing leave allocation transaction '''
allocation_list = get_allocation_records()
@@ -64,7 +75,7 @@ def get_allocation_records():
employee,
leave_type,
new_leaves_allocated,
- carry_forwarded_leaves,
+ unused_leaves,
from_date,
to_date,
carry_forward
From 9bc4232af619503028400ffdc446428feb81691d Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Thu, 8 Aug 2019 17:11:08 +0530
Subject: [PATCH 218/484] feat: calculate remaining leaves both multiple
simultaneous allocation
---
.../leave_allocation/test_leave_allocation.js | 2 +-
.../leave_allocation/test_leave_allocation.py | 10 ++++------
.../leave_application/leave_application.py | 16 ++++++++++------
.../leave_application/test_leave_application.py | 15 ++++++++++++++-
4 files changed, 29 insertions(+), 14 deletions(-)
diff --git a/erpnext/hr/doctype/leave_allocation/test_leave_allocation.js b/erpnext/hr/doctype/leave_allocation/test_leave_allocation.js
index b8f4fafa6d..0ef78f2f88 100644
--- a/erpnext/hr/doctype/leave_allocation/test_leave_allocation.js
+++ b/erpnext/hr/doctype/leave_allocation/test_leave_allocation.js
@@ -34,7 +34,7 @@ QUnit.test("Test: Leave allocation [HR]", function (assert) {
() => assert.equal(today_date, cur_frm.doc.from_date,
"from date correctly set"),
// check for total leaves
- () => assert.equal(cur_frm.doc.carry_forwarded_leaves + 2, cur_frm.doc.total_leaves_allocated,
+ () => assert.equal(cur_frm.doc.unused_leaves + 2, cur_frm.doc.total_leaves_allocated,
"total leave calculation is correctly set"),
() => done()
]);
diff --git a/erpnext/hr/doctype/leave_allocation/test_leave_allocation.py b/erpnext/hr/doctype/leave_allocation/test_leave_allocation.py
index 4f4e0ab1fc..8f876ae7ce 100644
--- a/erpnext/hr/doctype/leave_allocation/test_leave_allocation.py
+++ b/erpnext/hr/doctype/leave_allocation/test_leave_allocation.py
@@ -80,7 +80,7 @@ class TestLeaveAllocation(unittest.TestCase):
leave_type="_Test_CF_leave",
from_date=add_months(nowdate(), -12),
to_date=add_months(nowdate(), -1),
- carry_forward=1)
+ carry_forward=0)
leave_allocation.submit()
# leave allocation with carry forward from previous allocation
@@ -89,7 +89,7 @@ class TestLeaveAllocation(unittest.TestCase):
carry_forward=1)
leave_allocation_1.submit()
- self.assertEquals(leave_allocation.total_leaves_allocated, leave_allocation_1.carry_forwarded_leaves)
+ self.assertEquals(leave_allocation.total_leaves_allocated, leave_allocation_1.unused_leaves)
def test_carry_forward_leaves_expiry(self):
frappe.db.sql("delete from `tabLeave Allocation`")
@@ -105,11 +105,9 @@ class TestLeaveAllocation(unittest.TestCase):
leave_type="_Test_CF_leave_expiry",
from_date=add_months(nowdate(), -24),
to_date=add_months(nowdate(), -12),
- carry_forward=1)
+ carry_forward=0)
leave_allocation.submit()
- expire_allocation(leave_allocation)
-
leave_allocation = create_leave_allocation(
leave_type="_Test_CF_leave_expiry",
from_date=add_days(nowdate(), -90),
@@ -128,7 +126,7 @@ class TestLeaveAllocation(unittest.TestCase):
to_date=add_months(nowdate(), 12))
leave_allocation_1.submit()
- self.assertEquals(leave_allocation_1.carry_forwarded_leaves, leave_allocation.new_leaves_allocated)
+ self.assertEquals(leave_allocation_1.unused_leaves, leave_allocation.new_leaves_allocated)
def test_creation_of_leave_ledger_entry_on_submit(self):
frappe.db.sql("delete from `tabLeave Allocation`")
diff --git a/erpnext/hr/doctype/leave_application/leave_application.py b/erpnext/hr/doctype/leave_application/leave_application.py
index 2e43721a58..0aa8849e87 100755
--- a/erpnext/hr/doctype/leave_application/leave_application.py
+++ b/erpnext/hr/doctype/leave_application/leave_application.py
@@ -387,10 +387,12 @@ class LeaveApplication(Document):
create_leave_ledger_entry(self, args, submit)
def get_allocation_expiry(employee, leave_type, to_date, from_date):
+ ''' Returns expiry of carry forward allocation in leave ledger entry '''
expiry = frappe.get_all("Leave Ledger Entry",
filters={
'employee': employee,
'leave_type': leave_type,
+ 'is_carry_forward': 1,
'transaction_type': 'Leave Allocation',
'to_date': ['between', (from_date, to_date)]
},fields=['to_date'])
@@ -487,7 +489,7 @@ def get_leave_allocation_records(employee, date, leave_type=None):
"from_date": d.from_date,
"to_date": d.to_date,
"total_leaves_allocated": flt(d.cf_leaves) + flt(d.new_leaves),
- "carry_forwarded_leaves": d.cf_leaves,
+ "unused_leaves": d.cf_leaves,
"new_leaves_allocated": d.new_leaves,
"leave_type": d.leave_type
}))
@@ -515,12 +517,14 @@ def get_remaining_leaves(allocation, leaves_taken, date, expiry):
return remaining_leaves
- if expiry and allocation.carry_forwarded_leaves:
- remaining_leaves = _get_remaining_leaves(allocation.carry_forwarded_leaves, expiry)
+ total_leaves = allocation.total_leaves_allocated
- return flt(allocation.new_leaves_allocated) + flt(remaining_leaves)
- else:
- return _get_remaining_leaves(allocation.total_leaves_allocated, allocation.to_date)
+ if expiry and allocation.unused_leaves:
+ remaining_leaves = _get_remaining_leaves(allocation.unused_leaves, expiry)
+
+ total_leaves = flt(allocation.new_leaves_allocated) + flt(remaining_leaves)
+
+ return _get_remaining_leaves(total_leaves, allocation.to_date)
def get_leaves_for_period(employee, leave_type, from_date, to_date):
leave_entries = get_leave_entries(employee, leave_type, from_date, to_date)
diff --git a/erpnext/hr/doctype/leave_application/test_leave_application.py b/erpnext/hr/doctype/leave_application/test_leave_application.py
index 709a2f57df..0f7bf86b22 100644
--- a/erpnext/hr/doctype/leave_application/test_leave_application.py
+++ b/erpnext/hr/doctype/leave_application/test_leave_application.py
@@ -542,6 +542,19 @@ class TestLeaveApplication(unittest.TestCase):
self.assertEquals(leave_ledger_entry[0].leaves, -9)
self.assertEquals(leave_ledger_entry[1].leaves, -2)
+ def test_leave_application_creation_after_expiry(self):
+ # test leave balance for carry forwarded allocation
+ employee = get_employee()
+ leave_type = create_leave_type(
+ leave_type_name="_Test_CF_leave_expiry",
+ is_carry_forward=1,
+ expire_carried_forward_leaves=90)
+ leave_type.submit()
+
+ create_carry_forwarded_allocation(employee, leave_type)
+
+ self.assertEquals(get_leave_balance_on(employee.name, leave_type.name, add_days(nowdate(), -85), add_days(nowdate(), -84)), 0)
+
def create_carry_forwarded_allocation(employee, leave_type):
# initial leave allocation
leave_allocation = create_leave_allocation(
@@ -550,7 +563,7 @@ def create_carry_forwarded_allocation(employee, leave_type):
employee_name=employee.employee_name,
from_date=add_months(nowdate(), -24),
to_date=add_months(nowdate(), -12),
- carry_forward=1)
+ carry_forward=0)
leave_allocation.submit()
leave_allocation = create_leave_allocation(
From 536e6bf57cac98af4b99a0d6e2e5fd46e71420f2 Mon Sep 17 00:00:00 2001
From: rohitwaghchaure
Date: Thu, 8 Aug 2019 17:40:57 +0530
Subject: [PATCH 219/484] fix: group by condition in the payment reconciliation
(#18657)
---
.../doctype/payment_reconciliation/payment_reconciliation.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
index b74eed5841..5bb269ee7e 100644
--- a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
+++ b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
@@ -93,7 +93,7 @@ class PaymentReconciliation(Document):
and `tab{doc}`.is_return = 1 and `tabGL Entry`.against_voucher_type = %(voucher_type)s
and `tab{doc}`.docstatus = 1 and `tabGL Entry`.party = %(party)s
and `tabGL Entry`.party_type = %(party_type)s and `tabGL Entry`.account = %(account)s
- GROUP BY `tabSales Invoice`.name
+ GROUP BY `tab{doc}`.name
Having
amount > 0
""".format(doc=voucher_type, dr_or_cr=dr_or_cr, reconciled_dr_or_cr=reconciled_dr_or_cr), {
From 9f9184c908212dc87b8ec435154e6a00220685d0 Mon Sep 17 00:00:00 2001
From: rohitwaghchaure
Date: Thu, 8 Aug 2019 17:41:38 +0530
Subject: [PATCH 220/484] fix: not able to transfer raw materials for
subcontracted items (#18650)
---
erpnext/buying/doctype/purchase_order/purchase_order.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py
index 8117d9d514..6ed6766288 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.py
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.py
@@ -483,7 +483,7 @@ def make_rm_stock_entry(purchase_order, rm_items):
'from_warehouse': rm_item_data["warehouse"],
'stock_uom': rm_item_data["stock_uom"],
'main_item_code': rm_item_data["item_code"],
- 'allow_alternative_item': item_wh[rm_item_code].get('allow_alternative_item')
+ 'allow_alternative_item': item_wh.get(rm_item_code, {}).get('allow_alternative_item')
}
}
stock_entry.add_to_stock_entry_detail(items_dict)
From bafc89f4399600bea1df4eecd6bc708b7ebf20c2 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Thu, 8 Aug 2019 17:43:23 +0530
Subject: [PATCH 221/484] refactor: convert raw sql to orm
---
.../leave_allocation/leave_allocation.py | 2 +-
.../leave_allocation/test_leave_allocation.py | 2 +-
.../leave_application/leave_application.js | 2 +-
.../test_leave_application.py | 6 +--
.../leave_ledger_entry/leave_ledger_entry.py | 2 +-
.../hr/doctype/leave_period/leave_period.py | 2 +-
erpnext/hr/doctype/leave_type/leave_type.json | 6 +--
.../hr/doctype/leave_type/test_leave_type.py | 2 +-
.../v12_0/generate_leave_ledger_entries.py | 49 +++++--------------
9 files changed, 23 insertions(+), 50 deletions(-)
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.py b/erpnext/hr/doctype/leave_allocation/leave_allocation.py
index 5e81999765..c11c125c6a 100755
--- a/erpnext/hr/doctype/leave_allocation/leave_allocation.py
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.py
@@ -126,7 +126,7 @@ class LeaveAllocation(Document):
def create_leave_ledger_entry(self, submit=True):
if self.unused_leaves:
- expiry_days = frappe.db.get_value("Leave Type", self.leave_type, "expire_carried_forward_leaves")
+ expiry_days = frappe.db.get_value("Leave Type", self.leave_type, "expire_carry_forwarded_leaves_after_days")
args = dict(
leaves=self.unused_leaves,
from_date=self.from_date,
diff --git a/erpnext/hr/doctype/leave_allocation/test_leave_allocation.py b/erpnext/hr/doctype/leave_allocation/test_leave_allocation.py
index 8f876ae7ce..bdba8c9f8f 100644
--- a/erpnext/hr/doctype/leave_allocation/test_leave_allocation.py
+++ b/erpnext/hr/doctype/leave_allocation/test_leave_allocation.py
@@ -97,7 +97,7 @@ class TestLeaveAllocation(unittest.TestCase):
leave_type = create_leave_type(
leave_type_name="_Test_CF_leave_expiry",
is_carry_forward=1,
- expire_carried_forward_leaves=90)
+ expire_carry_forwarded_leaves_after_days=90)
leave_type.submit()
# initial leave allocation
diff --git a/erpnext/hr/doctype/leave_application/leave_application.js b/erpnext/hr/doctype/leave_application/leave_application.js
index a755b57608..174641048b 100755
--- a/erpnext/hr/doctype/leave_application/leave_application.js
+++ b/erpnext/hr/doctype/leave_application/leave_application.js
@@ -49,7 +49,7 @@ frappe.ui.form.on("Leave Application", {
async: false,
args: {
employee: frm.doc.employee,
- date: frm.doc.from_date? frm.doc.from_date:frm.doc.posting_date
+ date: frm.doc.from_date || frm.doc.posting_date
},
callback: function(r) {
if (!r.exc && r.message['leave_allocation']) {
diff --git a/erpnext/hr/doctype/leave_application/test_leave_application.py b/erpnext/hr/doctype/leave_application/test_leave_application.py
index 0f7bf86b22..ad141a5748 100644
--- a/erpnext/hr/doctype/leave_application/test_leave_application.py
+++ b/erpnext/hr/doctype/leave_application/test_leave_application.py
@@ -415,7 +415,7 @@ class TestLeaveApplication(unittest.TestCase):
leave_type = create_leave_type(
leave_type_name="_Test_CF_leave_expiry",
is_carry_forward=1,
- expire_carried_forward_leaves=90)
+ expire_carry_forwarded_leaves_after_days=90)
leave_type.submit()
create_carry_forwarded_allocation(employee, leave_type)
@@ -516,7 +516,7 @@ class TestLeaveApplication(unittest.TestCase):
leave_type = create_leave_type(
leave_type_name="_Test_CF_leave_expiry",
is_carry_forward=1,
- expire_carried_forward_leaves=90)
+ expire_carry_forwarded_leaves_after_days=90)
leave_type.submit()
create_carry_forwarded_allocation(employee, leave_type)
@@ -548,7 +548,7 @@ class TestLeaveApplication(unittest.TestCase):
leave_type = create_leave_type(
leave_type_name="_Test_CF_leave_expiry",
is_carry_forward=1,
- expire_carried_forward_leaves=90)
+ expire_carry_forwarded_leaves_after_days=90)
leave_type.submit()
create_carry_forwarded_allocation(employee, leave_type)
diff --git a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
index 33e4ea0909..c82114e6d5 100644
--- a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
+++ b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
@@ -92,7 +92,7 @@ def process_expired_allocation():
# fetch leave type records that has carry forwarded leaves expiry
leave_type_records = frappe.db.get_values("Leave Type", filters={
- 'expire_carried_forward_leaves': (">", 0)
+ 'expire_carry_forwarded_leaves_after_days': (">", 0)
}, fieldname=['name'])
if leave_type_records:
diff --git a/erpnext/hr/doctype/leave_period/leave_period.py b/erpnext/hr/doctype/leave_period/leave_period.py
index a7de7185c9..a8566c4ffb 100644
--- a/erpnext/hr/doctype/leave_period/leave_period.py
+++ b/erpnext/hr/doctype/leave_period/leave_period.py
@@ -95,7 +95,7 @@ def get_existing_allocations(employees, leave_period):
def get_leave_type_details():
leave_type_details = frappe._dict()
leave_types = frappe.get_all("Leave Type",
- fields=["name", "is_lwp", "is_earned_leave", "is_compensatory", "is_carry_forward", "expire_carried_forward_leaves"])
+ fields=["name", "is_lwp", "is_earned_leave", "is_compensatory", "is_carry_forward", "expire_carry_forwarded_leaves_after_days"])
for d in leave_types:
leave_type_details.setdefault(d.name, d)
return leave_type_details
diff --git a/erpnext/hr/doctype/leave_type/leave_type.json b/erpnext/hr/doctype/leave_type/leave_type.json
index 7a279063ce..36d5f8b3d1 100644
--- a/erpnext/hr/doctype/leave_type/leave_type.json
+++ b/erpnext/hr/doctype/leave_type/leave_type.json
@@ -421,7 +421,7 @@
"depends_on": "",
"description": "Calculated in days",
"fetch_if_empty": 0,
- "fieldname": "expire_carried_forward_leaves",
+ "fieldname": "expire_carry_forwarded_leaves_after_days",
"fieldtype": "Int",
"hidden": 0,
"ignore_user_permissions": 0,
@@ -430,7 +430,7 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
- "label": "Expire Carried Forward Leaves",
+ "label": "Expire Carry Forwarded Leaves After Days",
"length": 0,
"no_copy": 0,
"permlevel": 0,
@@ -728,7 +728,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2019-07-22 15:38:39.334283",
+ "modified": "2019-08-01 15:38:39.334283",
"modified_by": "Administrator",
"module": "HR",
"name": "Leave Type",
diff --git a/erpnext/hr/doctype/leave_type/test_leave_type.py b/erpnext/hr/doctype/leave_type/test_leave_type.py
index d9852be6c9..0c4f435860 100644
--- a/erpnext/hr/doctype/leave_type/test_leave_type.py
+++ b/erpnext/hr/doctype/leave_type/test_leave_type.py
@@ -19,7 +19,7 @@ def create_leave_type(**args):
"is_earned_leave": args.is_earned_leave or 0,
"is_lwp": args.is_lwp or 0,
"is_carry_forward": args.is_carry_forward or 0,
- "expire_carried_forward_leaves": args.expire_carried_forward_leaves or 0,
+ "expire_carry_forwarded_leaves_after_days": args.expire_carry_forwarded_leaves_after_days or 0,
"encashment_threshold_days": args.encashment_threshold_days or 5,
"earning_component": "Leave Encashment"
})
diff --git a/erpnext/patches/v12_0/generate_leave_ledger_entries.py b/erpnext/patches/v12_0/generate_leave_ledger_entries.py
index c1e1b4f3b2..38f6883b9a 100644
--- a/erpnext/patches/v12_0/generate_leave_ledger_entries.py
+++ b/erpnext/patches/v12_0/generate_leave_ledger_entries.py
@@ -69,45 +69,18 @@ def generate_expiry_allocation_ledger_entries():
expire_allocation(allocation_obj)
def get_allocation_records():
- return frappe.db.sql("""
- SELECT
- name,
- employee,
- leave_type,
- new_leaves_allocated,
- unused_leaves,
- from_date,
- to_date,
- carry_forward
- FROM `tabLeave Allocation`
- WHERE
- docstatus=1
- ORDER BY to_date ASC
- """, as_dict=1)
+ return frappe.get_all("Leave Allocation", filters={
+ "docstatus": 1
+ }, fields=['name', 'employee', 'leave_type', 'new_leaves_allocated',
+ 'unused_leaves', 'from_date', 'to_date', 'carry_forward'
+ ], order_by='to_date ASC')
def get_leaves_application_records():
- return frappe.db.sql("""
- SELECT
- name,
- employee,
- leave_type,
- total_leave_days,
- from_date,
- to_date
- FROM `tabLeave Application`
- WHERE
- docstatus=1
- """, as_dict=1)
+ return frappe.get_all("Leave Application", filters={
+ "docstatus": 1
+ }, fields=['name', 'employee', 'leave_type', 'total_leave_days', 'from_date', 'to_date'])
def get_leave_encashment_records():
- return frappe.db.sql("""
- SELECT
- name,
- employee,
- leave_type,
- encashable_days,
- encashment_date
- FROM `tabLeave Encashment`
- WHERE
- docstatus=1
- """, as_dict=1)
\ No newline at end of file
+ return frappe.get_all("Leave Encashment", filters={
+ "docstatus": 1
+ }, fields=['name', 'employee', 'leave_type', 'encashable_days', 'encashment_date'])
From cfd19afabf7e9ddc7253d72567b4486fc107fab3 Mon Sep 17 00:00:00 2001
From: Faris Ansari
Date: Thu, 8 Aug 2019 17:45:44 +0530
Subject: [PATCH 222/484] fix: Set Maintenance Status fields as Read Only
(#18633)
Maintenance Status is set based on warranty_expiry_date and
amc_expiry_date. Even if they are editable they are set programmatically
server side. Better to make them as read only.
---
.../stock/doctype/serial_no/serial_no.json | 1408 ++---------------
1 file changed, 94 insertions(+), 1314 deletions(-)
diff --git a/erpnext/stock/doctype/serial_no/serial_no.json b/erpnext/stock/doctype/serial_no/serial_no.json
index 8c3dafe8ba..712aadc525 100644
--- a/erpnext/stock/doctype/serial_no/serial_no.json
+++ b/erpnext/stock/doctype/serial_no/serial_no.json
@@ -1,1691 +1,471 @@
{
- "allow_copy": 0,
- "allow_events_in_timeline": 0,
- "allow_guest_to_view": 0,
"allow_import": 1,
"allow_rename": 1,
"autoname": "field:serial_no",
- "beta": 0,
"creation": "2013-05-16 10:59:15",
- "custom": 0,
"description": "Distinct unit of an Item",
- "docstatus": 0,
"doctype": "DocType",
"document_type": "Setup",
- "editable_grid": 0,
+ "field_order": [
+ "details",
+ "column_break0",
+ "serial_no",
+ "item_code",
+ "warehouse",
+ "batch_no",
+ "column_break1",
+ "item_name",
+ "description",
+ "item_group",
+ "brand",
+ "sales_order",
+ "purchase_details",
+ "column_break2",
+ "purchase_document_type",
+ "purchase_document_no",
+ "purchase_date",
+ "purchase_time",
+ "purchase_rate",
+ "column_break3",
+ "supplier",
+ "supplier_name",
+ "asset_details",
+ "asset",
+ "asset_status",
+ "column_break_24",
+ "location",
+ "employee",
+ "delivery_details",
+ "delivery_document_type",
+ "delivery_document_no",
+ "delivery_date",
+ "delivery_time",
+ "is_cancelled",
+ "column_break5",
+ "customer",
+ "customer_name",
+ "invoice_details",
+ "sales_invoice",
+ "warranty_amc_details",
+ "column_break6",
+ "warranty_expiry_date",
+ "amc_expiry_date",
+ "column_break7",
+ "maintenance_status",
+ "warranty_period",
+ "more_info",
+ "serial_no_details",
+ "company"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "details",
"fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "",
- "length": 0,
- "no_copy": 0,
- "oldfieldtype": "Section Break",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
+ "oldfieldtype": "Section Break"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "column_break0",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
+ "fieldtype": "Column Break"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "serial_no",
"fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Serial No",
- "length": 0,
"no_copy": 1,
"oldfieldname": "serial_no",
"oldfieldtype": "Data",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
"reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
"unique": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "item_code",
"fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 1,
"label": "Item Code",
- "length": 0,
- "no_copy": 0,
"oldfieldname": "item_code",
"oldfieldtype": "Link",
"options": "Item",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "reqd": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"description": "Warehouse can only be changed via Stock Entry / Delivery Note / Purchase Receipt",
"fieldname": "warehouse",
"fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 1,
"label": "Warehouse",
- "length": 0,
"no_copy": 1,
"oldfieldname": "warehouse",
"oldfieldtype": "Link",
"options": "Warehouse",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
"read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 1,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "search_index": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "batch_no",
"fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 1,
"label": "Batch No",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "read_only": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "column_break1",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
+ "fieldtype": "Column Break"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "item_name",
"fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Item Name",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "read_only": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "description",
"fieldtype": "Text",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Description",
- "length": 0,
- "no_copy": 0,
"oldfieldname": "description",
"oldfieldtype": "Text",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
"read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
"width": "300px"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "",
"fieldname": "item_group",
"fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Item Group",
- "length": 0,
- "no_copy": 0,
"oldfieldname": "item_group",
"oldfieldtype": "Link",
"options": "Item Group",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "read_only": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "brand",
"fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Brand",
- "length": 0,
- "no_copy": 0,
"oldfieldname": "brand",
"oldfieldtype": "Link",
"options": "Brand",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "read_only": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "sales_order",
"fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Sales Order",
- "length": 0,
- "no_copy": 0,
- "options": "Sales Order",
- "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,
- "translatable": 0,
- "unique": 0
+ "options": "Sales Order"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "purchase_details",
"fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Purchase / Manufacture Details",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
+ "label": "Purchase / Manufacture Details"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "column_break2",
"fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0,
"width": "50%"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "purchase_document_type",
"fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Creation Document Type",
- "length": 0,
"no_copy": 1,
"options": "DocType",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "read_only": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "purchase_document_no",
"fieldtype": "Dynamic Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Creation Document No",
- "length": 0,
"no_copy": 1,
"options": "purchase_document_type",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "read_only": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "purchase_date",
"fieldtype": "Date",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Creation Date",
- "length": 0,
"no_copy": 1,
"oldfieldname": "purchase_date",
"oldfieldtype": "Date",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "read_only": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "purchase_time",
"fieldtype": "Time",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Creation Time",
- "length": 0,
"no_copy": 1,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "read_only": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "purchase_rate",
"fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Incoming Rate",
- "length": 0,
"no_copy": 1,
"oldfieldname": "purchase_rate",
"oldfieldtype": "Currency",
"options": "Company:company:default_currency",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "read_only": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "column_break3",
"fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0,
"width": "50%"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "supplier",
"fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Supplier",
- "length": 0,
"no_copy": 1,
- "options": "Supplier",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
+ "options": "Supplier"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
"bold": 1,
- "collapsible": 0,
- "columns": 0,
"fieldname": "supplier_name",
"fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Supplier Name",
- "length": 0,
"no_copy": 1,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "read_only": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "asset_details",
"fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Asset Details",
- "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,
- "translatable": 0,
- "unique": 0
+ "label": "Asset Details"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "asset",
"fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Asset",
- "length": 0,
"no_copy": 1,
"options": "Asset",
- "permlevel": 0,
- "precision": "",
"print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "read_only": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"depends_on": "asset",
"fieldname": "asset_status",
"fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Asset Status",
- "length": 0,
- "no_copy": 0,
"options": "\nIssue\nReceipt\nTransfer",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "read_only": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "column_break_24",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 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,
- "translatable": 0,
- "unique": 0
+ "fieldtype": "Column Break"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "location",
"fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Location",
- "length": 0,
- "no_copy": 0,
"options": "Location",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "read_only": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "employee",
"fieldtype": "Link",
- "hidden": 0,
"ignore_user_permissions": 1,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Employee",
- "length": 0,
- "no_copy": 0,
"options": "Employee",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "read_only": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "delivery_details",
"fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Delivery Details",
- "length": 0,
- "no_copy": 0,
- "oldfieldtype": "Column Break",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
+ "oldfieldtype": "Column Break"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "delivery_document_type",
"fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Delivery Document Type",
- "length": 0,
"no_copy": 1,
"options": "DocType",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "read_only": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "delivery_document_no",
"fieldtype": "Dynamic Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Delivery Document No",
- "length": 0,
"no_copy": 1,
"options": "delivery_document_type",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "read_only": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "delivery_date",
"fieldtype": "Date",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Delivery Date",
- "length": 0,
"no_copy": 1,
"oldfieldname": "delivery_date",
"oldfieldtype": "Date",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "read_only": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "delivery_time",
"fieldtype": "Time",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Delivery Time",
- "length": 0,
"no_copy": 1,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "read_only": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "is_cancelled",
"fieldtype": "Select",
"hidden": 1,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Is Cancelled",
- "length": 0,
- "no_copy": 0,
"oldfieldname": "is_cancelled",
"oldfieldtype": "Select",
"options": "\nYes\nNo",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 1,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "report_hide": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "column_break5",
"fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0,
"width": "50%"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "customer",
"fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Customer",
- "length": 0,
"no_copy": 1,
"oldfieldname": "customer",
"oldfieldtype": "Link",
"options": "Customer",
- "permlevel": 0,
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
+ "print_hide": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
"bold": 1,
- "collapsible": 0,
- "columns": 0,
"fieldname": "customer_name",
"fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Customer Name",
- "length": 0,
"no_copy": 1,
"oldfieldname": "customer_name",
"oldfieldtype": "Data",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "read_only": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "invoice_details",
"fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Invoice Details",
- "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,
- "translatable": 0,
- "unique": 0
+ "label": "Invoice Details"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "sales_invoice",
"fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Sales Invoice",
- "length": 0,
- "no_copy": 0,
"options": "Sales Invoice",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "read_only": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "warranty_amc_details",
"fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Warranty / AMC Details",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
+ "label": "Warranty / AMC Details"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "column_break6",
"fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0,
"width": "50%"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "maintenance_status",
"fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Maintenance Status",
- "length": 0,
- "no_copy": 0,
"oldfieldname": "maintenance_status",
"oldfieldtype": "Select",
"options": "\nUnder Warranty\nOut of Warranty\nUnder AMC\nOut of AMC",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
+ "read_only": 1,
"search_index": 1,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
"width": "150px"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "warranty_period",
"fieldtype": "Int",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Warranty Period (Days)",
- "length": 0,
- "no_copy": 0,
"oldfieldname": "warranty_period",
"oldfieldtype": "Int",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0,
+ "read_only": 1,
"width": "150px"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "column_break7",
"fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0,
"width": "50%"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "warranty_expiry_date",
"fieldtype": "Date",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Warranty Expiry Date",
- "length": 0,
- "no_copy": 0,
"oldfieldname": "warranty_expiry_date",
"oldfieldtype": "Date",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0,
"width": "150px"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "amc_expiry_date",
"fieldtype": "Date",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "AMC Expiry Date",
- "length": 0,
- "no_copy": 0,
"oldfieldname": "amc_expiry_date",
"oldfieldtype": "Date",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0,
"width": "150px"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "more_info",
"fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "More Information",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
+ "label": "More Information"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "serial_no_details",
"fieldtype": "Text Editor",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Serial No Details",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
+ "label": "Serial No Details"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "company",
"fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Company",
- "length": 0,
- "no_copy": 0,
"options": "Company",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 1,
- "report_hide": 0,
"reqd": 1,
- "search_index": 1,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "search_index": 1
}
],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
"icon": "fa fa-barcode",
"idx": 1,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2018-10-19 12:38:34.448513",
+ "modified": "2019-08-07 17:28:32.243280",
"modified_by": "Administrator",
"module": "Stock",
"name": "Serial No",
"owner": "Administrator",
"permissions": [
{
- "amend": 0,
- "cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Item Manager",
- "set_user_permissions": 0,
"share": 1,
- "submit": 0,
"write": 1
},
{
- "amend": 0,
- "cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
- "if_owner": 0,
"import": 1,
- "permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Stock Manager",
"set_user_permissions": 1,
- "share": 0,
- "submit": 0,
"write": 1
},
{
- "amend": 0,
- "cancel": 0,
- "create": 0,
- "delete": 0,
"email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
- "role": "Stock User",
- "set_user_permissions": 0,
- "share": 0,
- "submit": 0,
- "write": 0
+ "role": "Stock User"
}
],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
"search_fields": "item_code",
"show_name_in_global_search": 1,
"sort_field": "modified",
"sort_order": "DESC",
- "track_changes": 1,
- "track_seen": 0,
- "track_views": 0
+ "track_changes": 1
}
\ No newline at end of file
From 10e8073204ec2f4b2be32dcc89ef6000152af8cc Mon Sep 17 00:00:00 2001
From: Rohit Waghchaure
Date: Thu, 8 Aug 2019 18:19:24 +0530
Subject: [PATCH 223/484] fix: allow to subcotract service raw materials
---
erpnext/controllers/buying_controller.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py
index 0b4d38ce5c..5c51a2c7bd 100644
--- a/erpnext/controllers/buying_controller.py
+++ b/erpnext/controllers/buying_controller.py
@@ -725,7 +725,7 @@ def get_items_from_bom(item_code, bom, exploded_item=1):
where
t2.parent = t1.name and t1.item = %s
and t1.docstatus = 1 and t1.is_active = 1 and t1.name = %s
- and t2.item_code = t3.name and t3.is_stock_item = 1""".format(doctype),
+ and t2.item_code = t3.name""".format(doctype),
(item_code, bom), as_dict=1)
if not bom_items:
From 3662ed50d2eb624b62c4b27d00e53b9689560223 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Thu, 8 Aug 2019 19:47:17 +0530
Subject: [PATCH 224/484] fix: multiple changes
---
erpnext/hr/doctype/leave_type/leave_type.json | 4 ++--
erpnext/hr/doctype/leave_type/leave_type.py | 2 +-
.../employee_leave_balance.py | 2 +-
erpnext/hr/utils.py | 15 +++++++++------
erpnext/patches.txt | 1 -
5 files changed, 13 insertions(+), 11 deletions(-)
diff --git a/erpnext/hr/doctype/leave_type/leave_type.json b/erpnext/hr/doctype/leave_type/leave_type.json
index 36d5f8b3d1..2f15e3b3c1 100644
--- a/erpnext/hr/doctype/leave_type/leave_type.json
+++ b/erpnext/hr/doctype/leave_type/leave_type.json
@@ -430,7 +430,7 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
- "label": "Expire Carry Forwarded Leaves After Days",
+ "label": "Expire Carry Forwarded Leaves (Days)",
"length": 0,
"no_copy": 0,
"permlevel": 0,
@@ -728,7 +728,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2019-08-01 15:38:39.334283",
+ "modified": "2019-08-02 15:38:39.334283",
"modified_by": "Administrator",
"module": "HR",
"name": "Leave Type",
diff --git a/erpnext/hr/doctype/leave_type/leave_type.py b/erpnext/hr/doctype/leave_type/leave_type.py
index 75336e0c7e..3a19fa98e6 100644
--- a/erpnext/hr/doctype/leave_type/leave_type.py
+++ b/erpnext/hr/doctype/leave_type/leave_type.py
@@ -14,4 +14,4 @@ class LeaveType(Document):
if self.is_lwp:
leave_allocation = frappe.db.sql_list("""select name from `tabLeave Allocation` where leave_type=%s""", (self.name))
if leave_allocation:
- frappe.throw(_("""Leave application is linked with leave allocations {0}. Leave application cannot be set as leave without pay""").format(", ".join(leave_allocation))) #nosec
\ No newline at end of file
+ frappe.throw(_('Leave application is linked with leave allocations {0}. Leave application cannot be set as leave without pay').format(", ".join(leave_allocation))) #nosec
\ No newline at end of file
diff --git a/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py b/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py
index b99708a91f..66e3614982 100644
--- a/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py
+++ b/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py
@@ -66,7 +66,7 @@ def get_data(filters, leave_types):
filters.from_date, filters.to_date) * -1
# opening balance
- opening = get_leave_balance_on(employee.name, leave_type, filters.from_date)
+ opening = get_total_allocated_leaves(employee.name, leave_type, filters.from_date, filters.to_date)
# closing balance
closing = flt(opening) - flt(leaves_taken)
diff --git a/erpnext/hr/utils.py b/erpnext/hr/utils.py
index 4fe9f6b285..3accbbb156 100644
--- a/erpnext/hr/utils.py
+++ b/erpnext/hr/utils.py
@@ -266,8 +266,10 @@ def get_leave_period(from_date, to_date, company):
def generate_leave_encashment():
''' Generates a draft leave encashment on allocation expiry '''
from erpnext.hr.doctype.leave_encashment.leave_encashment import create_leave_encashment
+
if frappe.db.get_single_value('HR Settings', 'auto_leave_encashment'):
- leave_type = frappe.db.sql_list("SELECT name FROM `tabLeave Type` WHERE `allow_encashment`=1")
+ leave_type = frappe.get_all('Leave Type', filters={'allow_encashment': 1}, fields=['name'])
+ leave_type=[l['name'] for l in leave_type]
leave_allocation = frappe.get_all("Leave Allocation", filters={
'to_date': add_days(today(), -1),
@@ -285,9 +287,8 @@ def allocate_earned_leaves():
divide_by_frequency = {"Yearly": 1, "Half-Yearly": 6, "Quarterly": 4, "Monthly": 12}
for e_leave_type in e_leave_types:
- leave_allocations = frappe.db.sql("""select name, employee, from_date, to_date from `tabLeave Allocation` where '{0}'
- between from_date and to_date and docstatus=1 and leave_type='{1}'"""
- .format(today, e_leave_type.name), as_dict=1)
+ leave_allocations = frappe.db.sql("""select name, employee, from_date, to_date from `tabLeave Allocation` where %s
+ between from_date and to_date and docstatus=1 and leave_type=%s""", (today, e_leave_type.name), as_dict=1)
for allocation in leave_allocations:
leave_policy = get_employee_leave_policy(allocation.employee)
if not leave_policy:
@@ -295,8 +296,10 @@ def allocate_earned_leaves():
if not e_leave_type.earned_leave_frequency == "Monthly":
if not check_frequency_hit(allocation.from_date, today, e_leave_type.earned_leave_frequency):
continue
- annual_allocation = frappe.db.sql("""select annual_allocation from `tabLeave Policy Detail`
- where parent=%s and leave_type=%s""", (leave_policy.name, e_leave_type.name))
+ annual_allocation = frappe.get_all("Leave Policy Detail", filters={
+ 'parent': leave_policy.name,
+ 'leave_type': e_leave_type.name
+ }, fields=['annual_allocation'])
if annual_allocation and annual_allocation[0]:
earned_leaves = flt(annual_allocation[0][0]) / divide_by_frequency[e_leave_type.earned_leave_frequency]
if e_leave_type.rounding == "0.5":
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index ce2a5192d9..9b8c2f0a6b 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -603,7 +603,6 @@ erpnext.patches.v11_1.set_salary_details_submittable
erpnext.patches.v11_1.rename_depends_on_lwp
execute:frappe.delete_doc("Report", "Inactive Items")
erpnext.patches.v11_1.delete_scheduling_tool
-execute:frappe.delete_doc_if_exists("Page", "support-analytics")
erpnext.patches.v12_0.rename_tolerance_fields
erpnext.patches.v12_0.make_custom_fields_for_bank_remittance #14-06-2019
execute:frappe.delete_doc_if_exists("Page", "support-analytics")
From 224c2ddaf4b9a9ff4406e1d4d8764a5c09bf08a0 Mon Sep 17 00:00:00 2001
From: Himanshu Warekar
Date: Thu, 8 Aug 2019 23:34:34 +0530
Subject: [PATCH 225/484] feat: render multiple addresses
---
erpnext/public/js/templates/contact_list.html | 33 ++++++++++++-------
1 file changed, 22 insertions(+), 11 deletions(-)
diff --git a/erpnext/public/js/templates/contact_list.html b/erpnext/public/js/templates/contact_list.html
index 893b4e0ec2..c4bc04ff38 100644
--- a/erpnext/public/js/templates/contact_list.html
+++ b/erpnext/public/js/templates/contact_list.html
@@ -14,19 +14,30 @@
style="margin-top:-3px; margin-right: -5px;">
{%= __("Edit") %}
- {% if (contact_list[i].phone || contact_list[i].mobile_no ||
- contact_list[i].email_id) { %}
+ {% if (contact_list[i].phones || contact_list[i].email_ids) { %}
- {% if(contact_list[i].phone) { %}
- {%= __("Phone") %}: {%= contact_list[i].phone %}
- {% } %}
- {% if(contact_list[i].mobile_no) { %}
- {%= __("Mobile No.") %}: {%= contact_list[i].mobile_no %}
- {% } %}
- {% if(contact_list[i].email_id) { %}
- {%= __("Email Address") %}: {%= contact_list[i].email_id %}
- {% } %}
+ {% if(contact_list[i].phone) { %}
+ {%= __("Phone ") %}: {%= contact_list[i].phone %}
+ {% endif %}
+ {% if(contact_list[i].phones) { %}
+ {% for(var j=0, k=contact_list[i].phones.length; j
+ {% } %}
+ {% endif %}
+
+ {% if(contact_list[i].email_id) { %}
+ {%= __("Email ") %}: {%= contact_list[i].email_id %}
+ {% endif %}
+ {% if(contact_list[i].email_ids) { %}
+ {% for(var j=0, k=contact_list[i].email_ids.length; j
+ {% } %}
+ {% endif %}
+
+ {% endif %}
+ {% if (contact_list[i].address) { %}
+ {%= __("Address ") %}: {%= contact_list[i].address %}
{% endif %}
{% } %}
From f94d1832977516e726a9f71994c5b917ea521308 Mon Sep 17 00:00:00 2001
From: Himanshu Warekar
Date: Thu, 8 Aug 2019 23:50:03 +0530
Subject: [PATCH 226/484] feat: move to newer contacts structure
---
erpnext/crm/doctype/opportunity/test_opportunity.py | 7 ++++---
erpnext/hub_node/legacy.py | 5 +++--
erpnext/selling/doctype/customer/customer.py | 7 ++++---
3 files changed, 11 insertions(+), 8 deletions(-)
diff --git a/erpnext/crm/doctype/opportunity/test_opportunity.py b/erpnext/crm/doctype/opportunity/test_opportunity.py
index 1a9f66ad9a..8927d93027 100644
--- a/erpnext/crm/doctype/opportunity/test_opportunity.py
+++ b/erpnext/crm/doctype/opportunity/test_opportunity.py
@@ -45,15 +45,16 @@ class TestOpportunity(unittest.TestCase):
# create new customer and create new contact against 'new.opportunity@example.com'
customer = make_customer(opp_doc.party_name).insert(ignore_permissions=True)
- frappe.get_doc({
+ d = frappe.get_doc({
"doctype": "Contact",
- "email_id": new_lead_email_id,
"first_name": "_Test Opportunity Customer",
"links": [{
"link_doctype": "Customer",
"link_name": customer.name
}]
- }).insert(ignore_permissions=True)
+ })
+ d.add_email(new_lead_email_id)
+ d.insert(ignore_permissions=True)
opp_doc = frappe.get_doc(args).insert(ignore_permissions=True)
self.assertTrue(opp_doc.party_name)
diff --git a/erpnext/hub_node/legacy.py b/erpnext/hub_node/legacy.py
index 95ada76a6a..85eb1b2bb0 100644
--- a/erpnext/hub_node/legacy.py
+++ b/erpnext/hub_node/legacy.py
@@ -68,12 +68,13 @@ def make_contact(supplier):
contact = frappe.get_doc({
'doctype': 'Contact',
'first_name': supplier.supplier_name,
- 'email_id': supplier.supplier_email,
'is_primary_contact': 1,
'links': [
{'link_doctype': 'Supplier', 'link_name': supplier.supplier_name}
]
- }).insert()
+ })
+ contact.add_email(supplier.supplier_email)
+ contact.insert()
else:
contact = frappe.get_doc('Contact', contact_name)
diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py
index c946c47c59..d0b4ba0e65 100644
--- a/erpnext/selling/doctype/customer/customer.py
+++ b/erpnext/selling/doctype/customer/customer.py
@@ -337,14 +337,15 @@ def make_contact(args, is_primary_contact=1):
contact = frappe.get_doc({
'doctype': 'Contact',
'first_name': args.get('name'),
- 'mobile_no': args.get('mobile_no'),
- 'email_id': args.get('email_id'),
'is_primary_contact': is_primary_contact,
'links': [{
'link_doctype': args.get('doctype'),
'link_name': args.get('name')
}]
- }).insert()
+ })
+ contact.add_email(args.get('email_id'))
+ contact.add_phone(args.get('mobile_no'))
+ contact.insert()
return contact
From 86f3310ac1492fbd6aba27666dae852f28dc9dba Mon Sep 17 00:00:00 2001
From: Himanshu Warekar
Date: Fri, 9 Aug 2019 11:05:04 +0530
Subject: [PATCH 227/484] fix: iterate over valid variable
---
erpnext/public/js/templates/contact_list.html | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/erpnext/public/js/templates/contact_list.html b/erpnext/public/js/templates/contact_list.html
index c4bc04ff38..a90580f652 100644
--- a/erpnext/public/js/templates/contact_list.html
+++ b/erpnext/public/js/templates/contact_list.html
@@ -19,9 +19,9 @@
{% if(contact_list[i].phone) { %}
{%= __("Phone ") %}: {%= contact_list[i].phone %}
{% endif %}
- {% if(contact_list[i].phones) { %}
- {% for(var j=0, k=contact_list[i].phones.length; j
+ {% if(contact_list[i].phone_nos) { %}
+ {% for(var j=0, k=contact_list[i].phone_nos.length; j
{% } %}
{% endif %}
From 261d132f3a90ffc0b3391d4baf7f2bc1e50a9c77 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Fri, 9 Aug 2019 13:18:52 +0530
Subject: [PATCH 228/484] fix: calculate earned leaves based on annual
allocation
---
erpnext/hr/utils.py | 8 ++++----
erpnext/patches/v12_0/generate_leave_ledger_entries.py | 2 +-
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/erpnext/hr/utils.py b/erpnext/hr/utils.py
index 3accbbb156..7ef61e920c 100644
--- a/erpnext/hr/utils.py
+++ b/erpnext/hr/utils.py
@@ -296,12 +296,12 @@ def allocate_earned_leaves():
if not e_leave_type.earned_leave_frequency == "Monthly":
if not check_frequency_hit(allocation.from_date, today, e_leave_type.earned_leave_frequency):
continue
- annual_allocation = frappe.get_all("Leave Policy Detail", filters={
+ annual_allocation = frappe.db.get_value("Leave Policy Detail", filters={
'parent': leave_policy.name,
'leave_type': e_leave_type.name
- }, fields=['annual_allocation'])
- if annual_allocation and annual_allocation[0]:
- earned_leaves = flt(annual_allocation[0][0]) / divide_by_frequency[e_leave_type.earned_leave_frequency]
+ }, fieldname=['annual_allocation'])
+ if annual_allocation:
+ earned_leaves = flt(annual_allocation) / divide_by_frequency[e_leave_type.earned_leave_frequency]
if e_leave_type.rounding == "0.5":
earned_leaves = round(earned_leaves * 2) / 2
else:
diff --git a/erpnext/patches/v12_0/generate_leave_ledger_entries.py b/erpnext/patches/v12_0/generate_leave_ledger_entries.py
index 38f6883b9a..44b59bf09b 100644
--- a/erpnext/patches/v12_0/generate_leave_ledger_entries.py
+++ b/erpnext/patches/v12_0/generate_leave_ledger_entries.py
@@ -83,4 +83,4 @@ def get_leaves_application_records():
def get_leave_encashment_records():
return frappe.get_all("Leave Encashment", filters={
"docstatus": 1
- }, fields=['name', 'employee', 'leave_type', 'encashable_days', 'encashment_date'])
+ }, fields=['name', 'employee', 'leave_type', 'encashable_days', 'encashment_date'])
\ No newline at end of file
From 24c3b4e00ffab02eb47d7a22f4fda3da91bd94ff Mon Sep 17 00:00:00 2001
From: Anurag Mishra
Date: Fri, 9 Aug 2019 13:27:59 +0530
Subject: [PATCH 229/484] fix: get item from product bundle
---
erpnext/public/js/controllers/buying.js | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/erpnext/public/js/controllers/buying.js b/erpnext/public/js/controllers/buying.js
index acc09ed213..118aee9a8c 100644
--- a/erpnext/public/js/controllers/buying.js
+++ b/erpnext/public/js/controllers/buying.js
@@ -452,7 +452,8 @@ erpnext.buying.get_items_from_product_bundle = function(frm) {
company: frm.doc.company,
is_subcontracted: frm.doc.is_subcontracted,
transaction_date: frm.doc.transaction_date || frm.doc.posting_date,
- ignore_pricing_rule: frm.doc.ignore_pricing_rule
+ ignore_pricing_rule: frm.doc.ignore_pricing_rule,
+ doctype: frm.doc.doctype
}
},
freeze: true,
From 9839a9afb0f4c38e1a008b263e0d8212de6b6fab Mon Sep 17 00:00:00 2001
From: marination
Date: Fri, 9 Aug 2019 15:54:18 +0530
Subject: [PATCH 230/484] fix: Fixed error message in Payment Entry for
outstanding invoices not found via filters
---
erpnext/accounts/doctype/payment_entry/payment_entry.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py
index da6b167880..401d1806f2 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.py
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py
@@ -624,7 +624,7 @@ def get_outstanding_reference_documents(args):
data = negative_outstanding_invoices + outstanding_invoices + orders_to_be_billed
if not data:
- frappe.msgprint(_("No outstanding invoices found for the {0} {1} .")
+ frappe.msgprint(_("No outstanding invoices found for the {0} {1} which qualify the filters you have specified")
.format(args.get("party_type").lower(), args.get("party")))
return data
From 12fbecf48bc781df144d5e1311f613578131565b Mon Sep 17 00:00:00 2001
From: Himanshu Warekar
Date: Fri, 9 Aug 2019 17:50:03 +0530
Subject: [PATCH 231/484] fix: use primary label instead of bold letters
---
erpnext/public/js/templates/contact_list.html | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/erpnext/public/js/templates/contact_list.html b/erpnext/public/js/templates/contact_list.html
index a90580f652..0a339aa539 100644
--- a/erpnext/public/js/templates/contact_list.html
+++ b/erpnext/public/js/templates/contact_list.html
@@ -17,7 +17,7 @@
{% if (contact_list[i].phones || contact_list[i].email_ids) { %}
{% if(contact_list[i].phone) { %}
- {%= __("Phone ") %}: {%= contact_list[i].phone %}
+ {%= __("Phone ") %}: {%= contact_list[i].phone %} ({%= __("Primary") %})
{% endif %}
{% if(contact_list[i].phone_nos) { %}
{% for(var j=0, k=contact_list[i].phone_nos.length; j
{% if(contact_list[i].email_id) { %}
- {%= __("Email ") %}: {%= contact_list[i].email_id %}
+ {%= __("Email ") %}: {%= contact_list[i].email_id %} ({%= __("Primary") %})
{% endif %}
{% if(contact_list[i].email_ids) { %}
{% for(var j=0, k=contact_list[i].email_ids.length; j
Date: Sun, 11 Aug 2019 10:58:16 +0530
Subject: [PATCH 232/484] fix: GSTR 3B report fixes
---
.../doctype/gstr_3b_report/gstr_3b_report.js | 8 +-
.../gstr_3b_report/gstr_3b_report.json | 304 ++++--------------
.../doctype/gstr_3b_report/gstr_3b_report.py | 48 +--
3 files changed, 90 insertions(+), 270 deletions(-)
diff --git a/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.js b/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.js
index 0d6cef0792..a1cea8f609 100644
--- a/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.js
+++ b/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.js
@@ -2,7 +2,7 @@
// For license information, please see license.txt
frappe.ui.form.on('GSTR 3B Report', {
- refresh : function(frm){
+ refresh : function(frm) {
if(!frm.is_new()) {
frm.set_intro(__("Please save the report again to rebuild or update"));
frm.add_custom_button(__('Download JSON'), function() {
@@ -39,9 +39,13 @@ frappe.ui.form.on('GSTR 3B Report', {
});
});
}
+
+ let current_year = new Date().getFullYear();
+ let options = [current_year, current_year-1, current_year-2];
+ frm.set_df_property('year', 'options', options);
},
- setup: function(frm){
+ setup: function(frm) {
frm.set_query('company_address', function(doc) {
if(!doc.company) {
frappe.throw(__('Please set Company'));
diff --git a/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.json b/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.json
index 7b0462fd4b..548d40b974 100644
--- a/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.json
+++ b/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.json
@@ -1,259 +1,73 @@
{
- "allow_copy": 0,
- "allow_events_in_timeline": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "autoname": "format:GSTR3B-{month}-{year}-{company_address}",
- "beta": 0,
- "creation": "2019-02-04 11:35:55.964639",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "",
- "editable_grid": 1,
- "engine": "InnoDB",
+ "autoname": "format:GSTR3B-{month}-{year}-{company_address}",
+ "creation": "2019-02-04 11:35:55.964639",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "company",
+ "company_address",
+ "year",
+ "month",
+ "json_output",
+ "missing_field_invoices"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "company",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Company",
- "length": 0,
- "no_copy": 0,
- "options": "Company",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "label": "Company",
+ "options": "Company"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "company_address",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Company Address",
- "length": 0,
- "no_copy": 0,
- "options": "Address",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "company_address",
+ "fieldtype": "Link",
+ "label": "Company Address",
+ "options": "Address"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "year",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Year",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "year",
+ "fieldtype": "Select",
+ "label": "Year"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "month",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Month",
- "length": 0,
- "no_copy": 0,
- "options": "January\nFebruary\nMarch\nApril\nMay\nJune\nJuly\nAugust\nSeptember\nOctober\nNovember\nDecember",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "month",
+ "fieldtype": "Select",
+ "label": "Month",
+ "options": "January\nFebruary\nMarch\nApril\nMay\nJune\nJuly\nAugust\nSeptember\nOctober\nNovember\nDecember"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "json_output",
- "fieldtype": "Code",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "JSON Output",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "json_output",
+ "fieldtype": "Code",
+ "label": "JSON Output"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "missing_field_invoices",
- "fieldtype": "Small Text",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Invoices with no Place Of Supply",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "fieldname": "missing_field_invoices",
+ "fieldtype": "Small Text",
+ "label": "Invoices with no Place Of Supply",
+ "read_only": 1
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2019-03-04 10:04:44.767655",
- "modified_by": "Administrator",
- "module": "Regional",
- "name": "GSTR 3B Report",
- "name_case": "",
- "owner": "Administrator",
+ ],
+ "modified": "2019-08-10 22:30:26.727038",
+ "modified_by": "Administrator",
+ "module": "Regional",
+ "name": "GSTR 3B Report",
+ "owner": "Administrator",
"permissions": [
{
- "amend": 0,
- "cancel": 0,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "System Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "System Manager",
+ "share": 1,
"write": 1
}
- ],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1,
- "track_seen": 0,
- "track_views": 0
+ ],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
}
\ No newline at end of file
diff --git a/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.py b/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.py
index aad267e90a..79dace7925 100644
--- a/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.py
+++ b/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.py
@@ -329,28 +329,29 @@ class GSTR3BReport(Document):
d.gst_category, []
)
- if state_number != d.place_of_supply.split("-")[0]:
- inter_state_supply_details[d.gst_category].append({
- "pos": d.place_of_supply,
- "txval": flt(d.total, 2),
- "iamt": flt(inter_state_supply_tax_mapping.get(d.place_of_supply), 2)
- })
- else:
- osup_det = self.report_dict["sup_details"]["osup_det"]
- osup_det["txval"] = flt(osup_det["txval"] + d.total, 2)
- osup_det["camt"] = flt(osup_det["camt"] + inter_state_supply_tax_mapping.get(d.place_of_supply)/2, 2)
- osup_det["samt"] = flt(osup_det["samt"] + inter_state_supply_tax_mapping.get(d.place_of_supply)/2, 2)
+ if d.place_of_supply:
+ if state_number != d.place_of_supply.split("-")[0]:
+ inter_state_supply_details[d.gst_category].append({
+ "pos": d.place_of_supply.split("-")[0],
+ "txval": flt(d.total, 2),
+ "iamt": flt(inter_state_supply_tax_mapping.get(d.place_of_supply), 2)
+ })
+ else:
+ osup_det = self.report_dict["sup_details"]["osup_det"]
+ osup_det["txval"] = flt(osup_det["txval"] + d.total, 2)
+ osup_det["camt"] = flt(osup_det["camt"] + inter_state_supply_tax_mapping.get(d.place_of_supply)/2, 2)
+ osup_det["samt"] = flt(osup_det["samt"] + inter_state_supply_tax_mapping.get(d.place_of_supply)/2, 2)
return inter_state_supply_details
def get_inward_nil_exempt(self, state):
- inward_nil_exempt = frappe.db.sql(""" select a.gst_state, sum(i.base_amount) as base_amount,
- i.is_nil_exempt, i.is_non_gst from `tabPurchase Invoice` p , `tabPurchase Invoice Item` i, `tabAddress` a
- where p.docstatus = 1 and p.name = i.parent and p.supplier_address = a.name
+ inward_nil_exempt = frappe.db.sql(""" select p.place_of_supply, sum(i.base_amount) as base_amount,
+ i.is_nil_exempt, i.is_non_gst from `tabPurchase Invoice` p , `tabPurchase Invoice Item` i
+ where p.docstatus = 1 and p.name = i.parent
and i.is_nil_exempt = 1 or i.is_non_gst = 1 and
month(p.posting_date) = %s and year(p.posting_date) = %s and p.company = %s and p.company_gstin = %s
- group by a.gst_state """, (self.month_no, self.year, self.company, self.gst_details.get("gstin")), as_dict=1)
+ group by p.place_of_supply """, (self.month_no, self.year, self.company, self.gst_details.get("gstin")), as_dict=1)
inward_nil_exempt_details = {
"gst": {
@@ -364,14 +365,15 @@ class GSTR3BReport(Document):
}
for d in inward_nil_exempt:
- if d.is_nil_exempt == 1 and state == d.gst_state:
- inward_nil_exempt_details["gst"]["intra"] += d.base_amount
- elif d.is_nil_exempt == 1 and state != d.gst_state:
- inward_nil_exempt_details["gst"]["inter"] += d.base_amount
- elif d.is_non_gst == 1 and state == d.gst_state:
- inward_nil_exempt_details["non_gst"]["inter"] += d.base_amount
- elif d.is_non_gst == 1 and state != d.gst_state:
- inward_nil_exempt_details["non_gst"]["intra"] += d.base_amount
+ if d.place_of_supply:
+ if d.is_nil_exempt == 1 and state == d.place_of_supply.split("-")[1]:
+ inward_nil_exempt_details["gst"]["intra"] += d.base_amount
+ elif d.is_nil_exempt == 1 and state != d.place_of_supply.split("-")[1]:
+ inward_nil_exempt_details["gst"]["inter"] += d.base_amount
+ elif d.is_non_gst == 1 and state == d.place_of_supply.split("-")[1]:
+ inward_nil_exempt_details["non_gst"]["intra"] += d.base_amount
+ elif d.is_non_gst == 1 and state != d.place_of_supply.split("-")[1]:
+ inward_nil_exempt_details["non_gst"]["inter"] += d.base_amount
return inward_nil_exempt_details
From b87c5d83de06a4f3b4c55bba11e047abc68d910b Mon Sep 17 00:00:00 2001
From: deepeshgarg007
Date: Sun, 11 Aug 2019 12:40:45 +0530
Subject: [PATCH 233/484] fix: Test Cases
---
erpnext/regional/doctype/gstr_3b_report/test_gstr_3b_report.py | 3 +++
1 file changed, 3 insertions(+)
diff --git a/erpnext/regional/doctype/gstr_3b_report/test_gstr_3b_report.py b/erpnext/regional/doctype/gstr_3b_report/test_gstr_3b_report.py
index de150f466e..fa33541e60 100644
--- a/erpnext/regional/doctype/gstr_3b_report/test_gstr_3b_report.py
+++ b/erpnext/regional/doctype/gstr_3b_report/test_gstr_3b_report.py
@@ -176,6 +176,9 @@ def create_purchase_invoices():
do_not_save=1
)
+ pi1.place_of_supply = "29-Karnataka"
+ pi1.save()
+
pi1.submit()
def make_suppliers():
From db017438851cf0b73abf23477f93bc75b8dc00b2 Mon Sep 17 00:00:00 2001
From: deepeshgarg007
Date: Sun, 11 Aug 2019 15:47:35 +0530
Subject: [PATCH 234/484] fix: Test Case
---
erpnext/regional/doctype/gstr_3b_report/test_gstr_3b_report.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/erpnext/regional/doctype/gstr_3b_report/test_gstr_3b_report.py b/erpnext/regional/doctype/gstr_3b_report/test_gstr_3b_report.py
index fa33541e60..fef73d9a0a 100644
--- a/erpnext/regional/doctype/gstr_3b_report/test_gstr_3b_report.py
+++ b/erpnext/regional/doctype/gstr_3b_report/test_gstr_3b_report.py
@@ -176,7 +176,7 @@ def create_purchase_invoices():
do_not_save=1
)
- pi1.place_of_supply = "29-Karnataka"
+ pi1.shipping_address = "_Test Supplier GST-1-Billing"
pi1.save()
pi1.submit()
@@ -221,6 +221,7 @@ def make_suppliers():
"link_name": "_Test Registered Supplier"
})
+ address.is_shipping_address = 1
address.save()
if not frappe.db.exists('Address', '_Test Supplier GST-2-Billing'):
From a0b9b3cef5fe786977f00107872f6618ea799939 Mon Sep 17 00:00:00 2001
From: sahil28297 <37302950+sahil28297@users.noreply.github.com>
Date: Mon, 12 Aug 2019 11:49:14 +0530
Subject: [PATCH 235/484] fix(patch): force reload child docs (#18671)
---
.../v12_0/update_pricing_rule_fields.py | 94 +++++++++----------
1 file changed, 47 insertions(+), 47 deletions(-)
diff --git a/erpnext/patches/v12_0/update_pricing_rule_fields.py b/erpnext/patches/v12_0/update_pricing_rule_fields.py
index 8f8349e9b5..985613a973 100644
--- a/erpnext/patches/v12_0/update_pricing_rule_fields.py
+++ b/erpnext/patches/v12_0/update_pricing_rule_fields.py
@@ -5,67 +5,67 @@ from __future__ import unicode_literals
import frappe
parentfield = {
- 'item_code': 'items',
- 'item_group': 'item_groups',
- 'brand': 'brands'
+ 'item_code': 'items',
+ 'item_group': 'item_groups',
+ 'brand': 'brands'
}
def execute():
- if not frappe.get_all('Pricing Rule', limit=1):
- return
+ if not frappe.get_all('Pricing Rule', limit=1):
+ return
- frappe.reload_doc('accounts', 'doctype', 'pricing_rule_detail')
- doctypes = {'Supplier Quotation': 'buying', 'Purchase Order': 'buying', 'Purchase Invoice': 'accounts',
- 'Purchase Receipt': 'stock', 'Quotation': 'selling', 'Sales Order': 'selling',
- 'Sales Invoice': 'accounts', 'Delivery Note': 'stock'}
+ frappe.reload_doc('accounts', 'doctype', 'pricing_rule_detail')
+ doctypes = {'Supplier Quotation': 'buying', 'Purchase Order': 'buying', 'Purchase Invoice': 'accounts',
+ 'Purchase Receipt': 'stock', 'Quotation': 'selling', 'Sales Order': 'selling',
+ 'Sales Invoice': 'accounts', 'Delivery Note': 'stock'}
- for doctype, module in doctypes.items():
- frappe.reload_doc(module, 'doctype', frappe.scrub(doctype))
+ for doctype, module in doctypes.items():
+ frappe.reload_doc(module, 'doctype', frappe.scrub(doctype))
- child_doc = frappe.scrub(doctype) + '_item'
- frappe.reload_doc(module, 'doctype', child_doc)
+ child_doc = frappe.scrub(doctype) + '_item'
+ frappe.reload_doc(module, 'doctype', child_doc, force=True)
- child_doctype = doctype + ' Item'
+ child_doctype = doctype + ' Item'
- frappe.db.sql(""" UPDATE `tab{child_doctype}` SET pricing_rules = pricing_rule
- WHERE docstatus < 2 and pricing_rule is not null and pricing_rule != ''
- """.format(child_doctype= child_doctype))
+ frappe.db.sql(""" UPDATE `tab{child_doctype}` SET pricing_rules = pricing_rule
+ WHERE docstatus < 2 and pricing_rule is not null and pricing_rule != ''
+ """.format(child_doctype= child_doctype))
- data = frappe.db.sql(""" SELECT pricing_rule, name, parent,
- parenttype, creation, modified, docstatus, modified_by, owner, name
- FROM `tab{child_doc}` where docstatus < 2 and pricing_rule is not null
- and pricing_rule != ''""".format(child_doc=child_doctype), as_dict=1)
+ data = frappe.db.sql(""" SELECT pricing_rule, name, parent,
+ parenttype, creation, modified, docstatus, modified_by, owner, name
+ FROM `tab{child_doc}` where docstatus < 2 and pricing_rule is not null
+ and pricing_rule != ''""".format(child_doc=child_doctype), as_dict=1)
- values = []
- for d in data:
- values.append((d.pricing_rule, d.name, d.parent, 'pricing_rules', d.parenttype,
- d.creation, d.modified, d.docstatus, d.modified_by, d.owner, frappe.generate_hash("", 10)))
+ values = []
+ for d in data:
+ values.append((d.pricing_rule, d.name, d.parent, 'pricing_rules', d.parenttype,
+ d.creation, d.modified, d.docstatus, d.modified_by, d.owner, frappe.generate_hash("", 10)))
- if values:
- frappe.db.sql(""" INSERT INTO
- `tabPricing Rule Detail` (`pricing_rule`, `child_docname`, `parent`, `parentfield`, `parenttype`,
- `creation`, `modified`, `docstatus`, `modified_by`, `owner`, `name`)
- VALUES {values} """.format(values=', '.join(['%s'] * len(values))), tuple(values))
+ if values:
+ frappe.db.sql(""" INSERT INTO
+ `tabPricing Rule Detail` (`pricing_rule`, `child_docname`, `parent`, `parentfield`, `parenttype`,
+ `creation`, `modified`, `docstatus`, `modified_by`, `owner`, `name`)
+ VALUES {values} """.format(values=', '.join(['%s'] * len(values))), tuple(values))
- frappe.reload_doc('accounts', 'doctype', 'pricing_rule')
+ frappe.reload_doc('accounts', 'doctype', 'pricing_rule')
- for doctype, apply_on in {'Pricing Rule Item Code': 'Item Code',
- 'Pricing Rule Item Group': 'Item Group', 'Pricing Rule Brand': 'Brand'}.items():
- frappe.reload_doc('accounts', 'doctype', frappe.scrub(doctype))
+ for doctype, apply_on in {'Pricing Rule Item Code': 'Item Code',
+ 'Pricing Rule Item Group': 'Item Group', 'Pricing Rule Brand': 'Brand'}.items():
+ frappe.reload_doc('accounts', 'doctype', frappe.scrub(doctype))
- field = frappe.scrub(apply_on)
- data = frappe.get_all('Pricing Rule', fields=[field, "name", "creation", "modified",
- "owner", "modified_by"], filters= {'apply_on': apply_on})
+ field = frappe.scrub(apply_on)
+ data = frappe.get_all('Pricing Rule', fields=[field, "name", "creation", "modified",
+ "owner", "modified_by"], filters= {'apply_on': apply_on})
- values = []
- for d in data:
- values.append((d.get(field), d.name, parentfield.get(field), 'Pricing Rule',
- d.creation, d.modified, d.owner, d.modified_by, frappe.generate_hash("", 10)))
+ values = []
+ for d in data:
+ values.append((d.get(field), d.name, parentfield.get(field), 'Pricing Rule',
+ d.creation, d.modified, d.owner, d.modified_by, frappe.generate_hash("", 10)))
- if values:
- frappe.db.sql(""" INSERT INTO
- `tab{doctype}` ({field}, parent, parentfield, parenttype, creation, modified,
- owner, modified_by, name)
- VALUES {values} """.format(doctype=doctype,
- field=field, values=', '.join(['%s'] * len(values))), tuple(values))
\ No newline at end of file
+ if values:
+ frappe.db.sql(""" INSERT INTO
+ `tab{doctype}` ({field}, parent, parentfield, parenttype, creation, modified,
+ owner, modified_by, name)
+ VALUES {values} """.format(doctype=doctype,
+ field=field, values=', '.join(['%s'] * len(values))), tuple(values))
From 83705af0b336ec7b87a7f32854e3c4a6aacd5690 Mon Sep 17 00:00:00 2001
From: Suraj Shetty <13928957+surajshetty3416@users.noreply.github.com>
Date: Mon, 12 Aug 2019 11:51:27 +0530
Subject: [PATCH 236/484] fix: Filters for portal quotation list (#18689)
* fix: Filters for portal quotation list
* fix: Remove unwanted import
---
.../controllers/website_list_for_contact.py | 59 ++++++++-----------
erpnext/templates/pages/rfq.py | 7 +--
2 files changed, 29 insertions(+), 37 deletions(-)
diff --git a/erpnext/controllers/website_list_for_contact.py b/erpnext/controllers/website_list_for_contact.py
index 187eaed107..0738fd506f 100644
--- a/erpnext/controllers/website_list_for_contact.py
+++ b/erpnext/controllers/website_list_for_contact.py
@@ -21,42 +21,45 @@ def get_list_context(context=None):
def get_transaction_list(doctype, txt=None, filters=None, limit_start=0, limit_page_length=20, order_by="modified"):
user = frappe.session.user
- key = None
+ ignore_permissions = False
if not filters: filters = []
if doctype == 'Supplier Quotation':
- filters.append((doctype, "docstatus", "<", 2))
+ filters.append((doctype, 'docstatus', '<', 2))
else:
- filters.append((doctype, "docstatus", "=", 1))
+ filters.append((doctype, 'docstatus', '=', 1))
- if (user != "Guest" and is_website_user()) or doctype == 'Request for Quotation':
+ if (user != 'Guest' and is_website_user()) or doctype == 'Request for Quotation':
parties_doctype = 'Request for Quotation Supplier' if doctype == 'Request for Quotation' else doctype
# find party for this contact
customers, suppliers = get_customers_suppliers(parties_doctype, user)
- if not customers and not suppliers: return []
-
- key, parties = get_party_details(customers, suppliers)
-
- if doctype == 'Request for Quotation':
- return rfq_transaction_list(parties_doctype, doctype, parties, limit_start, limit_page_length)
-
- filters.append((doctype, key, "in", parties))
-
- if key:
- return post_process(doctype, get_list_for_transactions(doctype, txt,
- filters=filters, fields="name",limit_start=limit_start,
- limit_page_length=limit_page_length,ignore_permissions=True,
- order_by="modified desc"))
+ if customers:
+ if doctype == 'Quotation':
+ filters.append(('quotation_to', '=', 'Customer'))
+ filters.append(('party_name', 'in', customers))
+ else:
+ filters.append(('customer', 'in', customers))
+ elif suppliers:
+ filters.append(('supplier', 'in', suppliers))
else:
return []
- return post_process(doctype, get_list_for_transactions(doctype, txt, filters, limit_start, limit_page_length,
- fields="name", order_by="modified desc"))
+ if doctype == 'Request for Quotation':
+ parties = customers or suppliers
+ return rfq_transaction_list(parties_doctype, doctype, parties, limit_start, limit_page_length)
+
+ # Since customers and supplier do not have direct access to internal doctypes
+ ignore_permissions = True
+
+ transactions = get_list_for_transactions(doctype, txt, filters, limit_start, limit_page_length,
+ fields='name', ignore_permissions=ignore_permissions, order_by='modified desc')
+
+ return post_process(doctype, transactions)
def get_list_for_transactions(doctype, txt, filters, limit_start, limit_page_length=20,
- ignore_permissions=False,fields=None, order_by=None):
+ ignore_permissions=False, fields=None, order_by=None):
""" Get List of transactions like Invoices, Orders """
from frappe.www.list import get_list
meta = frappe.get_meta(doctype)
@@ -83,16 +86,6 @@ def get_list_for_transactions(doctype, txt, filters, limit_start, limit_page_len
return data
-def get_party_details(customers, suppliers):
- if customers:
- key, parties = "customer", customers
- elif suppliers:
- key, parties = "supplier", suppliers
- else:
- key, parties = "customer", []
-
- return key, parties
-
def rfq_transaction_list(parties_doctype, doctype, parties, limit_start, limit_page_length):
data = frappe.db.sql("""select distinct parent as name, supplier from `tab{doctype}`
where supplier = '{supplier}' and docstatus=1 order by modified desc limit {start}, {len}""".
@@ -159,7 +152,7 @@ def has_website_permission(doc, ptype, user, verbose=False):
doctype = doc.doctype
customers, suppliers = get_customers_suppliers(doctype, user)
if customers:
- return frappe.db.exists(doctype, filters=get_customer_filter(doc, customers))
+ return frappe.db.exists(doctype, get_customer_filter(doc, customers))
elif suppliers:
fieldname = 'suppliers' if doctype == 'Request for Quotation' else 'supplier'
return frappe.db.exists(doctype, filters={
@@ -175,7 +168,7 @@ def get_customer_filter(doc, customers):
filters.name = doc.name
filters[get_customer_field_name(doctype)] = ['in', customers]
if doctype == 'Quotation':
- filters.party_type = 'Customer'
+ filters.quotation_to = 'Customer'
return filters
def get_customer_field_name(doctype):
diff --git a/erpnext/templates/pages/rfq.py b/erpnext/templates/pages/rfq.py
index 62ec60966b..67679a1a7d 100644
--- a/erpnext/templates/pages/rfq.py
+++ b/erpnext/templates/pages/rfq.py
@@ -5,8 +5,7 @@ from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.utils import formatdate
-from erpnext.controllers.website_list_for_contact import (get_customers_suppliers,
- get_party_details)
+from erpnext.controllers.website_list_for_contact import get_customers_suppliers
def get_context(context):
context.no_cache = 1
@@ -23,8 +22,8 @@ def get_supplier():
doctype = frappe.form_dict.doctype
parties_doctype = 'Request for Quotation Supplier' if doctype == 'Request for Quotation' else doctype
customers, suppliers = get_customers_suppliers(parties_doctype, frappe.session.user)
- key, parties = get_party_details(customers, suppliers)
- return parties[0] if key == 'supplier' else ''
+
+ return suppliers[0] if suppliers else ''
def check_supplier_has_docname_access(supplier):
status = True
From 677c522f01b9aa583de64cd5bc78162550fdec87 Mon Sep 17 00:00:00 2001
From: Andrew McLeod
Date: Mon, 12 Aug 2019 07:36:23 +0100
Subject: [PATCH 237/484] fix: Python3 urllib use in item_group.py (now uses
six.moves) (#18642)
---
erpnext/setup/doctype/item_group/item_group.py | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/erpnext/setup/doctype/item_group/item_group.py b/erpnext/setup/doctype/item_group/item_group.py
index cab21162c7..33ab992568 100644
--- a/erpnext/setup/doctype/item_group/item_group.py
+++ b/erpnext/setup/doctype/item_group/item_group.py
@@ -3,7 +3,6 @@
from __future__ import unicode_literals
import frappe
-import urllib
import copy
from frappe.utils import nowdate, cint, cstr
from frappe.utils.nestedset import NestedSet
@@ -12,6 +11,7 @@ from frappe.website.render import clear_cache
from frappe.website.doctype.website_slideshow.website_slideshow import get_slideshow
from erpnext.shopping_cart.product_info import set_product_info_for_website
from erpnext.utilities.product import get_qty_in_stock
+from six.moves.urllib.parse import quote
class ItemGroup(NestedSet, WebsiteGenerator):
nsm_parent_field = 'parent_item_group'
@@ -165,7 +165,7 @@ def get_item_for_list_in_html(context):
# add missing absolute link in files
# user may forget it during upload
if (context.get("website_image") or "").startswith("files/"):
- context["website_image"] = "/" + urllib.quote(context["website_image"])
+ context["website_image"] = "/" + quote(context["website_image"])
context["show_availability_status"] = cint(frappe.db.get_single_value('Products Settings',
'show_availability_status'))
@@ -218,4 +218,4 @@ def get_item_group_defaults(item, company):
row.pop("name")
return row
- return frappe._dict()
\ No newline at end of file
+ return frappe._dict()
From 19199baf29024233ded5138336c1b0c1622af1d1 Mon Sep 17 00:00:00 2001
From: Himanshu
Date: Mon, 12 Aug 2019 12:17:28 +0530
Subject: [PATCH 238/484] fix: miscellaneous fixes (#18615)
---
erpnext/stock/doctype/item/item.json | 1 -
erpnext/stock/doctype/purchase_receipt/purchase_receipt.js | 2 +-
2 files changed, 1 insertion(+), 2 deletions(-)
diff --git a/erpnext/stock/doctype/item/item.json b/erpnext/stock/doctype/item/item.json
index a142bb9035..383fb61f51 100644
--- a/erpnext/stock/doctype/item/item.json
+++ b/erpnext/stock/doctype/item/item.json
@@ -468,7 +468,6 @@
},
{
"default": "0",
- "depends_on": "has_batch_no",
"fieldname": "retain_sample",
"fieldtype": "Check",
"label": "Retain Sample"
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js
index 7da648aad9..8266055d69 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js
@@ -190,7 +190,7 @@ erpnext.stock.PurchaseReceiptController = erpnext.buying.BuyingController.extend
frappe.set_route("Form", doc.doctype, doc.name);
}
else {
- frappe.msgprint(__("Retention Stock Entry already created or Sample Quantity not provided"));
+ frappe.msgprint(__("Purchase Receipt doesn't have any Item for which Retain Sample is enabled."));
}
}
});
From cfce53103b9c206afdb1fd5d5cfa231f57961bd1 Mon Sep 17 00:00:00 2001
From: DeeMysterio
Date: Mon, 12 Aug 2019 13:03:55 +0530
Subject: [PATCH 239/484] fix(delivery note): change the text invoice to sales
invoice on make button (#18666)
---
erpnext/stock/doctype/delivery_note/delivery_note.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.js b/erpnext/stock/doctype/delivery_note/delivery_note.js
index 569a03a8f1..a88bb2ad1e 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.js
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.js
@@ -197,7 +197,7 @@ erpnext.stock.DeliveryNoteController = erpnext.selling.SellingController.extend(
});
if(!from_sales_invoice) {
- this.frm.add_custom_button(__('Invoice'), function() { me.make_sales_invoice() },
+ this.frm.add_custom_button(__('Sales Invoice'), function() { me.make_sales_invoice() },
__('Create'));
}
}
From fb237739358930b4057528203be4275aa3dd730a Mon Sep 17 00:00:00 2001
From: Rohit Waghchaure
Date: Mon, 12 Aug 2019 14:56:57 +0530
Subject: [PATCH 240/484] fix: reconciled entry has not clearance date set
---
erpnext/accounts/doctype/bank_transaction/bank_transaction.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/accounts/doctype/bank_transaction/bank_transaction.py b/erpnext/accounts/doctype/bank_transaction/bank_transaction.py
index f943b34581..716ec1f552 100644
--- a/erpnext/accounts/doctype/bank_transaction/bank_transaction.py
+++ b/erpnext/accounts/doctype/bank_transaction/bank_transaction.py
@@ -50,7 +50,7 @@ class BankTransaction(StatusUpdater):
if paid_amount and allocated_amount:
if flt(allocated_amount[0]["allocated_amount"]) > flt(paid_amount):
frappe.throw(_("The total allocated amount ({0}) is greated than the paid amount ({1}).".format(flt(allocated_amount[0]["allocated_amount"]), flt(paid_amount))))
- elif flt(allocated_amount[0]["allocated_amount"]) == flt(paid_amount):
+ else:
if payment_entry.payment_document in ["Payment Entry", "Journal Entry", "Purchase Invoice", "Expense Claim"]:
self.clear_simple_entry(payment_entry)
From 8b9b77959d0b2b03158cfa376d3d4d74ee1b3005 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Tue, 13 Aug 2019 13:20:10 +0530
Subject: [PATCH 241/484] fix: fetch min date when carry forward expiry is
greater than leave allocation expiry
---
erpnext/hr/doctype/leave_allocation/leave_allocation.py | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.py b/erpnext/hr/doctype/leave_allocation/leave_allocation.py
index c11c125c6a..296a52c2c7 100755
--- a/erpnext/hr/doctype/leave_allocation/leave_allocation.py
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.py
@@ -3,7 +3,7 @@
from __future__ import unicode_literals
import frappe
-from frappe.utils import flt, date_diff, formatdate, add_days, today
+from frappe.utils import flt, date_diff, formatdate, add_days, today, getdate
from frappe import _
from frappe.model.document import Document
from erpnext.hr.utils import set_employee_name, get_leave_period
@@ -127,10 +127,11 @@ class LeaveAllocation(Document):
def create_leave_ledger_entry(self, submit=True):
if self.unused_leaves:
expiry_days = frappe.db.get_value("Leave Type", self.leave_type, "expire_carry_forwarded_leaves_after_days")
+ end_date = add_days(self.from_date, expiry_days - 1) if expiry_days else self.to_date
args = dict(
leaves=self.unused_leaves,
from_date=self.from_date,
- to_date=add_days(self.from_date, expiry_days - 1) if expiry_days else self.to_date,
+ to_date= min(getdate(end_date), getdate(self.to_date)),
is_carry_forward=1
)
create_leave_ledger_entry(self, args, submit)
From f841afd48dd7d1f4bfeb7db53d209c7f51071f5b Mon Sep 17 00:00:00 2001
From: Sahil Khan
Date: Tue, 13 Aug 2019 15:04:18 +0550
Subject: [PATCH 242/484] bumped to version 12.0.6
---
erpnext/__init__.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/__init__.py b/erpnext/__init__.py
index 0a735a1da1..e1c3d78d3f 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__ = '12.0.5'
+__version__ = '12.0.6'
def get_default_company(user=None):
'''Get default company for user'''
From e14a00b887beb062c45e72b310ccb3347f3f036f Mon Sep 17 00:00:00 2001
From: Sagar Vora
Date: Tue, 13 Aug 2019 17:26:56 +0530
Subject: [PATCH 243/484] fix: v12 patches sequence (#18609)
---
erpnext/patches.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 33d4f55ae0..b6ea542554 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -596,6 +596,7 @@ erpnext.patches.v12_0.rename_pricing_rule_child_doctypes
erpnext.patches.v12_0.move_target_distribution_from_parent_to_child
erpnext.patches.v12_0.stock_entry_enhancements
erpnext.patches.v10_0.item_barcode_childtable_migrate # 16-02-2019 #25-06-2019
+erpnext.patches.v12_0.make_item_manufacturer
erpnext.patches.v12_0.move_item_tax_to_item_tax_template
erpnext.patches.v11_1.set_variant_based_on
erpnext.patches.v11_1.woocommerce_set_creation_user
@@ -606,7 +607,6 @@ erpnext.patches.v11_1.delete_scheduling_tool
erpnext.patches.v12_0.rename_tolerance_fields
erpnext.patches.v12_0.make_custom_fields_for_bank_remittance #14-06-2019
execute:frappe.delete_doc_if_exists("Page", "support-analytics")
-erpnext.patches.v12_0.make_item_manufacturer
erpnext.patches.v12_0.remove_patient_medical_record_page
erpnext.patches.v11_1.move_customer_lead_to_dynamic_column
erpnext.patches.v11_1.set_default_action_for_quality_inspection
From 81d5265385393a2b78c936613fddffd528f3bc62 Mon Sep 17 00:00:00 2001
From: Anurag Mishra
Date: Tue, 13 Aug 2019 19:40:36 +0530
Subject: [PATCH 244/484] fix: removed hard coded string
---
erpnext/setup/doctype/company/company.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/setup/doctype/company/company.py b/erpnext/setup/doctype/company/company.py
index da29d20503..584391e1e0 100644
--- a/erpnext/setup/doctype/company/company.py
+++ b/erpnext/setup/doctype/company/company.py
@@ -252,7 +252,7 @@ class Company(NestedSet):
def set_mode_of_payment_account(self):
cash = frappe.db.get_value('Mode of Payment', {'type': 'Cash'}, 'name')
if cash and self.default_cash_account \
- and not frappe.db.get_value('Mode of Payment Account', {'company': self.name, 'parent': 'Cash'}):
+ and not frappe.db.get_value('Mode of Payment Account', {'company': self.name, 'parent': cash}):
mode_of_payment = frappe.get_doc('Mode of Payment', cash)
mode_of_payment.append('accounts', {
'company': self.name,
From 904cbef4dc3559802fec472de21a3e0401542281 Mon Sep 17 00:00:00 2001
From: Anurag Mishra
Date: Tue, 13 Aug 2019 19:48:42 +0530
Subject: [PATCH 245/484] fix: removed hard coded string
---
erpnext/setup/doctype/company/company.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/setup/doctype/company/company.py b/erpnext/setup/doctype/company/company.py
index da29d20503..4b34dc1fa5 100644
--- a/erpnext/setup/doctype/company/company.py
+++ b/erpnext/setup/doctype/company/company.py
@@ -252,7 +252,7 @@ class Company(NestedSet):
def set_mode_of_payment_account(self):
cash = frappe.db.get_value('Mode of Payment', {'type': 'Cash'}, 'name')
if cash and self.default_cash_account \
- and not frappe.db.get_value('Mode of Payment Account', {'company': self.name, 'parent': 'Cash'}):
+ and not frappe.db.get_value('Mode of Payment Account', {'company': self.name, 'parent': cash}):
mode_of_payment = frappe.get_doc('Mode of Payment', cash)
mode_of_payment.append('accounts', {
'company': self.name,
From 44546305490e99213f0310dc0bf6cb8549138d59 Mon Sep 17 00:00:00 2001
From: Vignesh S
Date: Tue, 30 Jul 2019 01:16:17 +0530
Subject: [PATCH 246/484] feat(Auto Attendance): Add grace period
Co-authored-by: Karthikeyan S
---
erpnext/hr/doctype/attendance/attendance.json | 19 +++++++-
.../employee_checkin/employee_checkin.json | 18 +------
.../employee_checkin/employee_checkin.py | 22 +++++++--
.../employee_checkin/test_employee_checkin.py | 8 ++--
erpnext/hr/doctype/shift_type/shift_type.json | 47 +------------------
erpnext/hr/doctype/shift_type/shift_type.py | 19 +++++---
.../monthly_attendance_sheet.py | 8 +++-
7 files changed, 61 insertions(+), 80 deletions(-)
diff --git a/erpnext/hr/doctype/attendance/attendance.json b/erpnext/hr/doctype/attendance/attendance.json
index eb38147a98..bc89b368d3 100644
--- a/erpnext/hr/doctype/attendance/attendance.json
+++ b/erpnext/hr/doctype/attendance/attendance.json
@@ -4,6 +4,7 @@
"creation": "2013-01-10 16:34:13",
"doctype": "DocType",
"document_type": "Setup",
+ "engine": "InnoDB",
"field_order": [
"attendance_details",
"naming_series",
@@ -19,7 +20,9 @@
"department",
"shift",
"attendance_request",
- "amended_from"
+ "amended_from",
+ "late_entry",
+ "early_exit"
],
"fields": [
{
@@ -153,12 +156,24 @@
"fieldtype": "Link",
"label": "Shift",
"options": "Shift Type"
+ },
+ {
+ "default": "0",
+ "fieldname": "late_entry",
+ "fieldtype": "Check",
+ "label": "Late Entry"
+ },
+ {
+ "default": "0",
+ "fieldname": "early_exit",
+ "fieldtype": "Check",
+ "label": "Early Exit"
}
],
"icon": "fa fa-ok",
"idx": 1,
"is_submittable": 1,
- "modified": "2019-06-05 19:37:30.410071",
+ "modified": "2019-07-29 20:35:40.845422",
"modified_by": "Administrator",
"module": "HR",
"name": "Attendance",
diff --git a/erpnext/hr/doctype/employee_checkin/employee_checkin.json b/erpnext/hr/doctype/employee_checkin/employee_checkin.json
index 15ec7c0b1b..08fa4afa5c 100644
--- a/erpnext/hr/doctype/employee_checkin/employee_checkin.json
+++ b/erpnext/hr/doctype/employee_checkin/employee_checkin.json
@@ -14,8 +14,6 @@
"device_id",
"skip_auto_attendance",
"attendance",
- "entry_grace_period_consequence",
- "exit_grace_period_consequence",
"shift_start",
"shift_end",
"shift_actual_start",
@@ -80,20 +78,6 @@
"options": "Attendance",
"read_only": 1
},
- {
- "default": "0",
- "fieldname": "entry_grace_period_consequence",
- "fieldtype": "Check",
- "hidden": 1,
- "label": "Entry Grace Period Consequence"
- },
- {
- "default": "0",
- "fieldname": "exit_grace_period_consequence",
- "fieldtype": "Check",
- "hidden": 1,
- "label": "Exit Grace Period Consequence"
- },
{
"fieldname": "shift_start",
"fieldtype": "Datetime",
@@ -119,7 +103,7 @@
"label": "Shift Actual End"
}
],
- "modified": "2019-06-10 15:33:22.731697",
+ "modified": "2019-07-23 23:47:33.975263",
"modified_by": "Administrator",
"module": "HR",
"name": "Employee Checkin",
diff --git a/erpnext/hr/doctype/employee_checkin/employee_checkin.py b/erpnext/hr/doctype/employee_checkin/employee_checkin.py
index b0e15d96ed..d7d6706140 100644
--- a/erpnext/hr/doctype/employee_checkin/employee_checkin.py
+++ b/erpnext/hr/doctype/employee_checkin/employee_checkin.py
@@ -72,7 +72,7 @@ def add_log_based_on_employee_field(employee_field_value, timestamp, device_id=N
return doc
-def mark_attendance_and_link_log(logs, attendance_status, attendance_date, working_hours=None, shift=None):
+def mark_attendance_and_link_log(logs, attendance_status, attendance_date, working_hours=None, late_entry=False, early_exit=False, shift=None):
"""Creates an attendance and links the attendance to the Employee Checkin.
Note: If attendance is already present for the given date, the logs are marked as skipped and no exception is thrown.
@@ -98,7 +98,9 @@ def mark_attendance_and_link_log(logs, attendance_status, attendance_date, worki
'status': attendance_status,
'working_hours': working_hours,
'company': employee_doc.company,
- 'shift': shift
+ 'shift': shift,
+ 'late_entry': late_entry,
+ 'early_exit': early_exit
}
attendance = frappe.get_doc(doc_dict).insert()
attendance.submit()
@@ -124,11 +126,16 @@ def calculate_working_hours(logs, check_in_out_type, working_hours_calc_type):
:param working_hours_calc_type: One of: 'First Check-in and Last Check-out', 'Every Valid Check-in and Check-out'
"""
total_hours = 0
+ in_time = out_time = None
if check_in_out_type == 'Alternating entries as IN and OUT during the same shift':
+ in_time = logs[0].time
+ if len(logs) >= 2:
+ out_time = logs[-1].time
if working_hours_calc_type == 'First Check-in and Last Check-out':
# assumption in this case: First log always taken as IN, Last log always taken as OUT
- total_hours = time_diff_in_hours(logs[0].time, logs[-1].time)
+ total_hours = time_diff_in_hours(in_time, logs[-1].time)
elif working_hours_calc_type == 'Every Valid Check-in and Check-out':
+ logs = logs[:]
while len(logs) >= 2:
total_hours += time_diff_in_hours(logs[0].time, logs[1].time)
del logs[:2]
@@ -138,11 +145,15 @@ def calculate_working_hours(logs, check_in_out_type, working_hours_calc_type):
first_in_log = logs[find_index_in_dict(logs, 'log_type', 'IN')]
last_out_log = logs[len(logs)-1-find_index_in_dict(reversed(logs), 'log_type', 'OUT')]
if first_in_log and last_out_log:
- total_hours = time_diff_in_hours(first_in_log.time, last_out_log.time)
+ in_time, out_time = first_in_log.time, last_out_log.time
+ total_hours = time_diff_in_hours(in_time, out_time)
elif working_hours_calc_type == 'Every Valid Check-in and Check-out':
in_log = out_log = None
for log in logs:
if in_log and out_log:
+ if not in_time:
+ in_time = in_log.time
+ out_time = out_log.time
total_hours += time_diff_in_hours(in_log.time, out_log.time)
in_log = out_log = None
if not in_log:
@@ -150,8 +161,9 @@ def calculate_working_hours(logs, check_in_out_type, working_hours_calc_type):
elif not out_log:
out_log = log if log.log_type == 'OUT' else None
if in_log and out_log:
+ out_time = out_log.time
total_hours += time_diff_in_hours(in_log.time, out_log.time)
- return total_hours
+ return total_hours, in_time, out_time
def time_diff_in_hours(start, end):
return round((end-start).total_seconds() / 3600, 1)
diff --git a/erpnext/hr/doctype/employee_checkin/test_employee_checkin.py b/erpnext/hr/doctype/employee_checkin/test_employee_checkin.py
index 424d1a3c1b..9f12ef24e6 100644
--- a/erpnext/hr/doctype/employee_checkin/test_employee_checkin.py
+++ b/erpnext/hr/doctype/employee_checkin/test_employee_checkin.py
@@ -70,16 +70,16 @@ class TestEmployeeCheckin(unittest.TestCase):
logs_type_2 = [frappe._dict(x) for x in logs_type_2]
working_hours = calculate_working_hours(logs_type_1,check_in_out_type[0],working_hours_calc_type[0])
- self.assertEqual(working_hours, 6.5)
+ self.assertEqual(working_hours, (6.5, logs_type_1[0].time, logs_type_1[-1].time))
working_hours = calculate_working_hours(logs_type_1,check_in_out_type[0],working_hours_calc_type[1])
- self.assertEqual(working_hours, 4.5)
+ self.assertEqual(working_hours, (4.5, logs_type_1[0].time, logs_type_1[-1].time))
working_hours = calculate_working_hours(logs_type_2,check_in_out_type[1],working_hours_calc_type[0])
- self.assertEqual(working_hours, 5)
+ self.assertEqual(working_hours, (5, logs_type_2[1].time, logs_type_2[-1].time))
working_hours = calculate_working_hours(logs_type_2,check_in_out_type[1],working_hours_calc_type[1])
- self.assertEqual(working_hours, 4.5)
+ self.assertEqual(working_hours, (4.5, logs_type_2[1].time, logs_type_2[-1].time))
def make_n_checkins(employee, n, hours_to_reverse=1):
logs = [make_checkin(employee, now_datetime() - timedelta(hours=hours_to_reverse, minutes=n+1))]
diff --git a/erpnext/hr/doctype/shift_type/shift_type.json b/erpnext/hr/doctype/shift_type/shift_type.json
index 86039deebd..61f3d2c279 100644
--- a/erpnext/hr/doctype/shift_type/shift_type.json
+++ b/erpnext/hr/doctype/shift_type/shift_type.json
@@ -23,14 +23,9 @@
"grace_period_settings_auto_attendance_section",
"enable_entry_grace_period",
"late_entry_grace_period",
- "consequence_after",
- "consequence",
"column_break_18",
"enable_exit_grace_period",
- "enable_different_consequence_for_early_exit",
- "early_exit_grace_period",
- "early_exit_consequence_after",
- "early_exit_consequence"
+ "early_exit_grace_period"
],
"fields": [
{
@@ -107,21 +102,6 @@
"fieldtype": "Int",
"label": "Late Entry Grace Period"
},
- {
- "depends_on": "enable_entry_grace_period",
- "description": "The number of occurrence after which the consequence is executed.",
- "fieldname": "consequence_after",
- "fieldtype": "Int",
- "label": "Consequence after"
- },
- {
- "default": "Half Day",
- "depends_on": "enable_entry_grace_period",
- "fieldname": "consequence",
- "fieldtype": "Select",
- "label": "Consequence",
- "options": "Half Day\nAbsent"
- },
{
"fieldname": "column_break_18",
"fieldtype": "Column Break"
@@ -132,13 +112,6 @@
"fieldtype": "Check",
"label": "Enable Exit Grace Period"
},
- {
- "default": "0",
- "depends_on": "enable_exit_grace_period",
- "fieldname": "enable_different_consequence_for_early_exit",
- "fieldtype": "Check",
- "label": "Enable Different Consequence for Early Exit"
- },
{
"depends_on": "eval:doc.enable_exit_grace_period",
"description": "The time before the shift end time when check-out is considered as early (in minutes).",
@@ -146,21 +119,6 @@
"fieldtype": "Int",
"label": "Early Exit Grace Period"
},
- {
- "depends_on": "eval:doc.enable_exit_grace_period && doc.enable_different_consequence_for_early_exit",
- "description": "The number of occurrence after which the consequence is executed.",
- "fieldname": "early_exit_consequence_after",
- "fieldtype": "Int",
- "label": "Early Exit Consequence after"
- },
- {
- "default": "Half Day",
- "depends_on": "eval:doc.enable_exit_grace_period && doc.enable_different_consequence_for_early_exit",
- "fieldname": "early_exit_consequence",
- "fieldtype": "Select",
- "label": "Early Exit Consequence",
- "options": "Half Day\nAbsent"
- },
{
"default": "60",
"description": "Time after the end of shift during which check-out is considered for attendance.",
@@ -178,7 +136,6 @@
"depends_on": "enable_auto_attendance",
"fieldname": "grace_period_settings_auto_attendance_section",
"fieldtype": "Section Break",
- "hidden": 1,
"label": "Grace Period Settings For Auto Attendance"
},
{
@@ -201,7 +158,7 @@
"label": "Last Sync of Checkin"
}
],
- "modified": "2019-06-10 06:02:44.272036",
+ "modified": "2019-07-30 01:05:24.660666",
"modified_by": "Administrator",
"module": "HR",
"name": "Shift Type",
diff --git a/erpnext/hr/doctype/shift_type/shift_type.py b/erpnext/hr/doctype/shift_type/shift_type.py
index b98f445c0f..8de92b2761 100644
--- a/erpnext/hr/doctype/shift_type/shift_type.py
+++ b/erpnext/hr/doctype/shift_type/shift_type.py
@@ -28,8 +28,8 @@ class ShiftType(Document):
logs = frappe.db.get_list('Employee Checkin', fields="*", filters=filters, order_by="employee,time")
for key, group in itertools.groupby(logs, key=lambda x: (x['employee'], x['shift_actual_start'])):
single_shift_logs = list(group)
- attendance_status, working_hours = self.get_attendance(single_shift_logs)
- mark_attendance_and_link_log(single_shift_logs, attendance_status, key[1].date(), working_hours, self.name)
+ attendance_status, working_hours, late_entry, early_exit = self.get_attendance(single_shift_logs)
+ mark_attendance_and_link_log(single_shift_logs, attendance_status, key[1].date(), working_hours, late_entry, early_exit, self.name)
for employee in self.get_assigned_employee(self.process_attendance_after, True):
self.mark_absent_for_dates_with_no_attendance(employee)
@@ -39,12 +39,19 @@ class ShiftType(Document):
1. These logs belongs to an single shift, single employee and is not in a holiday date.
2. Logs are in chronological order
"""
- total_working_hours = calculate_working_hours(logs, self.determine_check_in_and_check_out, self.working_hours_calculation_based_on)
+ late_entry = early_exit = False
+ total_working_hours, in_time, out_time = calculate_working_hours(logs, self.determine_check_in_and_check_out, self.working_hours_calculation_based_on)
+ if cint(self.enable_entry_grace_period) and in_time and in_time > logs[0].shift_start + timedelta(minutes=cint(self.late_entry_grace_period)):
+ late_entry = True
+
+ if cint(self.enable_exit_grace_period) and out_time and out_time < logs[0].shift_end - timedelta(minutes=cint(self.early_exit_grace_period)):
+ early_exit = True
+
if self.working_hours_threshold_for_absent and total_working_hours < self.working_hours_threshold_for_absent:
- return 'Absent', total_working_hours
+ return 'Absent', total_working_hours, late_entry, early_exit
if self.working_hours_threshold_for_half_day and total_working_hours < self.working_hours_threshold_for_half_day:
- return 'Half Day', total_working_hours
- return 'Present', total_working_hours
+ return 'Half Day', total_working_hours, late_entry, early_exit
+ return 'Present', total_working_hours, late_entry, early_exit
def mark_absent_for_dates_with_no_attendance(self, employee):
"""Marks Absents for the given employee on working days in this shift which have no attendance marked.
diff --git a/erpnext/hr/report/monthly_attendance_sheet/monthly_attendance_sheet.py b/erpnext/hr/report/monthly_attendance_sheet/monthly_attendance_sheet.py
index e9c702944d..1e9c83bf3e 100644
--- a/erpnext/hr/report/monthly_attendance_sheet/monthly_attendance_sheet.py
+++ b/erpnext/hr/report/monthly_attendance_sheet/monthly_attendance_sheet.py
@@ -25,6 +25,7 @@ def execute(filters=None):
leave_types = frappe.db.sql("""select name from `tabLeave Type`""", as_list=True)
leave_list = [d[0] for d in leave_types]
columns.extend(leave_list)
+ columns.extend([_("Total Late Entries") + ":Float:120", _("Total Early Exits") + ":Float:120"])
for emp in sorted(att_map):
emp_det = emp_map.get(emp)
@@ -65,6 +66,10 @@ def execute(filters=None):
leave_details = frappe.db.sql("""select leave_type, status, count(*) as count from `tabAttendance`\
where leave_type is not NULL %s group by leave_type, status""" % conditions, filters, as_dict=1)
+
+ time_default_counts = frappe.db.sql("""select (select count(*) from `tabAttendance` where \
+ late_entry = 1 %s) as late_entry_count, (select count(*) from tabAttendance where \
+ early_exit = 1 %s) as early_exit_count""" % (conditions, conditions), filters)
leaves = {}
for d in leave_details:
@@ -80,7 +85,8 @@ def execute(filters=None):
row.append(leaves[d])
else:
row.append("0.0")
-
+
+ row.extend([time_default_counts[0][0],time_default_counts[0][1]])
data.append(row)
return columns, data
From 06ce1f5a403edc2f2073b93ae68eda73e4093d73 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Wed, 14 Aug 2019 14:25:59 +0530
Subject: [PATCH 247/484] fix(quality-inspection): fetch all items for
inspection type in process (#18716)
* fix(quality-inspection): fetch all items for inspection type in process
* fix(quality-inspection): add server side validation for in process items
---
.../quality_inspection/quality_inspection.js | 7 ++++---
.../quality_inspection/quality_inspection.py | 16 ++++++++++++++--
2 files changed, 18 insertions(+), 5 deletions(-)
diff --git a/erpnext/stock/doctype/quality_inspection/quality_inspection.js b/erpnext/stock/doctype/quality_inspection/quality_inspection.js
index aa9854aee1..22f29e05b4 100644
--- a/erpnext/stock/doctype/quality_inspection/quality_inspection.js
+++ b/erpnext/stock/doctype/quality_inspection/quality_inspection.js
@@ -39,11 +39,12 @@ cur_frm.fields_dict['item_code'].get_query = function(doc, cdt, cdn) {
query: "erpnext.stock.doctype.quality_inspection.quality_inspection.item_query",
filters: {
"from": doctype,
- "parent": doc.reference_name
+ "parent": doc.reference_name,
+ "inspection_type": doc.inspection_type
}
- }
+ };
}
-}
+},
// Serial No based on item_code
cur_frm.fields_dict['item_serial_no'].get_query = function(doc, cdt, cdn) {
diff --git a/erpnext/stock/doctype/quality_inspection/quality_inspection.py b/erpnext/stock/doctype/quality_inspection/quality_inspection.py
index e0b738202c..4e42e70367 100644
--- a/erpnext/stock/doctype/quality_inspection/quality_inspection.py
+++ b/erpnext/stock/doctype/quality_inspection/quality_inspection.py
@@ -3,6 +3,7 @@
from __future__ import unicode_literals
import frappe
+from frappe import _
from frappe.model.document import Document
from erpnext.stock.doctype.quality_inspection_template.quality_inspection_template \
import get_template_details
@@ -11,6 +12,7 @@ class QualityInspection(Document):
def validate(self):
if not self.readings and self.item_code:
self.get_item_specification_details()
+ self.validate_inspection_type()
def get_item_specification_details(self):
if not self.quality_inspection_template:
@@ -27,6 +29,14 @@ class QualityInspection(Document):
child.value = d.value
child.status = "Accepted"
+ def validate_inspection_type(self):
+ if self.inspection_type != "In Process":
+ inspection_required = frappe.db.get_value("Item", filters={
+ 'name': self.item_code
+ }, fieldname=['inspection_required_before_purchase', 'inspection_required_before_delivery'])
+ if 0 in inspection_required:
+ frappe.throw(_('Inspection type for the item can only be in process.'))
+
def get_quality_inspection_template(self):
template = ''
if self.bom_no:
@@ -63,10 +73,12 @@ def item_query(doctype, txt, searchfield, start, page_len, filters):
mcond = get_match_cond(filters["from"])
cond, qi_condition = "", "and (quality_inspection is null or quality_inspection = '')"
- if filters.get('from') in ['Purchase Invoice Item', 'Purchase Receipt Item']:
+ if filters.get('from') in ['Purchase Invoice Item', 'Purchase Receipt Item']\
+ and filters.get("inspection_type") != "In Process":
cond = """and item_code in (select name from `tabItem` where
inspection_required_before_purchase = 1)"""
- elif filters.get('from') in ['Sales Invoice Item', 'Delivery Note Item']:
+ elif filters.get('from') in ['Sales Invoice Item', 'Delivery Note Item']\
+ and filters.get("inspection_type") != "In Process":
cond = """and item_code in (select name from `tabItem` where
inspection_required_before_delivery = 1)"""
elif filters.get('from') == 'Stock Entry Detail':
From 2c5dcbe819fd87aa8a54eb5da945ae1f17fc8d20 Mon Sep 17 00:00:00 2001
From: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com>
Date: Wed, 14 Aug 2019 14:26:37 +0530
Subject: [PATCH 248/484] fix: Error handling in payment entry (#18720)
---
erpnext/accounts/doctype/payment_entry/payment_entry.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py
index e0d3e7ada3..8098329530 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.py
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py
@@ -683,8 +683,8 @@ def get_orders_to_be_billed(posting_date, party_type, party,
order_list = []
for d in orders:
- if not (d.outstanding_amount >= filters.get("outstanding_amt_greater_than")
- and d.outstanding_amount <= filters.get("outstanding_amt_less_than")):
+ if not (flt(d.outstanding_amount) >= flt(filters.get("outstanding_amt_greater_than"))
+ and flt(d.outstanding_amount) <= flt(filters.get("outstanding_amt_less_than"))):
continue
d["voucher_type"] = voucher_type
From 760b078dc99817b1ebb447ce0b5db4e74e11ba26 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Wed, 14 Aug 2019 14:40:00 +0530
Subject: [PATCH 249/484] fix(payroll-entry): commit submitted salary slip
check on change (#18694)
* fix(payroll-entry): commit submitted salary slip check onchange
* fix: track submitted ss via flags
---
erpnext/hr/doctype/payroll_entry/payroll_entry.js | 2 +-
erpnext/hr/doctype/payroll_entry/payroll_entry.py | 6 ++----
2 files changed, 3 insertions(+), 5 deletions(-)
diff --git a/erpnext/hr/doctype/payroll_entry/payroll_entry.js b/erpnext/hr/doctype/payroll_entry/payroll_entry.js
index e4ab68068c..adc06712ef 100644
--- a/erpnext/hr/doctype/payroll_entry/payroll_entry.js
+++ b/erpnext/hr/doctype/payroll_entry/payroll_entry.js
@@ -69,7 +69,7 @@ frappe.ui.form.on('Payroll Entry', {
},
add_context_buttons: function(frm) {
- if(frm.doc.salary_slips_submitted) {
+ if(frm.doc.salary_slips_submitted || (frm.doc.__onload && frm.doc.__onload.submitted_ss)) {
frm.events.add_bank_entry_button(frm);
} else if(frm.doc.salary_slips_created) {
frm.add_custom_button(__("Submit Salary Slip"), function() {
diff --git a/erpnext/hr/doctype/payroll_entry/payroll_entry.py b/erpnext/hr/doctype/payroll_entry/payroll_entry.py
index 8803a9a84e..9b988e0412 100644
--- a/erpnext/hr/doctype/payroll_entry/payroll_entry.py
+++ b/erpnext/hr/doctype/payroll_entry/payroll_entry.py
@@ -18,9 +18,8 @@ class PayrollEntry(Document):
# check if salary slips were manually submitted
entries = frappe.db.count("Salary Slip", {'payroll_entry': self.name, 'docstatus': 1}, ['name'])
- if cint(entries) == len(self.employees) and not self.salary_slips_submitted:
- self.db_set("salary_slips_submitted", 1)
- self.reload()
+ if cint(entries) == len(self.employees):
+ self.set_onload("submitted_ss", True)
def on_submit(self):
self.create_salary_slips()
@@ -429,7 +428,6 @@ def get_start_end_dates(payroll_frequency, start_date=None, company=None):
'start_date': start_date, 'end_date': end_date
})
-
def get_frequency_kwargs(frequency_name):
frequency_dict = {
'monthly': {'months': 1},
From 78690d7b8b91dd825fe80593e54dea1e7172bc4b Mon Sep 17 00:00:00 2001
From: Anurag Mishra <32095923+Anurag810@users.noreply.github.com>
Date: Wed, 14 Aug 2019 15:03:58 +0530
Subject: [PATCH 250/484] fix:payment ammount validation for pos invoices
(#18663)
---
.../accounts/doctype/sales_invoice/sales_invoice.py | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index 874230052a..4f80b78c88 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -78,6 +78,7 @@ class SalesInvoice(SellingController):
self.so_dn_required()
self.validate_proj_cust()
+ self.validate_pos_return()
self.validate_with_previous_doc()
self.validate_uom_is_integer("stock_uom", "stock_qty")
self.validate_uom_is_integer("uom", "qty")
@@ -199,6 +200,16 @@ class SalesInvoice(SellingController):
if "Healthcare" in active_domains:
manage_invoice_submit_cancel(self, "on_submit")
+ def validate_pos_return(self):
+
+ if self.is_pos and self.is_return:
+ total_amount_in_payments = 0
+ for payment in self.payments:
+ total_amount_in_payments += payment.amount
+
+ if total_amount_in_payments < self.rounded_total:
+ frappe.throw(_("Total payments amount can't be greater than {}".format(-self.rounded_total)))
+
def validate_pos_paid_amount(self):
if len(self.payments) == 0 and self.is_pos:
frappe.throw(_("At least one mode of payment is required for POS invoice."))
From 107b2768fd1a585f1ca83d1aad202751c426f3ca Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Wed, 14 Aug 2019 16:09:16 +0530
Subject: [PATCH 251/484] refactor: replace raw sql with orm
---
erpnext/hr/doctype/leave_type/leave_type.py | 9 ++++++++-
erpnext/hr/utils.py | 1 -
2 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/erpnext/hr/doctype/leave_type/leave_type.py b/erpnext/hr/doctype/leave_type/leave_type.py
index 3a19fa98e6..598bff2f13 100644
--- a/erpnext/hr/doctype/leave_type/leave_type.py
+++ b/erpnext/hr/doctype/leave_type/leave_type.py
@@ -5,6 +5,7 @@ from __future__ import unicode_literals
import calendar
import frappe
from datetime import datetime
+from frappe.utils import today
from frappe import _
from frappe.model.document import Document
@@ -12,6 +13,12 @@ from frappe.model.document import Document
class LeaveType(Document):
def validate(self):
if self.is_lwp:
- leave_allocation = frappe.db.sql_list("""select name from `tabLeave Allocation` where leave_type=%s""", (self.name))
+ leave_allocation = frappe.get_all("Leave Allocation", filters={
+ 'leave_type': self.name,
+ 'from_date': ("<=", today()),
+ 'to_date': (">=", today())
+ }, ['name'])
+ leave_allocation = [l['name'] for l in leave_allocation]
+ frappe.db("""select name from `tabLeave Allocation` where leave_type=%s""", (self.name))
if leave_allocation:
frappe.throw(_('Leave application is linked with leave allocations {0}. Leave application cannot be set as leave without pay').format(", ".join(leave_allocation))) #nosec
\ No newline at end of file
diff --git a/erpnext/hr/utils.py b/erpnext/hr/utils.py
index 2183c5e678..1464a77936 100644
--- a/erpnext/hr/utils.py
+++ b/erpnext/hr/utils.py
@@ -323,7 +323,6 @@ def allocate_earned_leaves():
allocation.db_set("total_leaves_allocated", new_allocation, update_modified=False)
create_earned_leave_ledger_entry(allocation, earned_leaves, today)
-
def create_earned_leave_ledger_entry(allocation, earned_leaves, date):
''' Create leave ledger entry based on the earned leave frequency '''
allocation.new_leaves_allocated = earned_leaves
From ca55af836b99c2763c6269d33ecb5bde2fc68554 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Wed, 14 Aug 2019 16:32:02 +0530
Subject: [PATCH 252/484] fix: travis
---
.../doctype/quality_inspection/quality_inspection.py | 10 ----------
1 file changed, 10 deletions(-)
diff --git a/erpnext/stock/doctype/quality_inspection/quality_inspection.py b/erpnext/stock/doctype/quality_inspection/quality_inspection.py
index 4e42e70367..738c63ca35 100644
--- a/erpnext/stock/doctype/quality_inspection/quality_inspection.py
+++ b/erpnext/stock/doctype/quality_inspection/quality_inspection.py
@@ -3,7 +3,6 @@
from __future__ import unicode_literals
import frappe
-from frappe import _
from frappe.model.document import Document
from erpnext.stock.doctype.quality_inspection_template.quality_inspection_template \
import get_template_details
@@ -12,7 +11,6 @@ class QualityInspection(Document):
def validate(self):
if not self.readings and self.item_code:
self.get_item_specification_details()
- self.validate_inspection_type()
def get_item_specification_details(self):
if not self.quality_inspection_template:
@@ -29,14 +27,6 @@ class QualityInspection(Document):
child.value = d.value
child.status = "Accepted"
- def validate_inspection_type(self):
- if self.inspection_type != "In Process":
- inspection_required = frappe.db.get_value("Item", filters={
- 'name': self.item_code
- }, fieldname=['inspection_required_before_purchase', 'inspection_required_before_delivery'])
- if 0 in inspection_required:
- frappe.throw(_('Inspection type for the item can only be in process.'))
-
def get_quality_inspection_template(self):
template = ''
if self.bom_no:
From ae2a0fb4c7ae3704e8f37fa3820cd9511fb05bf5 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Wed, 14 Aug 2019 16:50:31 +0530
Subject: [PATCH 253/484] chore: remove unused code
---
erpnext/hr/doctype/leave_type/leave_type.py | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/erpnext/hr/doctype/leave_type/leave_type.py b/erpnext/hr/doctype/leave_type/leave_type.py
index 598bff2f13..c0d1296841 100644
--- a/erpnext/hr/doctype/leave_type/leave_type.py
+++ b/erpnext/hr/doctype/leave_type/leave_type.py
@@ -17,8 +17,7 @@ class LeaveType(Document):
'leave_type': self.name,
'from_date': ("<=", today()),
'to_date': (">=", today())
- }, ['name'])
+ }, fields=['name'])
leave_allocation = [l['name'] for l in leave_allocation]
- frappe.db("""select name from `tabLeave Allocation` where leave_type=%s""", (self.name))
if leave_allocation:
- frappe.throw(_('Leave application is linked with leave allocations {0}. Leave application cannot be set as leave without pay').format(", ".join(leave_allocation))) #nosec
\ No newline at end of file
+ frappe.throw(_('Leave application is linked with leave allocations {0}. Leave application cannot be set as leave without pay').format(", ".join(leave_allocation))) #nosec
From dbb44c8950c468a3681f6cda46b7be3a67a86245 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Wed, 14 Aug 2019 17:38:44 +0530
Subject: [PATCH 254/484] fix: restrict the payment order to non received type
payment entries
---
erpnext/accounts/doctype/payment_order/payment_order.js | 1 +
1 file changed, 1 insertion(+)
diff --git a/erpnext/accounts/doctype/payment_order/payment_order.js b/erpnext/accounts/doctype/payment_order/payment_order.js
index f2f00cebcb..ce9cfe527c 100644
--- a/erpnext/accounts/doctype/payment_order/payment_order.js
+++ b/erpnext/accounts/doctype/payment_order/payment_order.js
@@ -66,6 +66,7 @@ frappe.ui.form.on('Payment Order', {
get_query_filters: {
bank: frm.doc.bank,
docstatus: 1,
+ payment_type: ("!=", "Receive"),
bank_account: frm.doc.company_bank_account,
paid_from: frm.doc.account,
payment_order_status: ["=", "Initiated"],
From c5d41af10fd32d1df79efee66b2d1a307304458a Mon Sep 17 00:00:00 2001
From: Rohit Waghchaure
Date: Wed, 14 Aug 2019 18:49:19 +0530
Subject: [PATCH 255/484] fix: sequence of customer name and contact in the AR
report
---
.../report/accounts_receivable/accounts_receivable.py | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
index ecf149b335..97e710450c 100755
--- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
+++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
@@ -33,6 +33,9 @@ class ReceivablePayableReport(object):
columns += [_(args.get("party_type")) + ":Link/" + args.get("party_type") + ":200"]
+ if party_naming_by == "Naming Series":
+ columns += [args.get("party_type") + " Name::110"]
+
if args.get("party_type") == 'Customer':
columns.append({
"label": _("Customer Contact"),
@@ -42,9 +45,6 @@ class ReceivablePayableReport(object):
"width": 100
})
- if party_naming_by == "Naming Series":
- columns += [args.get("party_type") + " Name::110"]
-
columns.append({
"label": _("Voucher Type"),
"fieldtype": "Data",
From 2fb6bc986781d7819afd860cb046a6f060baaaf0 Mon Sep 17 00:00:00 2001
From: deepeshgarg007
Date: Thu, 15 Aug 2019 17:06:32 +0530
Subject: [PATCH 256/484] fix: Default dimensions in child doctypes
---
.../accounting_dimension.js | 7 ----
.../accounting_dimension_detail.json | 8 ++---
.../public/js/utils/dimension_tree_filter.js | 36 ++++++++++++++-----
3 files changed, 30 insertions(+), 21 deletions(-)
diff --git a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.js b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.js
index 88b11dd678..5cea0d15bf 100644
--- a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.js
+++ b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.js
@@ -40,16 +40,9 @@ frappe.ui.form.on('Accounting Dimension', {
},
document_type: function(frm) {
-
frm.set_value('label', frm.doc.document_type);
frm.set_value('fieldname', frappe.model.scrub(frm.doc.document_type));
- if (frm.is_new()){
- let row = frappe.model.add_child(frm.doc, "Accounting Dimension Detail", "dimension_defaults");
- row.reference_document = frm.doc.document_type;
- frm.refresh_fields("dimension_defaults");
- }
-
frappe.db.get_value('Accounting Dimension', {'document_type': frm.doc.document_type}, 'document_type', (r) => {
if (r && r.document_type) {
frm.set_df_property('document_type', 'description', "Document type is already set as dimension");
diff --git a/erpnext/accounts/doctype/accounting_dimension_detail/accounting_dimension_detail.json b/erpnext/accounts/doctype/accounting_dimension_detail/accounting_dimension_detail.json
index 1ccef6cc7a..e9e1f43f99 100644
--- a/erpnext/accounts/doctype/accounting_dimension_detail/accounting_dimension_detail.json
+++ b/erpnext/accounts/doctype/accounting_dimension_detail/accounting_dimension_detail.json
@@ -17,8 +17,7 @@
"fieldtype": "Link",
"in_list_view": 1,
"label": "Company",
- "options": "Company",
- "reqd": 1
+ "options": "Company"
},
{
"fieldname": "reference_document",
@@ -34,8 +33,7 @@
"fieldtype": "Dynamic Link",
"in_list_view": 1,
"label": "Default Dimension",
- "options": "reference_document",
- "reqd": 1
+ "options": "reference_document"
},
{
"columns": 3,
@@ -55,7 +53,7 @@
}
],
"istable": 1,
- "modified": "2019-07-17 23:34:33.026883",
+ "modified": "2019-08-15 11:59:09.389891",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Accounting Dimension Detail",
diff --git a/erpnext/public/js/utils/dimension_tree_filter.js b/erpnext/public/js/utils/dimension_tree_filter.js
index f1c92091a8..72a05b4221 100644
--- a/erpnext/public/js/utils/dimension_tree_filter.js
+++ b/erpnext/public/js/utils/dimension_tree_filter.js
@@ -1,12 +1,13 @@
frappe.provide('frappe.ui.form');
erpnext.doctypes_with_dimensions = ["GL Entry", "Sales Invoice", "Purchase Invoice", "Payment Entry", "Asset",
- "Expense Claim", "Stock Entry", "Budget", "Payroll Entry", "Delivery Note", "Sales Invoice Item", "Purchase Invoice Item",
- "Purchase Order Item", "Journal Entry Account", "Material Request Item", "Delivery Note Item", "Purchase Receipt Item",
- "Stock Entry Detail", "Payment Entry Deduction", "Sales Taxes and Charges", "Purchase Taxes and Charges", "Shipping Rule",
- "Landed Cost Item", "Asset Value Adjustment", "Loyalty Program", "Fee Schedule", "Fee Structure", "Stock Reconciliation",
- "Travel Request", "Fees", "POS Profile", "Opening Invoice Creation Tool", "Opening Invoice Creation Tool Item", "Subscription",
- "Subscription Plan"];
+ "Expense Claim", "Stock Entry", "Budget", "Payroll Entry", "Delivery Note", "Shipping Rule", "Loyalty Program",
+ "Fee Schedule", "Fee Structure", "Stock Reconciliation", "Travel Request", "Fees", "POS Profile", "Opening Invoice Creation Tool",
+ "Subscription", "Purchase Order", "Journal Entry", "Material Request", "Purchase Receipt", "Landed Cost Item", "Asset"]
+
+erpnext.child_docs = ["Sales Invoice Item", "Purchase Invoice Item", "Purchase Order Item", "Journal Entry Account",
+ "Material Request Item", "Delivery Note Item", "Purchase Receipt Item", "Stock Entry Detail", "Payment Entry Deduction",
+ "Landed Cost Item", "Asset Value Adjustment", "Opening Invoice Creation Tool Item", "Subscription Plan"]
frappe.call({
method: "erpnext.accounts.doctype.accounting_dimension.accounting_dimension.get_dimension_filters",
@@ -26,8 +27,19 @@ erpnext.doctypes_with_dimensions.forEach((doctype) => {
"is_group": 0
});
}
- if (frm.is_new() && frappe.meta.has_field(doctype, 'company') && frm.doc.company) {
- frm.set_value(dimension['fieldname'], erpnext.default_dimensions[frm.doc.company][dimension['document_type']]);
+
+ if (frappe.meta.has_field(doctype, dimension['fieldname'])) {
+ if (frm.is_new() && frappe.meta.has_field(doctype, 'company') && frm.doc.company) {
+ frm.set_value(dimension['fieldname'], erpnext.default_dimensions[frm.doc.company][dimension['document_type']]);
+ }
+ }
+
+ if (frm.doc.items && frm.doc.items.length) {
+ frm.doc.items[0][dimension['fieldname']] = erpnext.default_dimensions[frm.doc.company][dimension['document_type']];
+ }
+
+ if (frm.doc.accounts && frm.doc.accounts.length) {
+ frm.doc.accounts[0][dimension['fieldname']] = erpnext.default_dimensions[frm.doc.company][dimension['document_type']];
}
});
});
@@ -36,11 +48,17 @@ erpnext.doctypes_with_dimensions.forEach((doctype) => {
company: function(frm) {
if(frm.doc.company) {
erpnext.dimension_filters.forEach((dimension) => {
- frm.set_value(dimension['fieldname'], erpnext.default_dimensions[frm.doc.company][dimension['document_type']]);
+ if (frappe.meta.has_field(doctype, dimension['fieldname'])) {
+ frm.set_value(dimension['fieldname'], erpnext.default_dimensions[frm.doc.company][dimension['document_type']]);
+ }
});
}
},
+ });
+});
+erpnext.child_docs.forEach((doctype) => {
+ frappe.ui.form.on(doctype, {
items_add: function(frm, cdt, cdn) {
erpnext.dimension_filters.forEach((dimension) => {
var row = frappe.get_doc(cdt, cdn);
From 182f4def0098664bf0aca82cad178da09606a890 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Fri, 16 Aug 2019 08:16:22 +0530
Subject: [PATCH 257/484] fix: Delivery note creation from pick list
- Changes in serial no and batch no seletion
- Changes in warehouse overrwite logic
Co-authored-by: Nabin Hait
---
erpnext/controllers/accounts_controller.py | 2 +-
.../doctype/sales_order/sales_order.py | 45 +--
.../stock/doctype/pick_list/pick_list.json | 10 +-
erpnext/stock/doctype/pick_list/pick_list.py | 266 ++++++++++++------
.../pick_list_item/pick_list_item.json | 152 +++++-----
.../pick_list_reference_item.json | 88 ++++--
erpnext/stock/get_item_details.py | 37 ++-
7 files changed, 401 insertions(+), 199 deletions(-)
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index 14bf9d57a1..f6d4eee518 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -263,7 +263,7 @@ class AccountsController(TransactionBase):
if self.get("is_subcontracted"):
args["is_subcontracted"] = self.is_subcontracted
- ret = get_item_details(args, self)
+ ret = get_item_details(args, self, overwrite_warehouse=False)
for fieldname, value in ret.items():
if item.meta.get_field(fieldname) and value is not None:
diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py
index b79a2925e0..2dc3788568 100755
--- a/erpnext/selling/doctype/sales_order/sales_order.py
+++ b/erpnext/selling/doctype/sales_order/sales_order.py
@@ -568,7 +568,7 @@ def make_project(source_name, target_doc=None):
return doc
@frappe.whitelist()
-def make_delivery_note(source_name, target_doc=None):
+def make_delivery_note(source_name, target_doc=None, skip_item_mapping=False):
def set_missing_values(source, target):
target.ignore_pricing_rule = 1
target.run_method("set_missing_values")
@@ -593,23 +593,13 @@ def make_delivery_note(source_name, target_doc=None):
or item.get("buying_cost_center") \
or item_group.get("buying_cost_center")
- target_doc = get_mapped_doc("Sales Order", source_name, {
+ mapper = {
"Sales Order": {
"doctype": "Delivery Note",
"validation": {
"docstatus": ["=", 1]
}
},
- "Sales Order Item": {
- "doctype": "Delivery Note Item",
- "field_map": {
- "rate": "rate",
- "name": "so_detail",
- "parent": "against_sales_order",
- },
- "postprocess": update_item,
- "condition": lambda doc: abs(doc.delivered_qty) < abs(doc.qty) and doc.delivered_by_supplier!=1
- },
"Sales Taxes and Charges": {
"doctype": "Sales Taxes and Charges",
"add_if_empty": True
@@ -618,7 +608,21 @@ def make_delivery_note(source_name, target_doc=None):
"doctype": "Sales Team",
"add_if_empty": True
}
- }, target_doc, set_missing_values)
+ }
+
+ if not skip_item_mapping:
+ mapper["Sales Order Item"] = {
+ "doctype": "Delivery Note Item",
+ "field_map": {
+ "rate": "rate",
+ "name": "so_detail",
+ "parent": "against_sales_order",
+ },
+ "postprocess": update_item,
+ "condition": lambda doc: abs(doc.delivered_qty) < abs(doc.qty) and doc.delivered_by_supplier!=1
+ }
+
+ target_doc = get_mapped_doc("Sales Order", source_name, mapper, target_doc, set_missing_values)
return target_doc
@@ -999,9 +1003,16 @@ def make_inter_company_purchase_order(source_name, target_doc=None):
@frappe.whitelist()
def make_pick_list(source_name, target_doc=None):
+ def update_item_quantity(source, target, source_parent):
+ target.qty = flt(source.qty) - flt(source.delivered_qty)
+ target.stock_qty = (flt(source.qty) - flt(source.delivered_qty)) * flt(source.conversion_factor)
+
doc = get_mapped_doc("Sales Order", source_name, {
"Sales Order": {
"doctype": "Pick List",
+ "field_map": {
+ "doctype": "items_based_on"
+ },
"validation": {
"docstatus": ["=", 1]
}
@@ -1009,11 +1020,11 @@ def make_pick_list(source_name, target_doc=None):
"Sales Order Item": {
"doctype": "Pick List Reference Item",
"field_map": {
- "item_code": "item",
- "parenttype": "reference_doctype",
- "parent": "reference_name",
- "name": "reference_document_item"
+ "parent": "sales_order",
+ "name": "sales_order_item"
},
+ "postprocess": update_item_quantity,
+ "conditions": lambda doc: abs(doc.delivered_qty) < abs(doc.qty) and doc.delivered_by_supplier!=1
},
}, target_doc)
diff --git a/erpnext/stock/doctype/pick_list/pick_list.json b/erpnext/stock/doctype/pick_list/pick_list.json
index 3f96630faf..c7a5fc8c75 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.json
+++ b/erpnext/stock/doctype/pick_list/pick_list.json
@@ -7,6 +7,7 @@
"field_order": [
"company",
"column_break_4",
+ "items_based_on",
"parent_warehouse",
"section_break_4",
"reference_items",
@@ -50,9 +51,16 @@
"fieldtype": "Table",
"label": "Items To Be Picked",
"options": "Pick List Reference Item"
+ },
+ {
+ "default": "Sales Order",
+ "fieldname": "items_based_on",
+ "fieldtype": "Select",
+ "label": "Items Based On",
+ "options": "\nSales Order\nWork Order"
}
],
- "modified": "2019-08-01 10:50:17.055509",
+ "modified": "2019-08-13 19:30:01.151720",
"modified_by": "Administrator",
"module": "Stock",
"name": "Pick List",
diff --git a/erpnext/stock/doctype/pick_list/pick_list.py b/erpnext/stock/doctype/pick_list/pick_list.py
index 77dacd5144..20b4230002 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.py
+++ b/erpnext/stock/doctype/pick_list/pick_list.py
@@ -5,7 +5,10 @@
from __future__ import unicode_literals
import frappe
from frappe.model.document import Document
-from frappe.model.mapper import get_mapped_doc
+from six import iteritems
+from frappe.model.mapper import get_mapped_doc, map_child_doc
+from frappe.utils import floor, flt, today
+from erpnext.selling.doctype.sales_order.sales_order import make_delivery_note as make_delivery_note_from_sales_order
class PickList(Document):
def set_item_locations(self):
@@ -17,46 +20,56 @@ class PickList(Document):
# Reset
self.delete_key('item_locations')
- for item in reference_items:
- data = get_items_with_warehouse_and_quantity(item, from_warehouses)
- for item_info in data:
- print(self.append('item_locations', item_info))
+ for item_doc in reference_items:
+ if frappe.get_cached_value('Item', item_doc.item_code, 'has_serial_no'):
+ item_locations = get_item_locations_based_on_serial_nos(item_doc)
+ elif frappe.get_cached_value('Item', item_doc.item_code, 'has_batch_no'):
+ item_locations = get_item_locations_based_on_batch_nos(item_doc)
+ else:
+ item_locations = get_items_with_warehouse_and_quantity(item_doc, from_warehouses)
- for item_doc in self.get('item_locations'):
- if frappe.get_cached_value('Item', item_doc.item, 'has_serial_no'):
- set_serial_nos(item_doc)
- elif frappe.get_cached_value('Item', item_doc.item, 'has_batch_no'):
- set_batch_no(item_doc, self)
+ for row in item_locations:
+ row.update({
+ 'item_code': item_doc.item_code,
+ 'sales_order': item_doc.sales_order,
+ 'sales_order_item': item_doc.sales_order_item,
+ 'uom': item_doc.uom,
+ 'stock_uom': item_doc.stock_uom,
+ 'conversion_factor': item_doc.conversion_factor,
+ 'stock_qty': row.get("qty", 0) * item_doc.conversion_factor,
+ 'picked_qty': row.get("qty", 0) * item_doc.conversion_factor
+ })
+ self.append('item_locations', row)
def get_items_with_warehouse_and_quantity(item_doc, from_warehouses):
- items = []
- item_locations = get_available_items(item_doc.item, from_warehouses)
- remaining_qty = item_doc.qty
+ item_locations = []
+ item_location_map = get_available_items(item_doc.item_code, from_warehouses)
+ remaining_stock_qty = item_doc.stock_qty
+ while remaining_stock_qty > 0 and item_location_map:
+ item_location = item_location_map.pop(0)
+ stock_qty = remaining_stock_qty if item_location.qty >= remaining_stock_qty else item_location.qty
+ qty = stock_qty / (item_doc.conversion_factor or 1)
- while remaining_qty > 0 and item_locations:
- item_location = item_locations.pop(0)
- qty = remaining_qty if item_location.qty >= remaining_qty else item_location.qty
- items.append({
- 'item': item_doc.item,
+ uom_must_be_whole_number = frappe.db.get_value("UOM", item_doc.uom, "must_be_whole_number")
+ if uom_must_be_whole_number:
+ qty = floor(qty)
+ stock_qty = qty * item_doc.conversion_factor
+
+ item_locations.append({
'qty': qty,
- 'warehouse': item_location.warehouse,
- 'reference_doctype': item_doc.reference_doctype,
- 'reference_name': item_doc.reference_name,
- 'reference_document_item': item_doc.reference_document_item,
+ 'warehouse': item_location.warehouse
})
- remaining_qty -= qty
+ remaining_stock_qty -= stock_qty
- if remaining_qty:
- frappe.msgprint('{} qty of {} is out of stock. Skipping...'.format(remaining_qty, item_doc.item))
- return items
+ if remaining_stock_qty:
+ frappe.msgprint('{0} {1} of {2} is not available.'
+ .format(remaining_stock_qty / item_doc.conversion_factor, item_doc.uom, item_doc.item_code))
+ return item_locations
- return items
-
-def get_available_items(item, from_warehouses):
+def get_available_items(item_code, from_warehouses):
# gets all items available in different warehouses
- # FIFO
filters = frappe._dict({
- 'item_code': item,
+ 'item_code': item_code,
'actual_qty': ['>', 0]
})
if from_warehouses:
@@ -71,79 +84,170 @@ def get_available_items(item, from_warehouses):
def set_serial_nos(item_doc):
serial_nos = frappe.get_all('Serial No', {
- 'item_code': item_doc.item,
+ 'item_code': item_doc.item_code,
'warehouse': item_doc.warehouse
- }, limit=item_doc.qty, order_by='purchase_date')
+ }, limit=item_doc.stock_qty, order_by='purchase_date')
item_doc.set('serial_no', '\n'.join([serial_no.name for serial_no in serial_nos]))
- # should we assume that all serialized item available in stock will have serial no?
+ # should we assume that all serialized item_code available in stock will have serial no?
-def set_batch_no(item_doc, parent_doc):
- batches = frappe.db.sql("""
+def get_item_locations_based_on_serial_nos(item_doc):
+ serial_nos = frappe.get_all('Serial No',
+ fields = ['name', 'warehouse'],
+ filters = {
+ 'item_code': item_doc.item_code,
+ 'warehouse': ['!=', '']
+ }, limit=item_doc.stock_qty, order_by='purchase_date', as_list=1)
+
+ remaining_stock_qty = flt(item_doc.stock_qty) - len(serial_nos)
+ if remaining_stock_qty:
+ frappe.msgprint('{0} {1} of {2} is not available.'
+ .format(remaining_stock_qty, item_doc.stock_uom, item_doc.item_code))
+
+ warehouse_serial_nos_map = frappe._dict()
+ for serial_no, warehouse in serial_nos:
+ warehouse_serial_nos_map.setdefault(warehouse, []).append(serial_no)
+
+ item_locations = []
+ for warehouse, serial_nos in iteritems(warehouse_serial_nos_map):
+ item_locations.append({
+ 'qty': len(serial_nos),
+ 'warehouse': warehouse,
+ 'serial_no': '\n'.join(serial_nos)
+ })
+
+ return item_locations
+
+def get_item_locations_based_on_batch_nos(item_doc):
+ batch_qty = frappe.db.sql("""
SELECT
- `batch_no`,
- SUM(`actual_qty`) AS `qty`
+ sle.`warehouse`,
+ sle.`batch_no`,
+ SUM(sle.`actual_qty`) AS `qty`
FROM
- `tabStock Ledger Entry`
+ `tabStock Ledger Entry` sle, `tabBatch` batch
WHERE
- `item_code`=%(item_code)s
- AND `warehouse`=%(warehouse)s
+ sle.batch_no = batch.name
+ and sle.`item_code`=%(item_code)s
+ and IFNULL(batch.expiry_date, '2200-01-01') > %(today)s
GROUP BY
`warehouse`,
`batch_no`,
`item_code`
HAVING `qty` > 0
+ ORDER BY IFNULL(batch.expiry_date, '2200-01-01')
""", {
- 'item_code': item_doc.item,
- 'warehouse': item_doc.warehouse,
+ 'item_code': item_doc.item_code,
+ 'today': today()
}, as_dict=1)
+ item_locations = []
required_qty = item_doc.qty
- while required_qty > 0 and batches:
- batch = batches.pop()
- batch_expiry = frappe.get_value('Batch', batch.batch_no, 'expiry_date')
- if batch_expiry and batch_expiry <= frappe.utils.getdate():
- frappe.msgprint('Skipping expired Batch {}'.format(batch.batch_no))
- continue
- item_doc.batch_no = batch.batch_no
- if batch.qty >= item_doc.qty:
- required_qty = 0
- break
+ for d in batch_qty:
+ if d.qty > required_qty:
+ d.qty = required_qty
else:
- # split item if quantity of item in batch is less that required
- # Look for another batch
+ required_qty -= d.qty
+
+ item_locations.append(d)
+
+ if required_qty <= 0:
+ break
+
+ # required_qty = item_doc.qty
+ # while required_qty > 0 and batches:
+ # batch = batches.pop()
+ # batch_expiry = frappe.get_value('Batch', batch.batch_no, 'expiry_date')
+ # if batch_expiry and batch_expiry <= frappe.utils.getdate():
+ # frappe.msgprint('Skipping expired Batch {}'.format(batch.batch_no))
+ # continue
+ # item_doc.batch_no = batch.batch_no
+ # if batch.qty >= item_doc.qty:
+ # required_qty = 0
+ # break
+ # else:
+ # # split item_code if quantity of item_code in batch is less that required
+ # # Look for another batch
+
+ # required_qty -= batch.qty
+ # # set quantity of current item_code equal to batch quantity
+ # item_doc.set('qty', batch.qty)
+ # item_doc = parent_doc.append('items', {
+ # 'item_code': item_doc.item_code,
+ # 'qty': required_qty,
+ # 'warehouse': item_doc.warehouse,
+ # 'sales_order': item_doc.sales_order,
+ # 'sales_order_item': item_doc.sales_order_item,
+ # 'uom': item_doc.uom,
+ # 'stock_uom': item_doc.stock_uom,
+ # 'conversion_factor': item_doc.conversion_factor,
+ # 'stock_qty': qty * item_doc.conversion_factor,
+ # })
- required_qty -= batch.qty
- # set quantity of current item equal to batch quantity
- item_doc.set('qty', batch.qty)
- item_doc = parent_doc.append('items', {
- 'item': item_doc.item,
- 'qty': required_qty,
- 'warehouse': item_doc.warehouse,
- 'reference_doctype': item_doc.reference_doctype,
- 'reference_name': item_doc.reference_name,
- 'reference_document_item': item_doc.reference_document_item,
- })
if required_qty:
- frappe.msgprint('No batches found for {} qty of {}. Skipping...'.format(required_qty, item_doc.item))
- parent_doc.remove(item_doc)
+ frappe.msgprint('No batches found for {} qty of {}.'.format(required_qty, item_doc.item_code))
+
+ return item_locations
@frappe.whitelist()
def make_delivery_note(source_name, target_doc=None):
- target_doc = get_mapped_doc("Pick List", source_name, {
- "Pick List": {
- "doctype": "Delivery Note",
- # "validation": {
- # "docstatus": ["=", 1]
- # }
- },
- "Pick List Item": {
+ pick_list = frappe.get_doc('Pick List', source_name)
+ sales_orders = [d.sales_order for d in pick_list.item_locations]
+ sales_orders = set(sales_orders)
+
+ delivery_note = None
+ for sales_order in sales_orders:
+ delivery_note = make_delivery_note_from_sales_order(sales_order,
+ delivery_note, skip_item_mapping=True)
+
+ for location in pick_list.item_locations:
+ sales_order_item = frappe.get_cached_doc('Sales Order Item', location.sales_order_item)
+ item_table_mapper = {
"doctype": "Delivery Note Item",
"field_map": {
- "item": "item_code",
- "reference_docname": "against_sales_order",
+ "rate": "rate",
+ "name": "so_detail",
+ "parent": "against_sales_order",
},
- },
- }, target_doc)
+ "condition": lambda doc: abs(doc.delivered_qty) < abs(doc.qty) and doc.delivered_by_supplier!=1
+ }
- return target_doc
\ No newline at end of file
+ dn_item = map_child_doc(sales_order_item, delivery_note, item_table_mapper)
+
+ if dn_item:
+ dn_item.warehouse = location.warehouse
+ dn_item.qty = location.qty
+
+ update_delivery_note_item(sales_order_item, dn_item, delivery_note)
+
+ set_delivery_note_missing_values(delivery_note)
+
+ return delivery_note
+
+
+def set_delivery_note_missing_values(target):
+ target.run_method("set_missing_values")
+ target.run_method("set_po_nos")
+ target.run_method("calculate_taxes_and_totals")
+
+def update_delivery_note_item(source, target, delivery_note):
+ cost_center = frappe.db.get_value("Project", delivery_note.project, "cost_center")
+ if not cost_center:
+ cost_center = frappe.db.get_value('Item Default',
+ fieldname=['buying_cost_center'],
+ filters={
+ 'parent': source.item_code,
+ 'parenttype': 'Item',
+ 'company': delivery_note.company
+ })
+
+ if not cost_center:
+ cost_center = frappe.db.get_value('Item Default',
+ fieldname=['buying_cost_center'],
+ filters={
+ 'parent': source.item_group,
+ 'parenttype': 'Item Group',
+ 'company': delivery_note.company
+ })
+
+ target.cost_center = cost_center
\ No newline at end of file
diff --git a/erpnext/stock/doctype/pick_list_item/pick_list_item.json b/erpnext/stock/doctype/pick_list_item/pick_list_item.json
index c83b696144..9ee806acf5 100644
--- a/erpnext/stock/doctype/pick_list_item/pick_list_item.json
+++ b/erpnext/stock/doctype/pick_list_item/pick_list_item.json
@@ -4,32 +4,29 @@
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
- "item",
+ "item_code",
"item_name",
"column_break_2",
"description",
- "has_batch_no",
- "has_serial_no",
"section_break_5",
"warehouse",
+ "quantity_section",
"qty",
+ "stock_qty",
"picked_qty",
+ "column_break_11",
+ "uom",
+ "stock_uom",
+ "conversion_factor",
+ "serial_no_and_batch_section",
"serial_no",
+ "column_break_20",
"batch_no",
- "reference_section",
- "reference_doctype",
- "reference_name",
- "reference_document_item"
+ "column_break_15",
+ "sales_order",
+ "sales_order_item"
],
"fields": [
- {
- "fieldname": "item",
- "fieldtype": "Link",
- "in_list_view": 1,
- "label": "Item",
- "options": "Item",
- "read_only": 1
- },
{
"fieldname": "qty",
"fieldtype": "Float",
@@ -52,72 +49,31 @@
"read_only": 1
},
{
- "fetch_from": "item.item_name",
+ "fetch_from": "item_code.item_name",
"fieldname": "item_name",
"fieldtype": "Data",
"label": "Item Name",
"read_only": 1
},
{
- "fetch_from": "item.description",
+ "fetch_from": "item_code.description",
"fieldname": "description",
"fieldtype": "Text",
"label": "Description",
"read_only": 1
},
{
- "fieldname": "reference_document_item",
- "fieldtype": "Data",
- "label": "Reference Document Item",
- "read_only": 1
- },
- {
+ "depends_on": "serial_no",
"fieldname": "serial_no",
"fieldtype": "Small Text",
- "label": "Serial No",
- "read_only": 1
+ "label": "Serial No"
},
{
+ "depends_on": "batch_no",
"fieldname": "batch_no",
"fieldtype": "Link",
"label": "Batch No",
- "options": "Batch",
- "read_only": 1
- },
- {
- "default": "0",
- "fetch_from": "item.has_serial_no",
- "fieldname": "has_serial_no",
- "fieldtype": "Check",
- "label": "Has Serial No",
- "read_only": 1
- },
- {
- "default": "0",
- "fetch_from": "item.has_batch_no",
- "fieldname": "has_batch_no",
- "fieldtype": "Check",
- "label": "Has Batch No",
- "read_only": 1
- },
- {
- "fieldname": "reference_section",
- "fieldtype": "Section Break",
- "label": "Reference"
- },
- {
- "fieldname": "reference_doctype",
- "fieldtype": "Select",
- "label": "Reference Document Type",
- "options": "Sales Order\nWork Order",
- "read_only": 1
- },
- {
- "fieldname": "reference_name",
- "fieldtype": "Dynamic Link",
- "label": "Reference Document",
- "options": "reference_doctype",
- "read_only": 1
+ "options": "Batch"
},
{
"fieldname": "column_break_2",
@@ -126,10 +82,80 @@
{
"fieldname": "section_break_5",
"fieldtype": "Section Break"
+ },
+ {
+ "fieldname": "stock_uom",
+ "fieldtype": "Link",
+ "label": "Stock UOM",
+ "options": "UOM",
+ "read_only": 1
+ },
+ {
+ "fieldname": "column_break_11",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "uom",
+ "fieldtype": "Link",
+ "label": "UOM",
+ "options": "UOM",
+ "read_only": 1
+ },
+ {
+ "fieldname": "conversion_factor",
+ "fieldtype": "Float",
+ "label": "UOM Conversion Factor",
+ "read_only": 1
+ },
+ {
+ "fieldname": "stock_qty",
+ "fieldtype": "Float",
+ "label": "Qty as per Stock UOM",
+ "read_only": 1
+ },
+ {
+ "fieldname": "item_code",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Item",
+ "options": "Item",
+ "read_only": 1
+ },
+ {
+ "fieldname": "quantity_section",
+ "fieldtype": "Section Break",
+ "label": "Quantity"
+ },
+ {
+ "fieldname": "column_break_15",
+ "fieldtype": "Section Break",
+ "label": "Reference"
+ },
+ {
+ "fieldname": "sales_order",
+ "fieldtype": "Link",
+ "label": "Sales Order",
+ "options": "Sales Order",
+ "read_only": 1
+ },
+ {
+ "fieldname": "sales_order_item",
+ "fieldtype": "Data",
+ "label": "Sales Order Item",
+ "read_only": 1
+ },
+ {
+ "fieldname": "serial_no_and_batch_section",
+ "fieldtype": "Section Break",
+ "label": "Serial No and Batch"
+ },
+ {
+ "fieldname": "column_break_20",
+ "fieldtype": "Column Break"
}
],
"istable": 1,
- "modified": "2019-07-30 23:47:53.566473",
+ "modified": "2019-08-14 18:41:37.727388",
"modified_by": "Administrator",
"module": "Stock",
"name": "Pick List Item",
diff --git a/erpnext/stock/doctype/pick_list_reference_item/pick_list_reference_item.json b/erpnext/stock/doctype/pick_list_reference_item/pick_list_reference_item.json
index 23ef2553a2..0aa94feb37 100644
--- a/erpnext/stock/doctype/pick_list_reference_item/pick_list_reference_item.json
+++ b/erpnext/stock/doctype/pick_list_reference_item/pick_list_reference_item.json
@@ -4,32 +4,19 @@
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
- "item",
+ "item_code",
+ "quantity_section",
"qty",
- "reference_doctype",
- "reference_name",
- "reference_document_item"
+ "stock_qty",
+ "column_break_5",
+ "uom",
+ "stock_uom",
+ "conversion_factor",
+ "reference_section",
+ "sales_order",
+ "sales_order_item"
],
"fields": [
- {
- "fieldname": "item",
- "fieldtype": "Link",
- "in_list_view": 1,
- "label": "Item",
- "options": "Item"
- },
- {
- "fieldname": "reference_doctype",
- "fieldtype": "Link",
- "label": "Reference Document type",
- "options": "DocType"
- },
- {
- "fieldname": "reference_name",
- "fieldtype": "Dynamic Link",
- "label": "Reference Name",
- "options": "reference_doctype"
- },
{
"fieldname": "qty",
"fieldtype": "Float",
@@ -37,13 +24,62 @@
"label": "Qty"
},
{
- "fieldname": "reference_document_item",
+ "fieldname": "quantity_section",
+ "fieldtype": "Section Break",
+ "label": "Quantity"
+ },
+ {
+ "fieldname": "stock_qty",
+ "fieldtype": "Float",
+ "label": "Stock Qty"
+ },
+ {
+ "fieldname": "uom",
+ "fieldtype": "Link",
+ "label": "UOM",
+ "options": "UOM"
+ },
+ {
+ "fieldname": "stock_uom",
+ "fieldtype": "Link",
+ "label": "Stock UOM",
+ "options": "UOM"
+ },
+ {
+ "fieldname": "item_code",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Item",
+ "options": "Item"
+ },
+ {
+ "fieldname": "column_break_5",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "reference_section",
+ "fieldtype": "Section Break",
+ "label": "Reference"
+ },
+ {
+ "fieldname": "sales_order",
+ "fieldtype": "Link",
+ "label": "Sales Order",
+ "options": "Sales Order"
+ },
+ {
+ "fieldname": "sales_order_item",
"fieldtype": "Data",
- "label": "Reference Document Item"
+ "label": "Sales Order Item"
+ },
+ {
+ "fieldname": "conversion_factor",
+ "fieldtype": "Float",
+ "label": "UOM Conversion Factor"
}
],
"istable": 1,
- "modified": "2019-07-30 23:43:30.901151",
+ "modified": "2019-08-14 18:38:28.867113",
"modified_by": "Administrator",
"module": "Stock",
"name": "Pick List Reference Item",
diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py
index f1d784c8d9..41101f4678 100644
--- a/erpnext/stock/get_item_details.py
+++ b/erpnext/stock/get_item_details.py
@@ -22,7 +22,7 @@ sales_doctypes = ['Quotation', 'Sales Order', 'Delivery Note', 'Sales Invoice']
purchase_doctypes = ['Material Request', 'Supplier Quotation', 'Purchase Order', 'Purchase Receipt', 'Purchase Invoice']
@frappe.whitelist()
-def get_item_details(args, doc=None):
+def get_item_details(args, doc=None, overwrite_warehouse=True):
"""
args = {
"item_code": "",
@@ -44,11 +44,15 @@ def get_item_details(args, doc=None):
"set_warehouse": ""
}
"""
+
args = process_args(args)
+ print('warehouse', args.warehouse, '========')
item = frappe.get_cached_doc("Item", args.item_code)
validate_item_details(args, item)
- out = get_basic_details(args, item)
+ out = get_basic_details(args, item, overwrite_warehouse)
+
+ print('warehouse2', out.warehouse, '========')
get_item_tax_template(args, item, out)
out["item_tax_rate"] = get_item_tax_map(args.company, args.get("item_tax_template") if out.get("item_tax_template") is None \
@@ -178,7 +182,7 @@ def validate_item_details(args, item):
throw(_("Item {0} must be a Sub-contracted Item").format(item.name))
-def get_basic_details(args, item):
+def get_basic_details(args, item, overwrite_warehouse=True):
"""
:param args: {
"item_code": "",
@@ -225,14 +229,26 @@ def get_basic_details(args, item):
item_group_defaults = get_item_group_defaults(item.name, args.company)
brand_defaults = get_brand_defaults(item.name, args.company)
- warehouse = (args.get("set_warehouse") or item_defaults.get("default_warehouse") or
- item_group_defaults.get("default_warehouse") or brand_defaults.get("default_warehouse") or args.warehouse)
+ if overwrite_warehouse or not args.warehouse:
+ warehouse = (
+ args.get("set_warehouse") or
+ item_defaults.get("default_warehouse") or
+ item_group_defaults.get("default_warehouse") or
+ brand_defaults.get("default_warehouse") or
+ args.warehouse
+ )
- if not warehouse:
- defaults = frappe.defaults.get_defaults() or {}
- if defaults.get("default_warehouse") and frappe.db.exists("Warehouse",
- {'name': defaults.default_warehouse, 'company': args.company}):
- warehouse = defaults.default_warehouse
+ if not warehouse:
+ defaults = frappe.defaults.get_defaults() or {}
+ warehouse_exists = frappe.db.exists("Warehouse", {
+ 'name': defaults.default_warehouse,
+ 'company': args.company
+ })
+ if defaults.get("default_warehouse") and warehouse_exists:
+ warehouse = defaults.default_warehouse
+
+ else:
+ warehouse = args.warehouse
if args.get('doctype') == "Material Request" and not args.get('material_request_type'):
args['material_request_type'] = frappe.db.get_value('Material Request',
@@ -784,6 +800,7 @@ def get_projected_qty(item_code, warehouse):
@frappe.whitelist()
def get_bin_details(item_code, warehouse):
+ print(item_code, warehouse, '---------------------------')
return frappe.db.get_value("Bin", {"item_code": item_code, "warehouse": warehouse},
["projected_qty", "actual_qty", "reserved_qty"], as_dict=True, cache=True) \
or {"projected_qty": 0, "actual_qty": 0, "reserved_qty": 0}
From 42d9298318657f83cd11612887280ee59c59316d Mon Sep 17 00:00:00 2001
From: deepeshgarg007
Date: Fri, 16 Aug 2019 12:58:24 +0530
Subject: [PATCH 258/484] fix: Remove extra space
---
erpnext/accounts/doctype/account/account_tree.js | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/erpnext/accounts/doctype/account/account_tree.js b/erpnext/accounts/doctype/account/account_tree.js
index 6fdd797437..efac1af551 100644
--- a/erpnext/accounts/doctype/account/account_tree.js
+++ b/erpnext/accounts/doctype/account/account_tree.js
@@ -123,7 +123,8 @@ frappe.treeview_settings["Account"] = {
if(frappe.boot.user.can_read.indexOf("GL Entry") !== -1){
// show Dr if positive since balance is calculated as debit - credit else show Cr
- let dr_or_cr = node.data.balance_in_account_currency > 0 ? "Dr": "Cr";
+ let balance = node.data.balance_in_account_currency || node.data.balance;
+ let dr_or_cr = balance > 0 ? "Dr": "Cr";
if (node.data && node.data.balance!==undefined) {
$(''
From 8d0b6f9a60c606423e3fea258ccfe1b12127560d Mon Sep 17 00:00:00 2001
From: deepeshgarg007
Date: Fri, 16 Aug 2019 14:00:26 +0530
Subject: [PATCH 259/484] fix: Handling if no default dimension exists
---
.../public/js/utils/dimension_tree_filter.js | 22 ++++++++++---------
1 file changed, 12 insertions(+), 10 deletions(-)
diff --git a/erpnext/public/js/utils/dimension_tree_filter.js b/erpnext/public/js/utils/dimension_tree_filter.js
index 72a05b4221..aada92d7da 100644
--- a/erpnext/public/js/utils/dimension_tree_filter.js
+++ b/erpnext/public/js/utils/dimension_tree_filter.js
@@ -28,25 +28,27 @@ erpnext.doctypes_with_dimensions.forEach((doctype) => {
});
}
- if (frappe.meta.has_field(doctype, dimension['fieldname'])) {
- if (frm.is_new() && frappe.meta.has_field(doctype, 'company') && frm.doc.company) {
- frm.set_value(dimension['fieldname'], erpnext.default_dimensions[frm.doc.company][dimension['document_type']]);
+ if (Object.keys(erpnext.default_dimensions).length > 0) {
+ if (frappe.meta.has_field(doctype, dimension['fieldname'])) {
+ if (frm.is_new() && frappe.meta.has_field(doctype, 'company') && frm.doc.company) {
+ frm.set_value(dimension['fieldname'], erpnext.default_dimensions[frm.doc.company][dimension['document_type']]);
+ }
}
- }
- if (frm.doc.items && frm.doc.items.length) {
- frm.doc.items[0][dimension['fieldname']] = erpnext.default_dimensions[frm.doc.company][dimension['document_type']];
- }
+ if (frm.doc.items && frm.doc.items.length) {
+ frm.doc.items[0][dimension['fieldname']] = erpnext.default_dimensions[frm.doc.company][dimension['document_type']];
+ }
- if (frm.doc.accounts && frm.doc.accounts.length) {
- frm.doc.accounts[0][dimension['fieldname']] = erpnext.default_dimensions[frm.doc.company][dimension['document_type']];
+ if (frm.doc.accounts && frm.doc.accounts.length) {
+ frm.doc.accounts[0][dimension['fieldname']] = erpnext.default_dimensions[frm.doc.company][dimension['document_type']];
+ }
}
});
});
},
company: function(frm) {
- if(frm.doc.company) {
+ if(frm.doc.company && (Object.keys(erpnext.default_dimensions).length > 0)) {
erpnext.dimension_filters.forEach((dimension) => {
if (frappe.meta.has_field(doctype, dimension['fieldname'])) {
frm.set_value(dimension['fieldname'], erpnext.default_dimensions[frm.doc.company][dimension['document_type']]);
From 0a2ed6da37848cd10315366fcc063545c2504d6b Mon Sep 17 00:00:00 2001
From: deepeshgarg007
Date: Fri, 16 Aug 2019 15:50:17 +0530
Subject: [PATCH 260/484] fix: Add missing semicolon
---
erpnext/public/js/utils/dimension_tree_filter.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/erpnext/public/js/utils/dimension_tree_filter.js b/erpnext/public/js/utils/dimension_tree_filter.js
index aada92d7da..e6c18a149b 100644
--- a/erpnext/public/js/utils/dimension_tree_filter.js
+++ b/erpnext/public/js/utils/dimension_tree_filter.js
@@ -3,11 +3,11 @@ frappe.provide('frappe.ui.form');
erpnext.doctypes_with_dimensions = ["GL Entry", "Sales Invoice", "Purchase Invoice", "Payment Entry", "Asset",
"Expense Claim", "Stock Entry", "Budget", "Payroll Entry", "Delivery Note", "Shipping Rule", "Loyalty Program",
"Fee Schedule", "Fee Structure", "Stock Reconciliation", "Travel Request", "Fees", "POS Profile", "Opening Invoice Creation Tool",
- "Subscription", "Purchase Order", "Journal Entry", "Material Request", "Purchase Receipt", "Landed Cost Item", "Asset"]
+ "Subscription", "Purchase Order", "Journal Entry", "Material Request", "Purchase Receipt", "Landed Cost Item", "Asset"];
erpnext.child_docs = ["Sales Invoice Item", "Purchase Invoice Item", "Purchase Order Item", "Journal Entry Account",
"Material Request Item", "Delivery Note Item", "Purchase Receipt Item", "Stock Entry Detail", "Payment Entry Deduction",
- "Landed Cost Item", "Asset Value Adjustment", "Opening Invoice Creation Tool Item", "Subscription Plan"]
+ "Landed Cost Item", "Asset Value Adjustment", "Opening Invoice Creation Tool Item", "Subscription Plan"];
frappe.call({
method: "erpnext.accounts.doctype.accounting_dimension.accounting_dimension.get_dimension_filters",
From 0df513434edf63cb37bc21f919fffc0f779cbda0 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Mon, 19 Aug 2019 10:04:52 +0530
Subject: [PATCH 261/484] fix: valuation rate in stock ledger (#18744)
* fix: valuation rate in stock ledger
* test: allow zero valuation rate for items
---
.../doctype/delivery_note/test_delivery_note.py | 1 +
erpnext/stock/stock_ledger.py | 16 +++++++++++-----
2 files changed, 12 insertions(+), 5 deletions(-)
diff --git a/erpnext/stock/doctype/delivery_note/test_delivery_note.py b/erpnext/stock/doctype/delivery_note/test_delivery_note.py
index bc95c965bc..91b6f4c606 100644
--- a/erpnext/stock/doctype/delivery_note/test_delivery_note.py
+++ b/erpnext/stock/doctype/delivery_note/test_delivery_note.py
@@ -701,6 +701,7 @@ def create_delivery_note(**args):
"qty": args.qty or 1,
"rate": args.rate or 100,
"conversion_factor": 1.0,
+ "allow_zero_valuation_rate": args.allow_zero_valuation_rate or 1,
"expense_account": "Cost of Goods Sold - _TC",
"cost_center": args.cost_center or "_Test Cost Center - _TC",
"serial_no": args.serial_no,
diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py
index 5fda2a4007..920fc272f7 100644
--- a/erpnext/stock/stock_ledger.py
+++ b/erpnext/stock/stock_ledger.py
@@ -464,16 +464,22 @@ def get_valuation_rate(item_code, warehouse, voucher_type, voucher_no,
last_valuation_rate = frappe.db.sql("""select valuation_rate
from `tabStock Ledger Entry`
- where item_code = %s and warehouse = %s
- and valuation_rate >= 0
- order by posting_date desc, posting_time desc, creation desc limit 1""", (item_code, warehouse))
+ where
+ item_code = %s
+ AND warehouse = %s
+ AND valuation_rate >= 0
+ AND NOT (voucher_no = %s AND voucher_type = %s)
+ order by posting_date desc, posting_time desc, name desc limit 1""", (item_code, warehouse, voucher_no, voucher_type))
if not last_valuation_rate:
# Get valuation rate from last sle for the item against any warehouse
last_valuation_rate = frappe.db.sql("""select valuation_rate
from `tabStock Ledger Entry`
- where item_code = %s and valuation_rate > 0
- order by posting_date desc, posting_time desc, creation desc limit 1""", item_code)
+ where
+ item_code = %s
+ AND valuation_rate > 0
+ AND NOT(voucher_no = %s AND voucher_type = %s)
+ order by posting_date desc, posting_time desc, name desc limit 1""", (item_code, voucher_no, voucher_type))
if last_valuation_rate:
return flt(last_valuation_rate[0][0]) # as there is previous records, it might come with zero rate
From bc5712a1b3aac62f170a2e1b37056817f50287bd Mon Sep 17 00:00:00 2001
From: Anurag Mishra <32095923+Anurag810@users.noreply.github.com>
Date: Mon, 19 Aug 2019 10:24:44 +0530
Subject: [PATCH 262/484] fix: validated cost center in financial_statement
(#18733)
* fix: validated cost center in financial_statement
* Update financial_statements.py
---
erpnext/accounts/report/financial_statements.py | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/erpnext/accounts/report/financial_statements.py b/erpnext/accounts/report/financial_statements.py
index 7b9c939b47..3c8de6026a 100644
--- a/erpnext/accounts/report/financial_statements.py
+++ b/erpnext/accounts/report/financial_statements.py
@@ -425,9 +425,12 @@ def get_cost_centers_with_children(cost_centers):
all_cost_centers = []
for d in cost_centers:
- lft, rgt = frappe.db.get_value("Cost Center", d, ["lft", "rgt"])
- children = frappe.get_all("Cost Center", filters={"lft": [">=", lft], "rgt": ["<=", rgt]})
- all_cost_centers += [c.name for c in children]
+ if frappe.db.exists("Cost Center", d):
+ lft, rgt = frappe.db.get_value("Cost Center", d, ["lft", "rgt"])
+ children = frappe.get_all("Cost Center", filters={"lft": [">=", lft], "rgt": ["<=", rgt]})
+ all_cost_centers += [c.name for c in children]
+ else:
+ frappe.throw(_("Cost Center: {0} does not exist".format(d)))
return list(set(all_cost_centers))
From 19c3cb0d5b3cde60c41fc5b7100edddca717b77a Mon Sep 17 00:00:00 2001
From: Anurag Mishra <32095923+Anurag810@users.noreply.github.com>
Date: Mon, 19 Aug 2019 10:31:02 +0530
Subject: [PATCH 263/484] fix: removed filters(not required) (#18729)
---
.../controllers/sales_and_purchase_return.py | 35 ++++++++-----------
1 file changed, 15 insertions(+), 20 deletions(-)
diff --git a/erpnext/controllers/sales_and_purchase_return.py b/erpnext/controllers/sales_and_purchase_return.py
index 2fddcdf24c..7d03722b16 100644
--- a/erpnext/controllers/sales_and_purchase_return.py
+++ b/erpnext/controllers/sales_and_purchase_return.py
@@ -18,34 +18,29 @@ def validate_return(doc):
validate_returned_items(doc)
def validate_return_against(doc):
- filters = {"doctype": doc.doctype, "docstatus": 1, "company": doc.company}
- if doc.meta.get_field("customer") and doc.customer:
- filters["customer"] = doc.customer
- elif doc.meta.get_field("supplier") and doc.supplier:
- filters["supplier"] = doc.supplier
-
- if not frappe.db.exists(filters):
+ if not frappe.db.exists(doc.doctype, doc.return_against):
frappe.throw(_("Invalid {0}: {1}")
.format(doc.meta.get_label("return_against"), doc.return_against))
else:
ref_doc = frappe.get_doc(doc.doctype, doc.return_against)
- # validate posting date time
- return_posting_datetime = "%s %s" % (doc.posting_date, doc.get("posting_time") or "00:00:00")
- ref_posting_datetime = "%s %s" % (ref_doc.posting_date, ref_doc.get("posting_time") or "00:00:00")
+ if ref_doc.company == doc.company and ref_doc.customer = doc.customer and ref_doc.docstatus == 1:
+ # validate posting date time
+ return_posting_datetime = "%s %s" % (doc.posting_date, doc.get("posting_time") or "00:00:00")
+ ref_posting_datetime = "%s %s" % (ref_doc.posting_date, ref_doc.get("posting_time") or "00:00:00")
- if get_datetime(return_posting_datetime) < get_datetime(ref_posting_datetime):
- frappe.throw(_("Posting timestamp must be after {0}").format(format_datetime(ref_posting_datetime)))
+ if get_datetime(return_posting_datetime) < get_datetime(ref_posting_datetime):
+ frappe.throw(_("Posting timestamp must be after {0}").format(format_datetime(ref_posting_datetime)))
- # validate same exchange rate
- if doc.conversion_rate != ref_doc.conversion_rate:
- frappe.throw(_("Exchange Rate must be same as {0} {1} ({2})")
- .format(doc.doctype, doc.return_against, ref_doc.conversion_rate))
+ # validate same exchange rate
+ if doc.conversion_rate != ref_doc.conversion_rate:
+ frappe.throw(_("Exchange Rate must be same as {0} {1} ({2})")
+ .format(doc.doctype, doc.return_against, ref_doc.conversion_rate))
- # validate update stock
- if doc.doctype == "Sales Invoice" and doc.update_stock and not ref_doc.update_stock:
- frappe.throw(_("'Update Stock' can not be checked because items are not delivered via {0}")
- .format(doc.return_against))
+ # validate update stock
+ if doc.doctype == "Sales Invoice" and doc.update_stock and not ref_doc.update_stock:
+ frappe.throw(_("'Update Stock' can not be checked because items are not delivered via {0}")
+ .format(doc.return_against))
def validate_returned_items(doc):
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
From 669cff88d147417caf3d1f35b0c09d1a62afa55a Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Mon, 19 Aug 2019 10:38:01 +0530
Subject: [PATCH 264/484] fix: Get items button
---
erpnext/stock/doctype/pick_list/pick_list.js | 57 ++++++++++----------
1 file changed, 28 insertions(+), 29 deletions(-)
diff --git a/erpnext/stock/doctype/pick_list/pick_list.js b/erpnext/stock/doctype/pick_list/pick_list.js
index 602b7e02dd..cb3cec6ab6 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.js
+++ b/erpnext/stock/doctype/pick_list/pick_list.js
@@ -14,24 +14,35 @@ frappe.ui.form.on('Pick List', {
},
refresh: (frm) => {
frm.add_custom_button(__('Delivery Note'), () => frm.trigger('make_delivery_note'), __('Create'));
- frm.add_custom_button(__('Sales Order'), () => {
- erpnext.utils.map_current_doc({
- method: "erpnext.selling.doctype.sales_order.sales_order.make_pick_list",
- source_doctype: "Sales Order",
- target: frm,
- setters: {
- company: frm.doc.company,
- },
- get_query_filters: {
- docstatus: 1,
- }
- });
- }, __("Get items from"));
- frm.add_custom_button(__('Work Order'), () => {
+ if (frm.doc.reference_items && frm.doc.reference_items.length) {
+ frm.add_custom_button(__('Get Item Locations'), () => {
+ frm.call('set_item_locations');
+ });
+ }
+
+ frm.trigger('add_get_items_button');
+ },
+ items_based_on: (frm) => {
+ frm.trigger('add_get_items_button');
+ },
+ make_delivery_note(frm) {
+ frappe.model.open_mapped_doc({
+ method: "erpnext.stock.doctype.pick_list.pick_list.make_delivery_note",
+ frm: frm
+ });
+ },
+ add_get_items_button(frm) {
+ frm.remove_custom_button(__("Get items"));
+ let source_doctype = frm.doc.items_based_on;
+ let method = 'erpnext.selling.doctype.sales_order.sales_order.make_pick_list';
+ if (source_doctype === 'Sales Order') {
+ method = 'erpnext.manufacturing.doctype.work_order.work_order.make_pick_list';
+ }
+ frm.add_custom_button(__("Get items"), () => {
erpnext.utils.map_current_doc({
- method: "erpnext.manufacturing.doctype.work_order.work_order.make_pick_list",
- source_doctype: "Work Order",
+ method: method,
+ source_doctype: source_doctype,
target: frm,
setters: {
company: frm.doc.company,
@@ -41,18 +52,6 @@ frappe.ui.form.on('Pick List', {
docstatus: 1,
}
});
- }, __("Get items from"));
-
- if (frm.doc.reference_items && frm.doc.reference_items.length) {
- frm.add_custom_button(__('Get Item Locations'), () => {
- frm.call('set_item_locations');
- });
- }
- },
- make_delivery_note(frm) {
- frappe.model.open_mapped_doc({
- method: "erpnext.stock.doctype.pick_list.pick_list.make_delivery_note",
- frm: frm
});
- },
+ }
});
From 6450be5e58fa070badf11bb03a2274a00f9e96d1 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Mon, 19 Aug 2019 10:48:21 +0530
Subject: [PATCH 265/484] fix: Get Items button
---
erpnext/stock/doctype/pick_list/pick_list.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/stock/doctype/pick_list/pick_list.js b/erpnext/stock/doctype/pick_list/pick_list.js
index cb3cec6ab6..2e72d98d3f 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.js
+++ b/erpnext/stock/doctype/pick_list/pick_list.js
@@ -36,7 +36,7 @@ frappe.ui.form.on('Pick List', {
frm.remove_custom_button(__("Get items"));
let source_doctype = frm.doc.items_based_on;
let method = 'erpnext.selling.doctype.sales_order.sales_order.make_pick_list';
- if (source_doctype === 'Sales Order') {
+ if (source_doctype === 'Work Order') {
method = 'erpnext.manufacturing.doctype.work_order.work_order.make_pick_list';
}
frm.add_custom_button(__("Get items"), () => {
From 960a1cbd8f965374c51c5f45b2a857f24bd4d958 Mon Sep 17 00:00:00 2001
From: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com>
Date: Mon, 19 Aug 2019 11:51:16 +0530
Subject: [PATCH 266/484] fix: Party dashboard heatmap not capturing sales,
purchase and other activities (#18753)
---
erpnext/accounts/party.py | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/erpnext/accounts/party.py b/erpnext/accounts/party.py
index cb94722651..e42f4af2a5 100644
--- a/erpnext/accounts/party.py
+++ b/erpnext/accounts/party.py
@@ -469,7 +469,9 @@ def get_timeline_data(doctype, name):
# fetch and append data from Activity Log
data += frappe.db.sql("""select {fields}
from `tabActivity Log`
- where reference_doctype={doctype} and reference_name={name}
+ where (reference_doctype="{doctype}" and reference_name="{name}")
+ or (timeline_doctype in ("{doctype}") and timeline_name="{name}")
+ or (reference_doctype in ("Quotation", "Opportunity") and timeline_name="{name}")
and status!='Success' and creation > {after}
{group_by} order by creation desc
""".format(doctype=frappe.db.escape(doctype), name=frappe.db.escape(name), fields=fields,
From 5efedd7a605a4ef1070a7f08886d9c9178aeba7f Mon Sep 17 00:00:00 2001
From: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com>
Date: Mon, 19 Aug 2019 12:56:22 +0530
Subject: [PATCH 267/484] fix: Travis (#18772)
---
erpnext/controllers/sales_and_purchase_return.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/controllers/sales_and_purchase_return.py b/erpnext/controllers/sales_and_purchase_return.py
index 7d03722b16..28dd4ea8b6 100644
--- a/erpnext/controllers/sales_and_purchase_return.py
+++ b/erpnext/controllers/sales_and_purchase_return.py
@@ -24,7 +24,7 @@ def validate_return_against(doc):
else:
ref_doc = frappe.get_doc(doc.doctype, doc.return_against)
- if ref_doc.company == doc.company and ref_doc.customer = doc.customer and ref_doc.docstatus == 1:
+ if ref_doc.company == doc.company and ref_doc.customer == doc.customer and ref_doc.docstatus == 1:
# validate posting date time
return_posting_datetime = "%s %s" % (doc.posting_date, doc.get("posting_time") or "00:00:00")
ref_posting_datetime = "%s %s" % (ref_doc.posting_date, ref_doc.get("posting_time") or "00:00:00")
From c80e5fe7a1e7d39eb297ba73c3e1c3ebf6845be1 Mon Sep 17 00:00:00 2001
From: deepeshgarg007
Date: Mon, 19 Aug 2019 14:38:15 +0530
Subject: [PATCH 268/484] fix: Failing sales and purchase return test cases
---
erpnext/controllers/sales_and_purchase_return.py | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/erpnext/controllers/sales_and_purchase_return.py b/erpnext/controllers/sales_and_purchase_return.py
index 28dd4ea8b6..6a03c519ef 100644
--- a/erpnext/controllers/sales_and_purchase_return.py
+++ b/erpnext/controllers/sales_and_purchase_return.py
@@ -24,7 +24,12 @@ def validate_return_against(doc):
else:
ref_doc = frappe.get_doc(doc.doctype, doc.return_against)
- if ref_doc.company == doc.company and ref_doc.customer == doc.customer and ref_doc.docstatus == 1:
+ if doc.doctype == "Sales Invoice":
+ party_type == "customer"
+ else:
+ party_type == "supplier"
+
+ if ref_doc.company == doc.company and ref_doc.get(pary_type) == doc.get(party_type) and ref_doc.docstatus == 1:
# validate posting date time
return_posting_datetime = "%s %s" % (doc.posting_date, doc.get("posting_time") or "00:00:00")
ref_posting_datetime = "%s %s" % (ref_doc.posting_date, ref_doc.get("posting_time") or "00:00:00")
From 7d288437d8a119712dad5067f40c008648420736 Mon Sep 17 00:00:00 2001
From: deepeshgarg007
Date: Mon, 19 Aug 2019 16:19:48 +0530
Subject: [PATCH 269/484] fix: Assignment
---
erpnext/controllers/sales_and_purchase_return.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/erpnext/controllers/sales_and_purchase_return.py b/erpnext/controllers/sales_and_purchase_return.py
index 6a03c519ef..cb68315f9b 100644
--- a/erpnext/controllers/sales_and_purchase_return.py
+++ b/erpnext/controllers/sales_and_purchase_return.py
@@ -25,9 +25,9 @@ def validate_return_against(doc):
ref_doc = frappe.get_doc(doc.doctype, doc.return_against)
if doc.doctype == "Sales Invoice":
- party_type == "customer"
+ party_type = "customer"
else:
- party_type == "supplier"
+ party_type = "supplier"
if ref_doc.company == doc.company and ref_doc.get(pary_type) == doc.get(party_type) and ref_doc.docstatus == 1:
# validate posting date time
From e2acc748c81b4e2d7a4e96e8f64e7e9e09acf226 Mon Sep 17 00:00:00 2001
From: deepeshgarg007
Date: Mon, 19 Aug 2019 16:38:04 +0530
Subject: [PATCH 270/484] fix: Check for return against delivery noteas well
---
erpnext/controllers/sales_and_purchase_return.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/controllers/sales_and_purchase_return.py b/erpnext/controllers/sales_and_purchase_return.py
index cb68315f9b..e9633558ef 100644
--- a/erpnext/controllers/sales_and_purchase_return.py
+++ b/erpnext/controllers/sales_and_purchase_return.py
@@ -24,7 +24,7 @@ def validate_return_against(doc):
else:
ref_doc = frappe.get_doc(doc.doctype, doc.return_against)
- if doc.doctype == "Sales Invoice":
+ if doc.doctype in ("Sales Invoice", "Delivery Note"):
party_type = "customer"
else:
party_type = "supplier"
From 0487ad5515df3fd1535bd5d1271e69e842d186e4 Mon Sep 17 00:00:00 2001
From: deepeshgarg007
Date: Mon, 19 Aug 2019 16:40:29 +0530
Subject: [PATCH 271/484] fix: Code cleanup
---
erpnext/controllers/sales_and_purchase_return.py | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/erpnext/controllers/sales_and_purchase_return.py b/erpnext/controllers/sales_and_purchase_return.py
index e9633558ef..6054b9015a 100644
--- a/erpnext/controllers/sales_and_purchase_return.py
+++ b/erpnext/controllers/sales_and_purchase_return.py
@@ -24,10 +24,7 @@ def validate_return_against(doc):
else:
ref_doc = frappe.get_doc(doc.doctype, doc.return_against)
- if doc.doctype in ("Sales Invoice", "Delivery Note"):
- party_type = "customer"
- else:
- party_type = "supplier"
+ party_type == "customer" if doc.doctype in ("Sales Invoice", "Delivery Note") else "supplier"
if ref_doc.company == doc.company and ref_doc.get(pary_type) == doc.get(party_type) and ref_doc.docstatus == 1:
# validate posting date time
From 3965451c7a78d3ea78d6fa5c57204448cbc24ec9 Mon Sep 17 00:00:00 2001
From: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com>
Date: Mon, 19 Aug 2019 17:40:29 +0530
Subject: [PATCH 272/484] Update
erpnext/controllers/sales_and_purchase_return.py
Co-Authored-By: Mangesh-Khairnar
---
erpnext/controllers/sales_and_purchase_return.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/controllers/sales_and_purchase_return.py b/erpnext/controllers/sales_and_purchase_return.py
index 6054b9015a..bc2876f824 100644
--- a/erpnext/controllers/sales_and_purchase_return.py
+++ b/erpnext/controllers/sales_and_purchase_return.py
@@ -24,7 +24,7 @@ def validate_return_against(doc):
else:
ref_doc = frappe.get_doc(doc.doctype, doc.return_against)
- party_type == "customer" if doc.doctype in ("Sales Invoice", "Delivery Note") else "supplier"
+ party_type = "customer" if doc.doctype in ("Sales Invoice", "Delivery Note") else "supplier"
if ref_doc.company == doc.company and ref_doc.get(pary_type) == doc.get(party_type) and ref_doc.docstatus == 1:
# validate posting date time
From 33b392ac2be2075321856c6273ee4b18f1ab715e Mon Sep 17 00:00:00 2001
From: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com>
Date: Mon, 19 Aug 2019 17:43:10 +0530
Subject: [PATCH 273/484] Update
erpnext/controllers/sales_and_purchase_return.py
Co-Authored-By: Mangesh-Khairnar
---
erpnext/controllers/sales_and_purchase_return.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/controllers/sales_and_purchase_return.py b/erpnext/controllers/sales_and_purchase_return.py
index bc2876f824..b713958b1b 100644
--- a/erpnext/controllers/sales_and_purchase_return.py
+++ b/erpnext/controllers/sales_and_purchase_return.py
@@ -26,7 +26,7 @@ def validate_return_against(doc):
party_type = "customer" if doc.doctype in ("Sales Invoice", "Delivery Note") else "supplier"
- if ref_doc.company == doc.company and ref_doc.get(pary_type) == doc.get(party_type) and ref_doc.docstatus == 1:
+ if ref_doc.company == doc.company and ref_doc.get(party_type) == doc.get(party_type) and ref_doc.docstatus == 1:
# validate posting date time
return_posting_datetime = "%s %s" % (doc.posting_date, doc.get("posting_time") or "00:00:00")
ref_posting_datetime = "%s %s" % (ref_doc.posting_date, ref_doc.get("posting_time") or "00:00:00")
From 1008e6e45022217131503af9b826580bb0f5b18c Mon Sep 17 00:00:00 2001
From: Rohit Waghchaure
Date: Mon, 19 Aug 2019 20:21:36 +0530
Subject: [PATCH 274/484] fix: debit note not reconciled with another purchase
invoice using payment reconciliation
---
.../payment_reconciliation.py | 13 +++++--------
1 file changed, 5 insertions(+), 8 deletions(-)
diff --git a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
index b74eed5841..4665d75510 100644
--- a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
+++ b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
@@ -93,7 +93,7 @@ class PaymentReconciliation(Document):
and `tab{doc}`.is_return = 1 and `tabGL Entry`.against_voucher_type = %(voucher_type)s
and `tab{doc}`.docstatus = 1 and `tabGL Entry`.party = %(party)s
and `tabGL Entry`.party_type = %(party_type)s and `tabGL Entry`.account = %(account)s
- GROUP BY `tabSales Invoice`.name
+ GROUP BY `tab{doc}`.name
Having
amount > 0
""".format(doc=voucher_type, dr_or_cr=dr_or_cr, reconciled_dr_or_cr=reconciled_dr_or_cr), {
@@ -257,11 +257,8 @@ def reconcile_dr_cr_note(dr_cr_notes):
voucher_type = ('Credit Note'
if d.voucher_type == 'Sales Invoice' else 'Debit Note')
- dr_or_cr = ('credit_in_account_currency'
- if d.reference_type == 'Sales Invoice' else 'debit_in_account_currency')
-
reconcile_dr_or_cr = ('debit_in_account_currency'
- if dr_or_cr == 'credit_in_account_currency' else 'credit_in_account_currency')
+ if d.dr_or_cr == 'credit_in_account_currency' else 'credit_in_account_currency')
jv = frappe.get_doc({
"doctype": "Journal Entry",
@@ -272,8 +269,7 @@ def reconcile_dr_cr_note(dr_cr_notes):
'account': d.account,
'party': d.party,
'party_type': d.party_type,
- reconcile_dr_or_cr: (abs(d.allocated_amount)
- if abs(d.unadjusted_amount) > abs(d.allocated_amount) else abs(d.unadjusted_amount)),
+ d.dr_or_cr: abs(d.allocated_amount),
'reference_type': d.against_voucher_type,
'reference_name': d.against_voucher
},
@@ -281,7 +277,8 @@ def reconcile_dr_cr_note(dr_cr_notes):
'account': d.account,
'party': d.party,
'party_type': d.party_type,
- dr_or_cr: abs(d.allocated_amount),
+ reconcile_dr_or_cr: (abs(d.allocated_amount)
+ if abs(d.unadjusted_amount) > abs(d.allocated_amount) else abs(d.unadjusted_amount)),
'reference_type': d.voucher_type,
'reference_name': d.voucher_no
}
From c97a7fb845302c7d3fe7e661ab228946b3e4545d Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Wed, 14 Aug 2019 17:38:44 +0530
Subject: [PATCH 275/484] fix: restrict the payment order to non received type
payment entries
---
erpnext/accounts/doctype/payment_order/payment_order.js | 1 +
1 file changed, 1 insertion(+)
diff --git a/erpnext/accounts/doctype/payment_order/payment_order.js b/erpnext/accounts/doctype/payment_order/payment_order.js
index f2f00cebcb..ce9cfe527c 100644
--- a/erpnext/accounts/doctype/payment_order/payment_order.js
+++ b/erpnext/accounts/doctype/payment_order/payment_order.js
@@ -66,6 +66,7 @@ frappe.ui.form.on('Payment Order', {
get_query_filters: {
bank: frm.doc.bank,
docstatus: 1,
+ payment_type: ("!=", "Receive"),
bank_account: frm.doc.company_bank_account,
paid_from: frm.doc.account,
payment_order_status: ["=", "Initiated"],
From 15839250804c6d62d37739533b2e898506218690 Mon Sep 17 00:00:00 2001
From: Rohit Waghchaure
Date: Sun, 26 May 2019 18:18:21 +0530
Subject: [PATCH 276/484] fix: Pro rata calculation is not working for WDV
depreciation method
---
erpnext/assets/doctype/asset/asset.js | 15 ++-
erpnext/assets/doctype/asset/asset.py | 109 +++++++-----------
.../asset_settings/asset_settings.json | 71 +-----------
3 files changed, 56 insertions(+), 139 deletions(-)
diff --git a/erpnext/assets/doctype/asset/asset.js b/erpnext/assets/doctype/asset/asset.js
index 2d78d2693d..c5cad73801 100644
--- a/erpnext/assets/doctype/asset/asset.js
+++ b/erpnext/assets/doctype/asset/asset.js
@@ -303,14 +303,17 @@ frappe.ui.form.on('Asset', {
},
set_depreciation_rate: function(frm, row) {
- if (row.total_number_of_depreciations && row.frequency_of_depreciation) {
+ if (row.total_number_of_depreciations && row.frequency_of_depreciation
+ && row.expected_value_after_useful_life) {
frappe.call({
method: "get_depreciation_rate",
doc: frm.doc,
args: row,
callback: function(r) {
if (r.message) {
- frappe.model.set_value(row.doctype, row.name, "rate_of_depreciation", r.message);
+ frappe.flags.dont_change_rate = true;
+ frappe.model.set_value(row.doctype, row.name,
+ "rate_of_depreciation", flt(r.message, precision("rate_of_depreciation", row)));
}
}
});
@@ -338,6 +341,14 @@ frappe.ui.form.on('Asset Finance Book', {
total_number_of_depreciations: function(frm, cdt, cdn) {
const row = locals[cdt][cdn];
frm.events.set_depreciation_rate(frm, row);
+ },
+
+ rate_of_depreciation: function(frm, cdt, cdn) {
+ if(!frappe.flags.dont_change_rate) {
+ frappe.model.set_value(cdt, cdn, "expected_value_after_useful_life", 0);
+ }
+
+ frappe.flags.dont_change_rate = false;
}
});
diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py
index c398a7342a..6475d0c4aa 100644
--- a/erpnext/assets/doctype/asset/asset.py
+++ b/erpnext/assets/doctype/asset/asset.py
@@ -101,7 +101,8 @@ class Asset(AccountsController):
def set_depreciation_rate(self):
for d in self.get("finance_books"):
- d.rate_of_depreciation = self.get_depreciation_rate(d, on_validate=True)
+ d.rate_of_depreciation = flt(self.get_depreciation_rate(d, on_validate=True),
+ d.precision("rate_of_depreciation"))
def make_depreciation_schedule(self):
depreciation_method = [d.depreciation_method for d in self.finance_books]
@@ -110,8 +111,6 @@ class Asset(AccountsController):
self.schedules = []
if not self.get("schedules") and self.available_for_use_date:
- total_depreciations = sum([d.total_number_of_depreciations for d in self.get('finance_books')])
-
for d in self.get('finance_books'):
self.validate_asset_finance_books(d)
@@ -124,74 +123,55 @@ class Asset(AccountsController):
end_date = add_months(d.depreciation_start_date,
no_of_depreciations * cint(d.frequency_of_depreciation))
- total_days = date_diff(end_date, self.available_for_use_date)
- rate_per_day = (value_after_depreciation - d.get("expected_value_after_useful_life")) / total_days
+ if d.depreciation_method in ("Straight Line", "Manual"):
+ total_days = date_diff(end_date, self.available_for_use_date)
+ rate_per_day = (value_after_depreciation - d.get("expected_value_after_useful_life")) / total_days
number_of_pending_depreciations = cint(d.total_number_of_depreciations) - \
cint(self.number_of_depreciations_booked)
from_date = self.available_for_use_date
if number_of_pending_depreciations:
- next_depr_date = getdate(add_months(self.available_for_use_date,
- number_of_pending_depreciations * 12))
- if (cint(frappe.db.get_value("Asset Settings", None, "schedule_based_on_fiscal_year")) == 1
- and getdate(d.depreciation_start_date) < next_depr_date):
+ period_start_date = add_months(d.depreciation_start_date,
+ cint(d.frequency_of_depreciation) * -1)
- number_of_pending_depreciations += 1
- for n in range(number_of_pending_depreciations):
- if n == list(range(number_of_pending_depreciations))[-1]:
- schedule_date = add_months(self.available_for_use_date, n * 12)
- previous_scheduled_date = add_months(d.depreciation_start_date, (n-1) * 12)
- depreciation_amount = \
- self.get_depreciation_amount_prorata_temporis(value_after_depreciation,
- d, previous_scheduled_date, schedule_date)
+ for n in range(number_of_pending_depreciations):
+ schedule_date = add_months(d.depreciation_start_date,
+ n * cint(d.frequency_of_depreciation))
- elif n == list(range(number_of_pending_depreciations))[0]:
- schedule_date = d.depreciation_start_date
- depreciation_amount = \
- self.get_depreciation_amount_prorata_temporis(value_after_depreciation,
- d, self.available_for_use_date, schedule_date)
+ days = date_diff(schedule_date, from_date)
- else:
- schedule_date = add_months(d.depreciation_start_date, n * 12)
- depreciation_amount = \
- self.get_depreciation_amount_prorata_temporis(value_after_depreciation, d)
+ if n == 0: days += 1
- if value_after_depreciation != 0:
- value_after_depreciation -= flt(depreciation_amount)
+ if d.depreciation_method in ("Straight Line", "Manual"):
+ depreciation_amount = days * rate_per_day
+ else:
+ total_days = date_diff(schedule_date, period_start_date)
+ period_start_date = schedule_date
+ depreciation_amount = self.get_depreciation_amount(value_after_depreciation,
+ d.total_number_of_depreciations, d)
- self.append("schedules", {
- "schedule_date": schedule_date,
- "depreciation_amount": depreciation_amount,
- "depreciation_method": d.depreciation_method,
- "finance_book": d.finance_book,
- "finance_book_id": d.idx
- })
- else:
- for n in range(number_of_pending_depreciations):
- schedule_date = add_months(d.depreciation_start_date,
- n * cint(d.frequency_of_depreciation))
+ depreciation_amount = flt((depreciation_amount * days) / total_days,
+ self.precision("gross_purchase_amount"))
- if d.depreciation_method in ("Straight Line", "Manual"):
- days = date_diff(schedule_date, from_date)
- if n == 0: days += 1
+ from_date = schedule_date
- depreciation_amount = days * rate_per_day
- from_date = schedule_date
- else:
- depreciation_amount = self.get_depreciation_amount(value_after_depreciation,
- d.total_number_of_depreciations, d)
+ if depreciation_amount:
+ value_after_depreciation -= flt(depreciation_amount,
+ self.precision("gross_purchase_amount"))
- if depreciation_amount:
- value_after_depreciation -= flt(depreciation_amount)
+ if (n == cint(number_of_pending_depreciations) - 1 and
+ d.expected_value_after_useful_life and
+ value_after_depreciation > d.expected_value_after_useful_life):
+ depreciation_amount += (value_after_depreciation - d.expected_value_after_useful_life)
- self.append("schedules", {
- "schedule_date": schedule_date,
- "depreciation_amount": depreciation_amount,
- "depreciation_method": d.depreciation_method,
- "finance_book": d.finance_book,
- "finance_book_id": d.idx
- })
+ self.append("schedules", {
+ "schedule_date": schedule_date,
+ "depreciation_amount": depreciation_amount,
+ "depreciation_method": d.depreciation_method,
+ "finance_book": d.finance_book,
+ "finance_book_id": d.idx
+ })
def validate_asset_finance_books(self, row):
if flt(row.expected_value_after_useful_life) >= flt(self.gross_purchase_amount):
@@ -261,16 +241,8 @@ class Asset(AccountsController):
return flt(self.get('finance_books')[cint(idx)-1].value_after_depreciation)
def get_depreciation_amount(self, depreciable_value, total_number_of_depreciations, row):
- if row.depreciation_method in ["Straight Line", "Manual"]:
- amt = (flt(self.gross_purchase_amount) - flt(row.expected_value_after_useful_life) -
- flt(self.opening_accumulated_depreciation))
-
- depreciation_amount = amt * row.rate_of_depreciation
- else:
- depreciation_amount = flt(depreciable_value) * (flt(row.rate_of_depreciation) / 100)
- value_after_depreciation = flt(depreciable_value) - depreciation_amount
- if value_after_depreciation < flt(row.expected_value_after_useful_life):
- depreciation_amount = flt(depreciable_value) - flt(row.expected_value_after_useful_life)
+ precision = self.precision("gross_purchase_amount")
+ depreciation_amount = flt(depreciable_value * (flt(row.rate_of_depreciation) / 100), precision)
return depreciation_amount
@@ -301,9 +273,12 @@ class Asset(AccountsController):
flt(accumulated_depreciation_after_full_schedule),
self.precision('gross_purchase_amount'))
- if row.expected_value_after_useful_life < asset_value_after_full_schedule:
+ if (row.expected_value_after_useful_life and
+ row.expected_value_after_useful_life < asset_value_after_full_schedule):
frappe.throw(_("Depreciation Row {0}: Expected value after useful life must be greater than or equal to {1}")
.format(row.idx, asset_value_after_full_schedule))
+ elif not row.expected_value_after_useful_life:
+ row.expected_value_after_useful_life = asset_value_after_full_schedule
def validate_cancellation(self):
if self.status not in ("Submitted", "Partially Depreciated", "Fully Depreciated"):
diff --git a/erpnext/assets/doctype/asset_settings/asset_settings.json b/erpnext/assets/doctype/asset_settings/asset_settings.json
index a3fee96f4e..edc5ce169c 100644
--- a/erpnext/assets/doctype/asset_settings/asset_settings.json
+++ b/erpnext/assets/doctype/asset_settings/asset_settings.json
@@ -46,75 +46,6 @@
"translatable": 0,
"unique": 0
},
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "schedule_based_on_fiscal_year",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Calculate Prorated Depreciation Schedule Based on Fiscal Year",
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "360",
- "depends_on": "eval:doc.schedule_based_on_fiscal_year",
- "description": "This value is used for pro-rata temporis calculation",
- "fetch_if_empty": 0,
- "fieldname": "number_of_days_in_fiscal_year",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Number of Days in Fiscal Year",
- "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,
- "translatable": 0,
- "unique": 0
- },
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
@@ -159,7 +90,7 @@
"issingle": 1,
"istable": 0,
"max_attachments": 0,
- "modified": "2019-03-08 10:44:41.924547",
+ "modified": "2019-05-26 18:31:19.930563",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Settings",
From 5d3dee206f07e0e092c9d2bffcdda56772b961b0 Mon Sep 17 00:00:00 2001
From: Rohit Waghchaure
Date: Tue, 28 May 2019 10:33:56 +0530
Subject: [PATCH 277/484] fixed test cases and the logic for pro rata
calculation
---
erpnext/assets/doctype/asset/asset.py | 146 +++++++++++----------
erpnext/assets/doctype/asset/test_asset.py | 137 +++++++++++--------
2 files changed, 160 insertions(+), 123 deletions(-)
diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py
index 6475d0c4aa..45d2ec2c51 100644
--- a/erpnext/assets/doctype/asset/asset.py
+++ b/erpnext/assets/doctype/asset/asset.py
@@ -6,7 +6,7 @@ from __future__ import unicode_literals
import frappe, erpnext, math, json
from frappe import _
from six import string_types
-from frappe.utils import flt, add_months, cint, nowdate, getdate, today, date_diff
+from frappe.utils import flt, add_months, cint, nowdate, getdate, today, date_diff, add_days
from frappe.model.document import Document
from erpnext.assets.doctype.asset_category.asset_category import get_asset_category_account
from erpnext.assets.doctype.asset.depreciation \
@@ -105,73 +105,84 @@ class Asset(AccountsController):
d.precision("rate_of_depreciation"))
def make_depreciation_schedule(self):
- depreciation_method = [d.depreciation_method for d in self.finance_books]
-
- if 'Manual' not in depreciation_method:
+ if 'Manual' not in [d.depreciation_method for d in self.finance_books]:
self.schedules = []
- if not self.get("schedules") and self.available_for_use_date:
- for d in self.get('finance_books'):
- self.validate_asset_finance_books(d)
+ if self.get("schedules") or not self.available_for_use_date:
+ return
- value_after_depreciation = (flt(self.gross_purchase_amount) -
- flt(self.opening_accumulated_depreciation))
+ for d in self.get('finance_books'):
+ self.validate_asset_finance_books(d)
- d.value_after_depreciation = value_after_depreciation
+ value_after_depreciation = (flt(self.gross_purchase_amount) -
+ flt(self.opening_accumulated_depreciation))
- no_of_depreciations = cint(d.total_number_of_depreciations - 1) - cint(self.number_of_depreciations_booked)
- end_date = add_months(d.depreciation_start_date,
- no_of_depreciations * cint(d.frequency_of_depreciation))
+ d.value_after_depreciation = value_after_depreciation
- if d.depreciation_method in ("Straight Line", "Manual"):
- total_days = date_diff(end_date, self.available_for_use_date)
- rate_per_day = (value_after_depreciation - d.get("expected_value_after_useful_life")) / total_days
+ number_of_pending_depreciations = cint(d.total_number_of_depreciations) - \
+ cint(self.number_of_depreciations_booked)
- number_of_pending_depreciations = cint(d.total_number_of_depreciations) - \
- cint(self.number_of_depreciations_booked)
+ has_pro_rata = self.check_is_pro_rata(d)
- from_date = self.available_for_use_date
- if number_of_pending_depreciations:
- period_start_date = add_months(d.depreciation_start_date,
- cint(d.frequency_of_depreciation) * -1)
+ if has_pro_rata:
+ number_of_pending_depreciations += 1
- for n in range(number_of_pending_depreciations):
- schedule_date = add_months(d.depreciation_start_date,
- n * cint(d.frequency_of_depreciation))
+ skip_row = False
+ for n in range(number_of_pending_depreciations):
+ # If depreciation is already completed (for double declining balance)
+ if skip_row: continue
- days = date_diff(schedule_date, from_date)
+ depreciation_amount = self.get_depreciation_amount(value_after_depreciation,
+ d.total_number_of_depreciations, d)
- if n == 0: days += 1
+ if not has_pro_rata or n < cint(number_of_pending_depreciations) - 1:
+ schedule_date = add_months(d.depreciation_start_date,
+ n * cint(d.frequency_of_depreciation))
- if d.depreciation_method in ("Straight Line", "Manual"):
- depreciation_amount = days * rate_per_day
- else:
- total_days = date_diff(schedule_date, period_start_date)
- period_start_date = schedule_date
- depreciation_amount = self.get_depreciation_amount(value_after_depreciation,
- d.total_number_of_depreciations, d)
+ # For first row
+ if has_pro_rata and n==0:
+ depreciation_amount, days = get_pro_rata_amt(d, depreciation_amount,
+ self.available_for_use_date, d.depreciation_start_date)
+ # For last row
+ elif has_pro_rata and n == cint(number_of_pending_depreciations) - 1:
+ to_date = add_months(self.available_for_use_date,
+ n * cint(d.frequency_of_depreciation))
- depreciation_amount = flt((depreciation_amount * days) / total_days,
- self.precision("gross_purchase_amount"))
+ depreciation_amount, days = get_pro_rata_amt(d,
+ depreciation_amount, schedule_date, to_date)
- from_date = schedule_date
+ schedule_date = add_days(schedule_date, days)
- if depreciation_amount:
- value_after_depreciation -= flt(depreciation_amount,
- self.precision("gross_purchase_amount"))
+ if not depreciation_amount: continue
+ value_after_depreciation -= flt(depreciation_amount,
+ self.precision("gross_purchase_amount"))
- if (n == cint(number_of_pending_depreciations) - 1 and
- d.expected_value_after_useful_life and
- value_after_depreciation > d.expected_value_after_useful_life):
- depreciation_amount += (value_after_depreciation - d.expected_value_after_useful_life)
+ # Adjust depreciation amount in the last period based on the expected value after useful life
+ if d.expected_value_after_useful_life and ((n == cint(number_of_pending_depreciations) - 1
+ and value_after_depreciation != d.expected_value_after_useful_life)
+ or value_after_depreciation < d.expected_value_after_useful_life):
+ depreciation_amount += (value_after_depreciation - d.expected_value_after_useful_life)
+ skip_row = True
- self.append("schedules", {
- "schedule_date": schedule_date,
- "depreciation_amount": depreciation_amount,
- "depreciation_method": d.depreciation_method,
- "finance_book": d.finance_book,
- "finance_book_id": d.idx
- })
+ if depreciation_amount > 0:
+ self.append("schedules", {
+ "schedule_date": schedule_date,
+ "depreciation_amount": depreciation_amount,
+ "depreciation_method": d.depreciation_method,
+ "finance_book": d.finance_book,
+ "finance_book_id": d.idx
+ })
+
+ def check_is_pro_rata(self, row):
+ has_pro_rata = False
+
+ days = date_diff(row.depreciation_start_date, self.available_for_use_date) + 1
+ total_days = get_total_days(row.depreciation_start_date, row.frequency_of_depreciation)
+
+ if days < total_days:
+ has_pro_rata = True
+
+ return has_pro_rata
def validate_asset_finance_books(self, row):
if flt(row.expected_value_after_useful_life) >= flt(self.gross_purchase_amount):
@@ -242,22 +253,13 @@ class Asset(AccountsController):
def get_depreciation_amount(self, depreciable_value, total_number_of_depreciations, row):
precision = self.precision("gross_purchase_amount")
- depreciation_amount = flt(depreciable_value * (flt(row.rate_of_depreciation) / 100), precision)
-
- return depreciation_amount
-
- def get_depreciation_amount_prorata_temporis(self, depreciable_value, row, start_date=None, end_date=None):
- if start_date and end_date:
- prorata_temporis = min(abs(flt(date_diff(str(end_date), str(start_date)))) / flt(frappe.db.get_value("Asset Settings", None, "number_of_days_in_fiscal_year")), 1)
- else:
- prorata_temporis = 1
if row.depreciation_method in ("Straight Line", "Manual"):
depreciation_amount = (flt(row.value_after_depreciation) -
flt(row.expected_value_after_useful_life)) / (cint(row.total_number_of_depreciations) -
- cint(self.number_of_depreciations_booked)) * prorata_temporis
+ cint(self.number_of_depreciations_booked))
else:
- depreciation_amount = self.get_depreciation_amount(depreciable_value, row.total_number_of_depreciations, row)
+ depreciation_amount = flt(depreciable_value * (flt(row.rate_of_depreciation) / 100), precision)
return depreciation_amount
@@ -387,15 +389,7 @@ class Asset(AccountsController):
if isinstance(args, string_types):
args = json.loads(args)
- number_of_depreciations_booked = 0
- if self.is_existing_asset:
- number_of_depreciations_booked = self.number_of_depreciations_booked
-
float_precision = cint(frappe.db.get_default("float_precision")) or 2
- tot_no_of_depreciation = flt(args.get("total_number_of_depreciations")) - flt(number_of_depreciations_booked)
-
- if args.get("depreciation_method") in ["Straight Line", "Manual"]:
- return 1.0 / tot_no_of_depreciation
if args.get("depreciation_method") == 'Double Declining Balance':
return 200.0 / args.get("total_number_of_depreciations")
@@ -575,3 +569,15 @@ def make_journal_entry(asset_name):
def is_cwip_accounting_disabled():
return cint(frappe.db.get_single_value("Asset Settings", "disable_cwip_accounting"))
+
+def get_pro_rata_amt(row, depreciation_amount, from_date, to_date):
+ days = date_diff(to_date, from_date)
+ total_days = get_total_days(to_date, row.frequency_of_depreciation)
+
+ return (depreciation_amount * flt(days)) / flt(total_days), days
+
+def get_total_days(date, frequency):
+ period_start_date = add_months(date,
+ cint(frequency) * -1)
+
+ return date_diff(date, period_start_date)
\ No newline at end of file
diff --git a/erpnext/assets/doctype/asset/test_asset.py b/erpnext/assets/doctype/asset/test_asset.py
index fceccfbd1c..481ee7d9f4 100644
--- a/erpnext/assets/doctype/asset/test_asset.py
+++ b/erpnext/assets/doctype/asset/test_asset.py
@@ -88,23 +88,23 @@ class TestAsset(unittest.TestCase):
asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, 'name')
asset = frappe.get_doc('Asset', asset_name)
asset.calculate_depreciation = 1
- asset.available_for_use_date = '2020-06-06'
- asset.purchase_date = '2020-06-06'
+ asset.available_for_use_date = '2030-01-01'
+ asset.purchase_date = '2030-01-01'
asset.append("finance_books", {
"expected_value_after_useful_life": 10000,
- "next_depreciation_date": "2020-12-31",
"depreciation_method": "Straight Line",
"total_number_of_depreciations": 3,
- "frequency_of_depreciation": 10,
- "depreciation_start_date": "2020-06-06"
+ "frequency_of_depreciation": 12,
+ "depreciation_start_date": "2030-12-31"
})
asset.save()
+
self.assertEqual(asset.status, "Draft")
expected_schedules = [
- ["2020-06-06", 147.54, 147.54],
- ["2021-04-06", 44852.46, 45000.0],
- ["2022-02-06", 45000.0, 90000.00]
+ ["2030-12-31", 30000.00, 30000.00],
+ ["2031-12-31", 30000.00, 60000.00],
+ ["2032-12-31", 30000.00, 90000.00]
]
schedules = [[cstr(d.schedule_date), d.depreciation_amount, d.accumulated_depreciation_amount]
@@ -118,20 +118,21 @@ class TestAsset(unittest.TestCase):
asset.calculate_depreciation = 1
asset.number_of_depreciations_booked = 1
asset.opening_accumulated_depreciation = 40000
+ asset.available_for_use_date = "2030-06-06"
asset.append("finance_books", {
"expected_value_after_useful_life": 10000,
- "next_depreciation_date": "2020-12-31",
"depreciation_method": "Straight Line",
"total_number_of_depreciations": 3,
- "frequency_of_depreciation": 10,
- "depreciation_start_date": "2020-06-06"
+ "frequency_of_depreciation": 12,
+ "depreciation_start_date": "2030-12-31"
})
asset.insert()
self.assertEqual(asset.status, "Draft")
asset.save()
expected_schedules = [
- ["2020-06-06", 164.47, 40164.47],
- ["2021-04-06", 49835.53, 90000.00]
+ ["2030-12-31", 14246.58, 54246.58],
+ ["2031-12-31", 25000.00, 79246.58],
+ ["2032-06-06", 10753.42, 90000.00]
]
schedules = [[cstr(d.schedule_date), flt(d.depreciation_amount, 2), d.accumulated_depreciation_amount]
for d in asset.get("schedules")]
@@ -145,24 +146,23 @@ class TestAsset(unittest.TestCase):
asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, 'name')
asset = frappe.get_doc('Asset', asset_name)
asset.calculate_depreciation = 1
- asset.available_for_use_date = '2020-06-06'
- asset.purchase_date = '2020-06-06'
+ asset.available_for_use_date = '2030-01-01'
+ asset.purchase_date = '2030-01-01'
asset.append("finance_books", {
"expected_value_after_useful_life": 10000,
- "next_depreciation_date": "2020-12-31",
"depreciation_method": "Double Declining Balance",
"total_number_of_depreciations": 3,
- "frequency_of_depreciation": 10,
- "depreciation_start_date": "2020-06-06"
+ "frequency_of_depreciation": 12,
+ "depreciation_start_date": '2030-12-31'
})
asset.insert()
self.assertEqual(asset.status, "Draft")
asset.save()
expected_schedules = [
- ["2020-06-06", 66666.67, 66666.67],
- ["2021-04-06", 22222.22, 88888.89],
- ["2022-02-06", 1111.11, 90000.0]
+ ['2030-12-31', 66667.00, 66667.00],
+ ['2031-12-31', 22222.11, 88889.11],
+ ['2032-12-31', 1110.89, 90000.0]
]
schedules = [[cstr(d.schedule_date), d.depreciation_amount, d.accumulated_depreciation_amount]
@@ -177,23 +177,21 @@ class TestAsset(unittest.TestCase):
asset.is_existing_asset = 1
asset.number_of_depreciations_booked = 1
asset.opening_accumulated_depreciation = 50000
+ asset.available_for_use_date = '2030-01-01'
+ asset.purchase_date = '2029-11-30'
asset.append("finance_books", {
"expected_value_after_useful_life": 10000,
- "next_depreciation_date": "2020-12-31",
"depreciation_method": "Double Declining Balance",
"total_number_of_depreciations": 3,
- "frequency_of_depreciation": 10,
- "depreciation_start_date": "2020-06-06"
+ "frequency_of_depreciation": 12,
+ "depreciation_start_date": "2030-12-31"
})
asset.insert()
self.assertEqual(asset.status, "Draft")
- asset.save()
-
- asset.save()
expected_schedules = [
- ["2020-06-06", 33333.33, 83333.33],
- ["2021-04-06", 6666.67, 90000.0]
+ ["2030-12-31", 33333.50, 83333.50],
+ ["2031-12-31", 6666.50, 90000.0]
]
schedules = [[cstr(d.schedule_date), d.depreciation_amount, d.accumulated_depreciation_amount]
@@ -209,25 +207,25 @@ class TestAsset(unittest.TestCase):
asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, 'name')
asset = frappe.get_doc('Asset', asset_name)
asset.calculate_depreciation = 1
- asset.purchase_date = '2020-01-30'
+ asset.purchase_date = '2030-01-30'
asset.is_existing_asset = 0
- asset.available_for_use_date = "2020-01-30"
+ asset.available_for_use_date = "2030-01-30"
asset.append("finance_books", {
"expected_value_after_useful_life": 10000,
"depreciation_method": "Straight Line",
"total_number_of_depreciations": 3,
- "frequency_of_depreciation": 10,
- "depreciation_start_date": "2020-12-31"
+ "frequency_of_depreciation": 12,
+ "depreciation_start_date": "2030-12-31"
})
asset.insert()
asset.save()
expected_schedules = [
- ["2020-12-31", 28000.0, 28000.0],
- ["2021-12-31", 30000.0, 58000.0],
- ["2022-12-31", 30000.0, 88000.0],
- ["2023-01-30", 2000.0, 90000.0]
+ ["2030-12-31", 27534.25, 27534.25],
+ ["2031-12-31", 30000.0, 57534.25],
+ ["2032-12-31", 30000.0, 87534.25],
+ ["2033-01-30", 2465.75, 90000.0]
]
schedules = [[cstr(d.schedule_date), flt(d.depreciation_amount, 2), flt(d.accumulated_depreciation_amount, 2)]
@@ -266,8 +264,8 @@ class TestAsset(unittest.TestCase):
self.assertEqual(asset.get("schedules")[0].journal_entry[:4], "DEPR")
expected_gle = (
- ("_Test Accumulated Depreciations - _TC", 0.0, 32129.24),
- ("_Test Depreciations - _TC", 32129.24, 0.0)
+ ("_Test Accumulated Depreciations - _TC", 0.0, 30000.0),
+ ("_Test Depreciations - _TC", 30000.0, 0.0)
)
gle = frappe.db.sql("""select account, debit, credit from `tabGL Entry`
@@ -277,15 +275,15 @@ class TestAsset(unittest.TestCase):
self.assertEqual(gle, expected_gle)
self.assertEqual(asset.get("value_after_depreciation"), 0)
- def test_depreciation_entry_for_wdv(self):
+ def test_depreciation_entry_for_wdv_without_pro_rata(self):
pr = make_purchase_receipt(item_code="Macbook Pro",
qty=1, rate=8000.0, location="Test Location")
asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, 'name')
asset = frappe.get_doc('Asset', asset_name)
asset.calculate_depreciation = 1
- asset.available_for_use_date = '2030-06-06'
- asset.purchase_date = '2030-06-06'
+ asset.available_for_use_date = '2030-01-01'
+ asset.purchase_date = '2030-01-01'
asset.append("finance_books", {
"expected_value_after_useful_life": 1000,
"depreciation_method": "Written Down Value",
@@ -298,9 +296,41 @@ class TestAsset(unittest.TestCase):
self.assertEqual(asset.finance_books[0].rate_of_depreciation, 50.0)
expected_schedules = [
- ["2030-12-31", 4000.0, 4000.0],
- ["2031-12-31", 2000.0, 6000.0],
- ["2032-12-31", 1000.0, 7000.0],
+ ["2030-12-31", 4000.00, 4000.00],
+ ["2031-12-31", 2000.00, 6000.00],
+ ["2032-12-31", 1000.00, 7000.0],
+ ]
+
+ schedules = [[cstr(d.schedule_date), flt(d.depreciation_amount, 2), flt(d.accumulated_depreciation_amount, 2)]
+ for d in asset.get("schedules")]
+
+ self.assertEqual(schedules, expected_schedules)
+
+ def test_pro_rata_depreciation_entry_for_wdv(self):
+ pr = make_purchase_receipt(item_code="Macbook Pro",
+ qty=1, rate=8000.0, location="Test Location")
+
+ asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, 'name')
+ asset = frappe.get_doc('Asset', asset_name)
+ asset.calculate_depreciation = 1
+ asset.available_for_use_date = '2030-06-06'
+ asset.purchase_date = '2030-01-01'
+ asset.append("finance_books", {
+ "expected_value_after_useful_life": 1000,
+ "depreciation_method": "Written Down Value",
+ "total_number_of_depreciations": 3,
+ "frequency_of_depreciation": 12,
+ "depreciation_start_date": "2030-12-31"
+ })
+ asset.save(ignore_permissions=True)
+
+ self.assertEqual(asset.finance_books[0].rate_of_depreciation, 50.0)
+
+ expected_schedules = [
+ ["2030-12-31", 2279.45, 2279.45],
+ ["2031-12-31", 2860.28, 5139.73],
+ ["2032-12-31", 1430.14, 6569.87],
+ ["2033-06-06", 430.13, 7000.0],
]
schedules = [[cstr(d.schedule_date), flt(d.depreciation_amount, 2), flt(d.accumulated_depreciation_amount, 2)]
@@ -346,18 +376,19 @@ class TestAsset(unittest.TestCase):
asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, 'name')
asset = frappe.get_doc('Asset', asset_name)
asset.calculate_depreciation = 1
- asset.available_for_use_date = '2020-06-06'
- asset.purchase_date = '2020-06-06'
+ asset.available_for_use_date = nowdate()
+ asset.purchase_date = nowdate()
asset.append("finance_books", {
"expected_value_after_useful_life": 10000,
"depreciation_method": "Straight Line",
"total_number_of_depreciations": 3,
"frequency_of_depreciation": 10,
- "depreciation_start_date": "2020-06-06"
+ "depreciation_start_date": nowdate()
})
asset.insert()
asset.submit()
- post_depreciation_entries(date="2021-01-01")
+
+ post_depreciation_entries(date=add_months(nowdate(), 10))
scrap_asset(asset.name)
@@ -366,9 +397,9 @@ class TestAsset(unittest.TestCase):
self.assertTrue(asset.journal_entry_for_scrap)
expected_gle = (
- ("_Test Accumulated Depreciations - _TC", 147.54, 0.0),
+ ("_Test Accumulated Depreciations - _TC", 30000.0, 0.0),
("_Test Fixed Asset - _TC", 0.0, 100000.0),
- ("_Test Gain/Loss on Asset Disposal - _TC", 99852.46, 0.0)
+ ("_Test Gain/Loss on Asset Disposal - _TC", 70000.0, 0.0)
)
gle = frappe.db.sql("""select account, debit, credit from `tabGL Entry`
@@ -412,9 +443,9 @@ class TestAsset(unittest.TestCase):
self.assertEqual(frappe.db.get_value("Asset", asset.name, "status"), "Sold")
expected_gle = (
- ("_Test Accumulated Depreciations - _TC", 23051.47, 0.0),
+ ("_Test Accumulated Depreciations - _TC", 20392.16, 0.0),
("_Test Fixed Asset - _TC", 0.0, 100000.0),
- ("_Test Gain/Loss on Asset Disposal - _TC", 51948.53, 0.0),
+ ("_Test Gain/Loss on Asset Disposal - _TC", 54607.84, 0.0),
("Debtors - _TC", 25000.0, 0.0)
)
From a251267dd7ae14c1ca32db0429222e1176d5ac51 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Tue, 20 Aug 2019 12:03:03 +0530
Subject: [PATCH 278/484] fix: Quantity while creating pick list from work
order
- Fix get_mapped_doc config to filter items
- Fix erroneous condition in get_mapped_doc used for creation of pick_list
in sales order
---
.../doctype/work_order/work_order.py | 17 +++---
.../doctype/sales_order/sales_order.py | 2 +-
erpnext/stock/doctype/pick_list/pick_list.js | 26 +++++++--
.../stock/doctype/pick_list/pick_list.json | 4 +-
erpnext/stock/doctype/pick_list/pick_list.py | 57 +++++++++----------
5 files changed, 60 insertions(+), 46 deletions(-)
diff --git a/erpnext/manufacturing/doctype/work_order/work_order.py b/erpnext/manufacturing/doctype/work_order/work_order.py
index c489fbcd55..c653deece3 100644
--- a/erpnext/manufacturing/doctype/work_order/work_order.py
+++ b/erpnext/manufacturing/doctype/work_order/work_order.py
@@ -711,6 +711,14 @@ def get_work_order_operation_data(work_order, operation, workstation):
@frappe.whitelist()
def make_pick_list(source_name, target_doc=None):
+ def update_item_quantity(source, target, source_parent):
+ qty = source.required_qty - source.transferred_qty
+ target.qty = qty
+ target.stock_qty = qty
+ target.uom = frappe.get_value('Item', source.item_code, 'stock_uom')
+ target.stock_uom = target.uom
+ target.conversion_factor = 1
+
doc = get_mapped_doc("Work Order", source_name, {
"Work Order": {
"doctype": "Pick List",
@@ -720,13 +728,8 @@ def make_pick_list(source_name, target_doc=None):
},
"Work Order Item": {
"doctype": "Pick List Reference Item",
- "field_map": {
- "item_code": "item",
- "required_qty": "qty",
- "parenttype": "reference_doctype",
- "parent": "reference_name",
- "name": "reference_document_item"
- },
+ "postprocess": update_item_quantity,
+ "condition": lambda doc: abs(doc.transferred_qty) < abs(doc.required_qty)
},
}, target_doc)
diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py
index 2dc3788568..dd156d0473 100755
--- a/erpnext/selling/doctype/sales_order/sales_order.py
+++ b/erpnext/selling/doctype/sales_order/sales_order.py
@@ -1024,7 +1024,7 @@ def make_pick_list(source_name, target_doc=None):
"name": "sales_order_item"
},
"postprocess": update_item_quantity,
- "conditions": lambda doc: abs(doc.delivered_qty) < abs(doc.qty) and doc.delivered_by_supplier!=1
+ "condition": lambda doc: abs(doc.delivered_qty) < abs(doc.qty) and doc.delivered_by_supplier!=1
},
}, target_doc)
diff --git a/erpnext/stock/doctype/pick_list/pick_list.js b/erpnext/stock/doctype/pick_list/pick_list.js
index 2e72d98d3f..b9b317b732 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.js
+++ b/erpnext/stock/doctype/pick_list/pick_list.js
@@ -28,17 +28,35 @@ frappe.ui.form.on('Pick List', {
},
make_delivery_note(frm) {
frappe.model.open_mapped_doc({
- method: "erpnext.stock.doctype.pick_list.pick_list.make_delivery_note",
+ method: 'erpnext.stock.doctype.pick_list.pick_list.make_delivery_note',
frm: frm
});
},
add_get_items_button(frm) {
frm.remove_custom_button(__("Get items"));
let source_doctype = frm.doc.items_based_on;
+ let date_field = 'transaction_date';
+ let get_query_method = null;
+ let get_query_filters = {
+ docstatus: 1,
+ per_delivered: ['<', 100],
+ status: ['!=', '']
+ };
let method = 'erpnext.selling.doctype.sales_order.sales_order.make_pick_list';
if (source_doctype === 'Work Order') {
method = 'erpnext.manufacturing.doctype.work_order.work_order.make_pick_list';
+ date_field = 'planned_start_date';
+ get_query_method = 'erpnext.stock.doctype.pick_list.pick_list.get_pending_work_orders';
+ get_query_filters = null;
}
+
+ let get_query = () => {
+ return {
+ 'query': get_query_method,
+ 'filters': get_query_filters
+ };
+ };
+
frm.add_custom_button(__("Get items"), () => {
erpnext.utils.map_current_doc({
method: method,
@@ -47,10 +65,8 @@ frappe.ui.form.on('Pick List', {
setters: {
company: frm.doc.company,
},
- date_field: 'creation',
- get_query_filters: {
- docstatus: 1,
- }
+ date_field: date_field,
+ get_query: get_query
});
});
}
diff --git a/erpnext/stock/doctype/pick_list/pick_list.json b/erpnext/stock/doctype/pick_list/pick_list.json
index c7a5fc8c75..70272bf584 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.json
+++ b/erpnext/stock/doctype/pick_list/pick_list.json
@@ -57,10 +57,10 @@
"fieldname": "items_based_on",
"fieldtype": "Select",
"label": "Items Based On",
- "options": "\nSales Order\nWork Order"
+ "options": "Sales Order\nWork Order"
}
],
- "modified": "2019-08-13 19:30:01.151720",
+ "modified": "2019-08-19 12:31:54.023456",
"modified_by": "Administrator",
"module": "Stock",
"name": "Pick List",
diff --git a/erpnext/stock/doctype/pick_list/pick_list.py b/erpnext/stock/doctype/pick_list/pick_list.py
index 20b4230002..91bdcb33ee 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.py
+++ b/erpnext/stock/doctype/pick_list/pick_list.py
@@ -10,6 +10,8 @@ from frappe.model.mapper import get_mapped_doc, map_child_doc
from frappe.utils import floor, flt, today
from erpnext.selling.doctype.sales_order.sales_order import make_delivery_note as make_delivery_note_from_sales_order
+# TODO: Prioritize SO or WO group warehouse
+
class PickList(Document):
def set_item_locations(self):
reference_items = self.reference_items
@@ -154,36 +156,6 @@ def get_item_locations_based_on_batch_nos(item_doc):
if required_qty <= 0:
break
- # required_qty = item_doc.qty
- # while required_qty > 0 and batches:
- # batch = batches.pop()
- # batch_expiry = frappe.get_value('Batch', batch.batch_no, 'expiry_date')
- # if batch_expiry and batch_expiry <= frappe.utils.getdate():
- # frappe.msgprint('Skipping expired Batch {}'.format(batch.batch_no))
- # continue
- # item_doc.batch_no = batch.batch_no
- # if batch.qty >= item_doc.qty:
- # required_qty = 0
- # break
- # else:
- # # split item_code if quantity of item_code in batch is less that required
- # # Look for another batch
-
- # required_qty -= batch.qty
- # # set quantity of current item_code equal to batch quantity
- # item_doc.set('qty', batch.qty)
- # item_doc = parent_doc.append('items', {
- # 'item_code': item_doc.item_code,
- # 'qty': required_qty,
- # 'warehouse': item_doc.warehouse,
- # 'sales_order': item_doc.sales_order,
- # 'sales_order_item': item_doc.sales_order_item,
- # 'uom': item_doc.uom,
- # 'stock_uom': item_doc.stock_uom,
- # 'conversion_factor': item_doc.conversion_factor,
- # 'stock_qty': qty * item_doc.conversion_factor,
- # })
-
if required_qty:
frappe.msgprint('No batches found for {} qty of {}.'.format(required_qty, item_doc.item_code))
@@ -250,4 +222,27 @@ def update_delivery_note_item(source, target, delivery_note):
'company': delivery_note.company
})
- target.cost_center = cost_center
\ No newline at end of file
+ target.cost_center = cost_center
+
+@frappe.whitelist()
+def get_pending_work_orders(doctype, txt, searchfield, start, page_length, filters, as_dict):
+ return frappe.db.sql("""
+ SELECT
+ `name`, `company`, `planned_start_date`
+ FROM
+ `tabWork Order`
+ WHERE
+ `qty` > `produced_qty`
+ AND `status` not in ('Completed', 'Stopped')
+ AND name like %(txt)s
+ AND docstatus = 1
+ ORDER BY
+ if(locate(%(_txt)s, name), locate(%(_txt)s, name), 99999), name
+ LIMIT
+ %(start)s, %(page_length)s""",
+ {
+ 'txt': "%%%s%%" % txt,
+ '_txt': txt.replace('%', ''),
+ 'start': start,
+ 'page_length': frappe.utils.cint(page_length),
+ }, as_dict=as_dict)
From 1a090432d979b100757c943f7aa4d773cdfb31f6 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Tue, 20 Aug 2019 12:04:07 +0530
Subject: [PATCH 279/484] fix: Quantity while creating pick list from work
order
- Fix get_mapped_doc config to filter items
- Fix erroneous condition in get_mapped_doc used for creation of pick_list
in sales order
Co-authored-by: Nabin Hait
---
.../doctype/work_order/work_order.py | 17 +++---
.../doctype/sales_order/sales_order.py | 2 +-
erpnext/stock/doctype/pick_list/pick_list.js | 26 +++++++--
.../stock/doctype/pick_list/pick_list.json | 4 +-
erpnext/stock/doctype/pick_list/pick_list.py | 57 +++++++++----------
5 files changed, 60 insertions(+), 46 deletions(-)
diff --git a/erpnext/manufacturing/doctype/work_order/work_order.py b/erpnext/manufacturing/doctype/work_order/work_order.py
index c489fbcd55..c653deece3 100644
--- a/erpnext/manufacturing/doctype/work_order/work_order.py
+++ b/erpnext/manufacturing/doctype/work_order/work_order.py
@@ -711,6 +711,14 @@ def get_work_order_operation_data(work_order, operation, workstation):
@frappe.whitelist()
def make_pick_list(source_name, target_doc=None):
+ def update_item_quantity(source, target, source_parent):
+ qty = source.required_qty - source.transferred_qty
+ target.qty = qty
+ target.stock_qty = qty
+ target.uom = frappe.get_value('Item', source.item_code, 'stock_uom')
+ target.stock_uom = target.uom
+ target.conversion_factor = 1
+
doc = get_mapped_doc("Work Order", source_name, {
"Work Order": {
"doctype": "Pick List",
@@ -720,13 +728,8 @@ def make_pick_list(source_name, target_doc=None):
},
"Work Order Item": {
"doctype": "Pick List Reference Item",
- "field_map": {
- "item_code": "item",
- "required_qty": "qty",
- "parenttype": "reference_doctype",
- "parent": "reference_name",
- "name": "reference_document_item"
- },
+ "postprocess": update_item_quantity,
+ "condition": lambda doc: abs(doc.transferred_qty) < abs(doc.required_qty)
},
}, target_doc)
diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py
index 2dc3788568..dd156d0473 100755
--- a/erpnext/selling/doctype/sales_order/sales_order.py
+++ b/erpnext/selling/doctype/sales_order/sales_order.py
@@ -1024,7 +1024,7 @@ def make_pick_list(source_name, target_doc=None):
"name": "sales_order_item"
},
"postprocess": update_item_quantity,
- "conditions": lambda doc: abs(doc.delivered_qty) < abs(doc.qty) and doc.delivered_by_supplier!=1
+ "condition": lambda doc: abs(doc.delivered_qty) < abs(doc.qty) and doc.delivered_by_supplier!=1
},
}, target_doc)
diff --git a/erpnext/stock/doctype/pick_list/pick_list.js b/erpnext/stock/doctype/pick_list/pick_list.js
index 2e72d98d3f..b9b317b732 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.js
+++ b/erpnext/stock/doctype/pick_list/pick_list.js
@@ -28,17 +28,35 @@ frappe.ui.form.on('Pick List', {
},
make_delivery_note(frm) {
frappe.model.open_mapped_doc({
- method: "erpnext.stock.doctype.pick_list.pick_list.make_delivery_note",
+ method: 'erpnext.stock.doctype.pick_list.pick_list.make_delivery_note',
frm: frm
});
},
add_get_items_button(frm) {
frm.remove_custom_button(__("Get items"));
let source_doctype = frm.doc.items_based_on;
+ let date_field = 'transaction_date';
+ let get_query_method = null;
+ let get_query_filters = {
+ docstatus: 1,
+ per_delivered: ['<', 100],
+ status: ['!=', '']
+ };
let method = 'erpnext.selling.doctype.sales_order.sales_order.make_pick_list';
if (source_doctype === 'Work Order') {
method = 'erpnext.manufacturing.doctype.work_order.work_order.make_pick_list';
+ date_field = 'planned_start_date';
+ get_query_method = 'erpnext.stock.doctype.pick_list.pick_list.get_pending_work_orders';
+ get_query_filters = null;
}
+
+ let get_query = () => {
+ return {
+ 'query': get_query_method,
+ 'filters': get_query_filters
+ };
+ };
+
frm.add_custom_button(__("Get items"), () => {
erpnext.utils.map_current_doc({
method: method,
@@ -47,10 +65,8 @@ frappe.ui.form.on('Pick List', {
setters: {
company: frm.doc.company,
},
- date_field: 'creation',
- get_query_filters: {
- docstatus: 1,
- }
+ date_field: date_field,
+ get_query: get_query
});
});
}
diff --git a/erpnext/stock/doctype/pick_list/pick_list.json b/erpnext/stock/doctype/pick_list/pick_list.json
index c7a5fc8c75..70272bf584 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.json
+++ b/erpnext/stock/doctype/pick_list/pick_list.json
@@ -57,10 +57,10 @@
"fieldname": "items_based_on",
"fieldtype": "Select",
"label": "Items Based On",
- "options": "\nSales Order\nWork Order"
+ "options": "Sales Order\nWork Order"
}
],
- "modified": "2019-08-13 19:30:01.151720",
+ "modified": "2019-08-19 12:31:54.023456",
"modified_by": "Administrator",
"module": "Stock",
"name": "Pick List",
diff --git a/erpnext/stock/doctype/pick_list/pick_list.py b/erpnext/stock/doctype/pick_list/pick_list.py
index 20b4230002..91bdcb33ee 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.py
+++ b/erpnext/stock/doctype/pick_list/pick_list.py
@@ -10,6 +10,8 @@ from frappe.model.mapper import get_mapped_doc, map_child_doc
from frappe.utils import floor, flt, today
from erpnext.selling.doctype.sales_order.sales_order import make_delivery_note as make_delivery_note_from_sales_order
+# TODO: Prioritize SO or WO group warehouse
+
class PickList(Document):
def set_item_locations(self):
reference_items = self.reference_items
@@ -154,36 +156,6 @@ def get_item_locations_based_on_batch_nos(item_doc):
if required_qty <= 0:
break
- # required_qty = item_doc.qty
- # while required_qty > 0 and batches:
- # batch = batches.pop()
- # batch_expiry = frappe.get_value('Batch', batch.batch_no, 'expiry_date')
- # if batch_expiry and batch_expiry <= frappe.utils.getdate():
- # frappe.msgprint('Skipping expired Batch {}'.format(batch.batch_no))
- # continue
- # item_doc.batch_no = batch.batch_no
- # if batch.qty >= item_doc.qty:
- # required_qty = 0
- # break
- # else:
- # # split item_code if quantity of item_code in batch is less that required
- # # Look for another batch
-
- # required_qty -= batch.qty
- # # set quantity of current item_code equal to batch quantity
- # item_doc.set('qty', batch.qty)
- # item_doc = parent_doc.append('items', {
- # 'item_code': item_doc.item_code,
- # 'qty': required_qty,
- # 'warehouse': item_doc.warehouse,
- # 'sales_order': item_doc.sales_order,
- # 'sales_order_item': item_doc.sales_order_item,
- # 'uom': item_doc.uom,
- # 'stock_uom': item_doc.stock_uom,
- # 'conversion_factor': item_doc.conversion_factor,
- # 'stock_qty': qty * item_doc.conversion_factor,
- # })
-
if required_qty:
frappe.msgprint('No batches found for {} qty of {}.'.format(required_qty, item_doc.item_code))
@@ -250,4 +222,27 @@ def update_delivery_note_item(source, target, delivery_note):
'company': delivery_note.company
})
- target.cost_center = cost_center
\ No newline at end of file
+ target.cost_center = cost_center
+
+@frappe.whitelist()
+def get_pending_work_orders(doctype, txt, searchfield, start, page_length, filters, as_dict):
+ return frappe.db.sql("""
+ SELECT
+ `name`, `company`, `planned_start_date`
+ FROM
+ `tabWork Order`
+ WHERE
+ `qty` > `produced_qty`
+ AND `status` not in ('Completed', 'Stopped')
+ AND name like %(txt)s
+ AND docstatus = 1
+ ORDER BY
+ if(locate(%(_txt)s, name), locate(%(_txt)s, name), 99999), name
+ LIMIT
+ %(start)s, %(page_length)s""",
+ {
+ 'txt': "%%%s%%" % txt,
+ '_txt': txt.replace('%', ''),
+ 'start': start,
+ 'page_length': frappe.utils.cint(page_length),
+ }, as_dict=as_dict)
From d5b4b1fdaff341df5697f1e37c0b19ffd9238791 Mon Sep 17 00:00:00 2001
From: rohitwaghchaure
Date: Tue, 20 Aug 2019 12:35:15 +0530
Subject: [PATCH 280/484] fix: group by voucher consolidated showing incorrect
data for deferred entries (#18777)
---
.../report/general_ledger/general_ledger.py | 27 ++++++++++---------
1 file changed, 14 insertions(+), 13 deletions(-)
diff --git a/erpnext/accounts/report/general_ledger/general_ledger.py b/erpnext/accounts/report/general_ledger/general_ledger.py
index 86fd1088f5..ec3fb1fc9c 100644
--- a/erpnext/accounts/report/general_ledger/general_ledger.py
+++ b/erpnext/accounts/report/general_ledger/general_ledger.py
@@ -119,19 +119,11 @@ def get_gl_entries(filters):
select_fields = """, debit, credit, debit_in_account_currency,
credit_in_account_currency """
- group_by_statement = ''
order_by_statement = "order by posting_date, account"
if filters.get("group_by") == _("Group by Voucher"):
order_by_statement = "order by posting_date, voucher_type, voucher_no"
- if filters.get("group_by") == _("Group by Voucher (Consolidated)"):
- group_by_statement = "group by voucher_type, voucher_no, account, cost_center"
-
- select_fields = """, sum(debit) as debit, sum(credit) as credit,
- sum(debit_in_account_currency) as debit_in_account_currency,
- sum(credit_in_account_currency) as credit_in_account_currency"""
-
if filters.get("include_default_book_entries"):
filters['company_fb'] = frappe.db.get_value("Company",
filters.get("company"), 'default_finance_book')
@@ -144,11 +136,10 @@ def get_gl_entries(filters):
against_voucher_type, against_voucher, account_currency,
remarks, against, is_opening {select_fields}
from `tabGL Entry`
- where company=%(company)s {conditions} {group_by_statement}
+ where company=%(company)s {conditions}
{order_by_statement}
""".format(
select_fields=select_fields, conditions=get_conditions(filters),
- group_by_statement=group_by_statement,
order_by_statement=order_by_statement
),
filters, as_dict=1)
@@ -185,7 +176,8 @@ def get_conditions(filters):
if not (filters.get("account") or filters.get("party") or
filters.get("group_by") in ["Group by Account", "Group by Party"]):
conditions.append("posting_date >=%(from_date)s")
- conditions.append("posting_date <=%(to_date)s")
+
+ conditions.append("(posting_date <=%(to_date)s or is_opening = 'Yes')")
if filters.get("project"):
conditions.append("project in %(project)s")
@@ -286,6 +278,7 @@ def initialize_gle_map(gl_entries, filters):
def get_accountwise_gle(filters, gl_entries, gle_map):
totals = get_totals_dict()
entries = []
+ consolidated_gle = OrderedDict()
group_by = group_by_field(filters.get('group_by'))
def update_value_in_dict(data, key, gle):
@@ -310,12 +303,20 @@ def get_accountwise_gle(filters, gl_entries, gle_map):
update_value_in_dict(totals, 'total', gle)
if filters.get("group_by") != _('Group by Voucher (Consolidated)'):
gle_map[gle.get(group_by)].entries.append(gle)
- else:
- entries.append(gle)
+ elif filters.get("group_by") == _('Group by Voucher (Consolidated)'):
+ key = (gle.get("voucher_type"), gle.get("voucher_no"),
+ gle.get("account"), gle.get("cost_center"))
+ if key not in consolidated_gle:
+ consolidated_gle.setdefault(key, gle)
+ else:
+ update_value_in_dict(consolidated_gle, key, gle)
update_value_in_dict(gle_map[gle.get(group_by)].totals, 'closing', gle)
update_value_in_dict(totals, 'closing', gle)
+ for key, value in consolidated_gle.items():
+ entries.append(value)
+
return totals, entries
def get_result_as_list(data, filters):
From 16dda1a991e555b3d7cd5f6dc948d6a243cb9a84 Mon Sep 17 00:00:00 2001
From: rohitwaghchaure
Date: Tue, 20 Aug 2019 12:37:32 +0530
Subject: [PATCH 281/484] fix: group by voucher consolidated showing incorrect
data for deferred entries (#18779)
---
.../report/general_ledger/general_ledger.py | 27 ++++++++++---------
1 file changed, 14 insertions(+), 13 deletions(-)
diff --git a/erpnext/accounts/report/general_ledger/general_ledger.py b/erpnext/accounts/report/general_ledger/general_ledger.py
index 86fd1088f5..ec3fb1fc9c 100644
--- a/erpnext/accounts/report/general_ledger/general_ledger.py
+++ b/erpnext/accounts/report/general_ledger/general_ledger.py
@@ -119,19 +119,11 @@ def get_gl_entries(filters):
select_fields = """, debit, credit, debit_in_account_currency,
credit_in_account_currency """
- group_by_statement = ''
order_by_statement = "order by posting_date, account"
if filters.get("group_by") == _("Group by Voucher"):
order_by_statement = "order by posting_date, voucher_type, voucher_no"
- if filters.get("group_by") == _("Group by Voucher (Consolidated)"):
- group_by_statement = "group by voucher_type, voucher_no, account, cost_center"
-
- select_fields = """, sum(debit) as debit, sum(credit) as credit,
- sum(debit_in_account_currency) as debit_in_account_currency,
- sum(credit_in_account_currency) as credit_in_account_currency"""
-
if filters.get("include_default_book_entries"):
filters['company_fb'] = frappe.db.get_value("Company",
filters.get("company"), 'default_finance_book')
@@ -144,11 +136,10 @@ def get_gl_entries(filters):
against_voucher_type, against_voucher, account_currency,
remarks, against, is_opening {select_fields}
from `tabGL Entry`
- where company=%(company)s {conditions} {group_by_statement}
+ where company=%(company)s {conditions}
{order_by_statement}
""".format(
select_fields=select_fields, conditions=get_conditions(filters),
- group_by_statement=group_by_statement,
order_by_statement=order_by_statement
),
filters, as_dict=1)
@@ -185,7 +176,8 @@ def get_conditions(filters):
if not (filters.get("account") or filters.get("party") or
filters.get("group_by") in ["Group by Account", "Group by Party"]):
conditions.append("posting_date >=%(from_date)s")
- conditions.append("posting_date <=%(to_date)s")
+
+ conditions.append("(posting_date <=%(to_date)s or is_opening = 'Yes')")
if filters.get("project"):
conditions.append("project in %(project)s")
@@ -286,6 +278,7 @@ def initialize_gle_map(gl_entries, filters):
def get_accountwise_gle(filters, gl_entries, gle_map):
totals = get_totals_dict()
entries = []
+ consolidated_gle = OrderedDict()
group_by = group_by_field(filters.get('group_by'))
def update_value_in_dict(data, key, gle):
@@ -310,12 +303,20 @@ def get_accountwise_gle(filters, gl_entries, gle_map):
update_value_in_dict(totals, 'total', gle)
if filters.get("group_by") != _('Group by Voucher (Consolidated)'):
gle_map[gle.get(group_by)].entries.append(gle)
- else:
- entries.append(gle)
+ elif filters.get("group_by") == _('Group by Voucher (Consolidated)'):
+ key = (gle.get("voucher_type"), gle.get("voucher_no"),
+ gle.get("account"), gle.get("cost_center"))
+ if key not in consolidated_gle:
+ consolidated_gle.setdefault(key, gle)
+ else:
+ update_value_in_dict(consolidated_gle, key, gle)
update_value_in_dict(gle_map[gle.get(group_by)].totals, 'closing', gle)
update_value_in_dict(totals, 'closing', gle)
+ for key, value in consolidated_gle.items():
+ entries.append(value)
+
return totals, entries
def get_result_as_list(data, filters):
From 5cdda19494dd04f046b0ad1a2aace0e5a0a0897c Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Tue, 20 Aug 2019 13:02:40 +0530
Subject: [PATCH 282/484] fix: ledger entries after expiry
---
erpnext/patches/v12_0/generate_leave_ledger_entries.py | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/erpnext/patches/v12_0/generate_leave_ledger_entries.py b/erpnext/patches/v12_0/generate_leave_ledger_entries.py
index 44b59bf09b..5e91449c3e 100644
--- a/erpnext/patches/v12_0/generate_leave_ledger_entries.py
+++ b/erpnext/patches/v12_0/generate_leave_ledger_entries.py
@@ -3,7 +3,7 @@
from __future__ import unicode_literals
import frappe
-from frappe.utils import getdate
+from frappe.utils import getdate, today
def execute():
""" Generates leave ledger entries for leave allocation/application/encashment
@@ -66,7 +66,8 @@ def generate_expiry_allocation_ledger_entries():
if not frappe.db.exists("Leave Ledger Entry", {'transaction_type': 'Leave Allocation', 'transaction_name': allocation.name, 'is_expired': 1}):
allocation.update(dict(doctype="Leave Allocation"))
allocation_obj = frappe.get_doc(allocation)
- expire_allocation(allocation_obj)
+ if allocation_obj.to_date <= getdate(today()):
+ expire_allocation(allocation_obj)
def get_allocation_records():
return frappe.get_all("Leave Allocation", filters={
From 79414a8d36c0def8c351216124763baae95f3c13 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Tue, 20 Aug 2019 14:44:48 +0530
Subject: [PATCH 283/484] fix: fetch employee name on leave ledger creation
---
erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.json | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.json b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.json
index c11422211c..771e706bbb 100644
--- a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.json
+++ b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.json
@@ -27,6 +27,7 @@
"options": "Employee"
},
{
+ "fetch_from": "employee.employee_name",
"fieldname": "employee_name",
"fieldtype": "Data",
"label": "Employee Name"
@@ -101,7 +102,7 @@
],
"in_create": 1,
"is_submittable": 1,
- "modified": "2019-06-21 00:37:07.782810",
+ "modified": "2019-08-20 14:40:04.130799",
"modified_by": "Administrator",
"module": "HR",
"name": "Leave Ledger Entry",
From cb38cc96c36d441ccc06b1d6421b48405b24045e Mon Sep 17 00:00:00 2001
From: deepeshgarg007
Date: Tue, 20 Aug 2019 15:00:48 +0530
Subject: [PATCH 284/484] fix: Enhancement in Purchase Order
---
.../buying_settings/buying_settings.js | 8 +
.../buying_settings/buying_settings.json | 468 ++++------------
.../buying_settings/test_buying_settings.py | 10 +
.../doctype/purchase_order/purchase_order.py | 1 +
.../purchase_order_item_supplied.json | 508 ++++--------------
.../stock/doctype/stock_entry/stock_entry.py | 15 +-
.../stock_entry_detail.json | 12 +-
7 files changed, 262 insertions(+), 760 deletions(-)
create mode 100644 erpnext/buying/doctype/buying_settings/buying_settings.js
create mode 100644 erpnext/buying/doctype/buying_settings/test_buying_settings.py
diff --git a/erpnext/buying/doctype/buying_settings/buying_settings.js b/erpnext/buying/doctype/buying_settings/buying_settings.js
new file mode 100644
index 0000000000..403b1c95e7
--- /dev/null
+++ b/erpnext/buying/doctype/buying_settings/buying_settings.js
@@ -0,0 +1,8 @@
+// Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Buying Settings', {
+ // refresh: function(frm) {
+
+ // }
+});
diff --git a/erpnext/buying/doctype/buying_settings/buying_settings.json b/erpnext/buying/doctype/buying_settings/buying_settings.json
index f2eec4f722..a492519591 100644
--- a/erpnext/buying/doctype/buying_settings/buying_settings.json
+++ b/erpnext/buying/doctype/buying_settings/buying_settings.json
@@ -1,379 +1,111 @@
{
- "allow_copy": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "beta": 0,
- "creation": "2013-06-25 11:04:03",
- "custom": 0,
- "description": "Settings for Buying Module",
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "Other",
- "editable_grid": 0,
+ "creation": "2013-06-25 11:04:03",
+ "description": "Settings for Buying Module",
+ "doctype": "DocType",
+ "document_type": "Other",
+ "field_order": [
+ "supp_master_name",
+ "supplier_group",
+ "buying_price_list",
+ "column_break_3",
+ "po_required",
+ "pr_required",
+ "maintain_same_rate",
+ "allow_multiple_items",
+ "subcontract",
+ "backflush_raw_materials_of_subcontract_based_on",
+ "column_break_11",
+ "over_transfer_allowance"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "Supplier Name",
- "fieldname": "supp_master_name",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Supplier Naming By",
- "length": 0,
- "no_copy": 0,
- "options": "Supplier Name\nNaming Series",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "supplier_group",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Default Supplier Group",
- "length": 0,
- "no_copy": 0,
- "options": "Supplier Group",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "buying_price_list",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Default Buying Price List",
- "length": 0,
- "no_copy": 0,
- "options": "Price List",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_3",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "po_required",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Purchase Order Required",
- "length": 0,
- "no_copy": 0,
- "options": "No\nYes",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "pr_required",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Purchase Receipt Required",
- "length": 0,
- "no_copy": 0,
- "options": "No\nYes",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "maintain_same_rate",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Maintain same rate throughout purchase cycle",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "allow_multiple_items",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Allow Item to be added multiple times in a transaction",
- "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,
- "translatable": 0,
- "unique": 0
+ "default": "Supplier Name",
+ "fieldname": "supp_master_name",
+ "fieldtype": "Select",
+ "label": "Supplier Naming By",
+ "options": "Supplier Name\nNaming Series"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "subcontract",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Subcontract",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "supplier_group",
+ "fieldtype": "Link",
+ "label": "Default Supplier Group",
+ "options": "Supplier Group"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "Material Transferred for Subcontract",
- "fieldname": "backflush_raw_materials_of_subcontract_based_on",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Backflush Raw Materials of Subcontract Based On",
- "length": 0,
- "no_copy": 0,
- "options": "BOM\nMaterial Transferred for Subcontract",
- "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,
- "translatable": 0,
- "unique": 0
+ "fieldname": "buying_price_list",
+ "fieldtype": "Link",
+ "label": "Default Buying Price List",
+ "options": "Price List"
+ },
+ {
+ "fieldname": "column_break_3",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "po_required",
+ "fieldtype": "Select",
+ "label": "Purchase Order Required",
+ "options": "No\nYes"
+ },
+ {
+ "fieldname": "pr_required",
+ "fieldtype": "Select",
+ "label": "Purchase Receipt Required",
+ "options": "No\nYes"
+ },
+ {
+ "default": "0",
+ "fieldname": "maintain_same_rate",
+ "fieldtype": "Check",
+ "label": "Maintain same rate throughout purchase cycle"
+ },
+ {
+ "default": "0",
+ "fieldname": "allow_multiple_items",
+ "fieldtype": "Check",
+ "label": "Allow Item to be added multiple times in a transaction"
+ },
+ {
+ "fieldname": "subcontract",
+ "fieldtype": "Section Break",
+ "label": "Subcontract"
+ },
+ {
+ "default": "Material Transferred for Subcontract",
+ "fieldname": "backflush_raw_materials_of_subcontract_based_on",
+ "fieldtype": "Select",
+ "label": "Backflush Raw Materials of Subcontract Based On",
+ "options": "BOM\nMaterial Transferred for Subcontract"
+ },
+ {
+ "depends_on": "eval:doc.backflush_raw_materials_of_subcontract_based_on == \"BOM\"",
+ "description": "Percentage you are allowed to transfer more against the quantity ordered. For example: If you have ordered 100 units. and your Allowance is 10% then you are allowed to transfer 110 units.",
+ "fieldname": "over_transfer_allowance",
+ "fieldtype": "Float",
+ "label": "Over Transfer Allowance (%)"
+ },
+ {
+ "fieldname": "column_break_11",
+ "fieldtype": "Column Break"
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "icon": "fa fa-cog",
- "idx": 1,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 1,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2018-07-31 07:52:38.062488",
- "modified_by": "Administrator",
- "module": "Buying",
- "name": "Buying Settings",
- "owner": "Administrator",
+ ],
+ "icon": "fa fa-cog",
+ "idx": 1,
+ "issingle": 1,
+ "modified": "2019-08-20 13:13:09.055189",
+ "modified_by": "Administrator",
+ "module": "Buying",
+ "name": "Buying Settings",
+ "owner": "Administrator",
"permissions": [
{
- "amend": 0,
- "cancel": 0,
- "create": 1,
- "delete": 0,
- "email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 0,
- "role": "System Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
+ "create": 1,
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "role": "System Manager",
+ "share": 1,
"write": 1
}
- ],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
- "track_changes": 0,
- "track_seen": 0
-}
+ ]
+}
\ No newline at end of file
diff --git a/erpnext/buying/doctype/buying_settings/test_buying_settings.py b/erpnext/buying/doctype/buying_settings/test_buying_settings.py
new file mode 100644
index 0000000000..bf6eec67d4
--- /dev/null
+++ b/erpnext/buying/doctype/buying_settings/test_buying_settings.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+# import frappe
+import unittest
+
+class TestBuyingSettings(unittest.TestCase):
+ pass
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py
index 8117d9d514..4bd172b514 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.py
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.py
@@ -477,6 +477,7 @@ def make_rm_stock_entry(purchase_order, rm_items):
rm_item_code = rm_item_data["rm_item_code"]
items_dict = {
rm_item_code: {
+ "po_detail": rm_item_data["name"],
"item_name": rm_item_data["item_name"],
"description": item_wh.get(rm_item_code, {}).get('description', ""),
'qty': rm_item_data["qty"],
diff --git a/erpnext/buying/doctype/purchase_order_item_supplied/purchase_order_item_supplied.json b/erpnext/buying/doctype/purchase_order_item_supplied/purchase_order_item_supplied.json
index 7016853058..8435bbb06e 100644
--- a/erpnext/buying/doctype/purchase_order_item_supplied/purchase_order_item_supplied.json
+++ b/erpnext/buying/doctype/purchase_order_item_supplied/purchase_order_item_supplied.json
@@ -1,404 +1,134 @@
{
- "allow_copy": 0,
- "allow_events_in_timeline": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "beta": 0,
- "creation": "2013-02-22 01:27:42",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "editable_grid": 1,
+ "creation": "2013-02-22 01:27:42",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "field_order": [
+ "main_item_code",
+ "rm_item_code",
+ "required_qty",
+ "supplied_qty",
+ "rate",
+ "amount",
+ "column_break_6",
+ "bom_detail_no",
+ "reference_name",
+ "conversion_factor",
+ "stock_uom",
+ "reserve_warehouse"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 2,
- "fieldname": "main_item_code",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Item Code",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "main_item_code",
- "oldfieldtype": "Data",
- "options": "Item",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "columns": 2,
+ "fieldname": "main_item_code",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Item Code",
+ "oldfieldname": "main_item_code",
+ "oldfieldtype": "Data",
+ "options": "Item",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 2,
- "fieldname": "rm_item_code",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Raw Material Item Code",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "rm_item_code",
- "oldfieldtype": "Data",
- "options": "Item",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "columns": 2,
+ "fieldname": "rm_item_code",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Raw Material Item Code",
+ "oldfieldname": "rm_item_code",
+ "oldfieldtype": "Data",
+ "options": "Item",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 2,
- "fieldname": "required_qty",
- "fieldtype": "Float",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Supplied Qty",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "required_qty",
- "oldfieldtype": "Currency",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "columns": 2,
+ "fieldname": "required_qty",
+ "fieldtype": "Float",
+ "in_list_view": 1,
+ "label": "Required Qty",
+ "oldfieldname": "required_qty",
+ "oldfieldtype": "Currency",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 2,
- "fieldname": "rate",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Rate",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "rate",
- "oldfieldtype": "Currency",
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "columns": 2,
+ "fieldname": "rate",
+ "fieldtype": "Currency",
+ "in_list_view": 1,
+ "label": "Rate",
+ "oldfieldname": "rate",
+ "oldfieldtype": "Currency",
+ "options": "Company:company:default_currency"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "amount",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Amount",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "amount",
- "oldfieldtype": "Currency",
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "amount",
+ "fieldtype": "Currency",
+ "label": "Amount",
+ "oldfieldname": "amount",
+ "oldfieldtype": "Currency",
+ "options": "Company:company:default_currency",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_6",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "column_break_6",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "bom_detail_no",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "BOM Detail No",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "bom_detail_no",
- "oldfieldtype": "Data",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "bom_detail_no",
+ "fieldtype": "Data",
+ "label": "BOM Detail No",
+ "oldfieldname": "bom_detail_no",
+ "oldfieldtype": "Data",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "reference_name",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Reference Name",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "reference_name",
- "oldfieldtype": "Data",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "reference_name",
+ "fieldtype": "Data",
+ "label": "Reference Name",
+ "oldfieldname": "reference_name",
+ "oldfieldtype": "Data",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "conversion_factor",
- "fieldtype": "Float",
- "hidden": 1,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Conversion Factor",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "conversion_factor",
- "oldfieldtype": "Currency",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "conversion_factor",
+ "fieldtype": "Float",
+ "hidden": 1,
+ "label": "Conversion Factor",
+ "oldfieldname": "conversion_factor",
+ "oldfieldtype": "Currency",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "stock_uom",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Stock Uom",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "stock_uom",
- "oldfieldtype": "Data",
- "options": "UOM",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "stock_uom",
+ "fieldtype": "Link",
+ "label": "Stock Uom",
+ "oldfieldname": "stock_uom",
+ "oldfieldtype": "Data",
+ "options": "UOM",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 2,
- "fieldname": "reserve_warehouse",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Reserve Warehouse",
- "length": 0,
- "no_copy": 0,
- "options": "Warehouse",
- "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,
- "translatable": 0,
- "unique": 0
+ "columns": 2,
+ "fieldname": "reserve_warehouse",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Reserve Warehouse",
+ "options": "Warehouse"
+ },
+ {
+ "fieldname": "supplied_qty",
+ "fieldtype": "Float",
+ "in_list_view": 1,
+ "label": "Supplied Qty",
+ "read_only": 1
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 1,
- "idx": 1,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 1,
- "max_attachments": 0,
- "modified": "2019-01-07 16:51:58.016007",
- "modified_by": "Administrator",
- "module": "Buying",
- "name": "Purchase Order Item Supplied",
- "owner": "dhanalekshmi@webnotestech.com",
- "permissions": [],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
- "track_changes": 0,
- "track_seen": 0,
- "track_views": 0
+ ],
+ "hide_toolbar": 1,
+ "idx": 1,
+ "istable": 1,
+ "modified": "2019-08-20 13:37:32.702068",
+ "modified_by": "Administrator",
+ "module": "Buying",
+ "name": "Purchase Order Item Supplied",
+ "owner": "dhanalekshmi@webnotestech.com",
+ "permissions": []
}
\ No newline at end of file
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py
index b5303327f6..32a785f258 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.py
@@ -521,14 +521,20 @@ class StockEntry(StockController):
backflush_raw_materials_based_on = frappe.db.get_single_value("Buying Settings",
"backflush_raw_materials_of_subcontract_based_on")
+ qty_allowance = flt(frappe.db.get_single_value("Buying Settings",
+ "over_transfer_allowance"))
+
if (self.purpose == "Send to Subcontractor" and self.purchase_order and
backflush_raw_materials_based_on == 'BOM'):
purchase_order = frappe.get_doc("Purchase Order", self.purchase_order)
for se_item in self.items:
item_code = se_item.original_item or se_item.item_code
precision = cint(frappe.db.get_default("float_precision")) or 3
- total_allowed = sum([flt(d.required_qty) for d in purchase_order.supplied_items \
+ required_qty = sum([flt(d.required_qty) for d in purchase_order.supplied_items \
if d.rm_item_code == item_code])
+
+ total_allowed = required_qty + (required_qty * (qty_allowance/100))
+
if not total_allowed:
frappe.throw(_("Item {0} not found in 'Raw Materials Supplied' table in Purchase Order {1}")
.format(se_item.item_code, self.purchase_order))
@@ -1106,6 +1112,7 @@ class StockEntry(StockController):
se_child.allow_alternative_item = item_dict[d].get("allow_alternative_item", 0)
se_child.subcontracted_item = item_dict[d].get("main_item_code")
se_child.original_item = item_dict[d].get("original_item")
+ se_child.po_detail = item_dict[d].get("po_detail")
if item_dict[d].get("idx"):
se_child.idx = item_dict[d].get("idx")
@@ -1157,7 +1164,11 @@ class StockEntry(StockController):
where po.name = poitemsup.parent
and po.name = %s""", self.purchase_order))
- #Update reserved sub contracted quantity in bin based on Supplied Item Details
+ #Update Supplied Qty in PO Supplied Items
+ frappe.db.sql("""UPDATE `tabPurchase Order Item Supplied` pos, `tabStock Entry Detail` sed
+ SET pos.supplied_qty = sed.transfer_qty where pos.name = sed.po_detail""")
+
+ #Update reserved sub contracted quantity in bin based on Supplied Item Details and
for d in self.get("items"):
item_code = d.get('original_item') or d.get('item_code')
reserve_warehouse = item_wh.get(item_code)
diff --git a/erpnext/stock/doctype/stock_entry_detail/stock_entry_detail.json b/erpnext/stock/doctype/stock_entry_detail/stock_entry_detail.json
index 912a4651b3..d86e68b722 100644
--- a/erpnext/stock/doctype/stock_entry_detail/stock_entry_detail.json
+++ b/erpnext/stock/doctype/stock_entry_detail/stock_entry_detail.json
@@ -59,6 +59,7 @@
"reference_section",
"against_stock_entry",
"ste_detail",
+ "po_detail",
"column_break_51",
"transferred_qty",
"reference_purchase_receipt",
@@ -480,11 +481,20 @@
"label": "Project",
"options": "Project",
"read_only": 1
+ },
+ {
+ "fieldname": "po_detail",
+ "fieldtype": "Data",
+ "hidden": 1,
+ "label": "PO Supplied Item",
+ "no_copy": 1,
+ "print_hide": 1,
+ "read_only": 1
}
],
"idx": 1,
"istable": 1,
- "modified": "2019-07-12 11:34:53.190749",
+ "modified": "2019-08-20 14:01:02.319754",
"modified_by": "Administrator",
"module": "Stock",
"name": "Stock Entry Detail",
From a8403cde168982d582563e0629f4ab38b1f7bae6 Mon Sep 17 00:00:00 2001
From: Sahil Khan
Date: Tue, 20 Aug 2019 16:20:26 +0550
Subject: [PATCH 285/484] bumped to version 12.0.7
---
erpnext/__init__.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/__init__.py b/erpnext/__init__.py
index e1c3d78d3f..8c47111e01 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__ = '12.0.6'
+__version__ = '12.0.7'
def get_default_company(user=None):
'''Get default company for user'''
From 9e6abc49481f1749876b33a70e5bea8509f5f9ec Mon Sep 17 00:00:00 2001
From: deepeshgarg007
Date: Tue, 20 Aug 2019 16:14:44 +0530
Subject: [PATCH 286/484] fix: Test case fixes
---
erpnext/buying/doctype/purchase_order/purchase_order.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py
index 4bd172b514..8ad320ee47 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.py
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.py
@@ -477,7 +477,7 @@ def make_rm_stock_entry(purchase_order, rm_items):
rm_item_code = rm_item_data["rm_item_code"]
items_dict = {
rm_item_code: {
- "po_detail": rm_item_data["name"],
+ "po_detail": rm_item_data.get("name"),
"item_name": rm_item_data["item_name"],
"description": item_wh.get(rm_item_code, {}).get('description', ""),
'qty': rm_item_data["qty"],
From c9b6c9bb613cff4280d77867f6cedc1714025aa9 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Tue, 20 Aug 2019 19:18:45 +0530
Subject: [PATCH 287/484] fix: calculate opening leave balance
---
.../employee_leave_balance.py | 21 +++++++++----------
1 file changed, 10 insertions(+), 11 deletions(-)
diff --git a/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py b/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py
index 66e3614982..22f0203c90 100644
--- a/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py
+++ b/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py
@@ -97,16 +97,15 @@ def get_approvers(department):
def get_total_allocated_leaves(employee, leave_type, from_date, to_date):
''' Returns leave allocation between from date and to date '''
- filters= {
- 'from_date': ['between', (from_date, to_date)],
- 'to_date': ['between', (from_date, to_date)],
- 'docstatus': 1,
- 'is_expired': 0,
- 'leave_type': leave_type,
- 'employee': employee,
- 'transaction_type': 'Leave Allocation'
- }
-
- leave_allocation_records = frappe.db.get_all('Leave Ledger Entry', filters=filters, fields=['SUM(leaves) as leaves'])
+ leave_allocation_records = frappe.db.get_all('Leave Ledger Entry', filters={
+ 'docstatus': 1,
+ 'is_expired': 0,
+ 'leave_type': leave_type,
+ 'employee': employee,
+ 'transaction_type': 'Leave Allocation'
+ }, or_filters={
+ 'from_date': ['between', (from_date, to_date)],
+ 'to_date': ['between', (from_date, to_date)]
+ }, fields=['SUM(leaves) as leaves'])
return flt(leave_allocation_records[0].get('leaves')) if leave_allocation_records else flt(0)
\ No newline at end of file
From eab5be111018b2615844e94aa2bf6ee6b7e9dbae Mon Sep 17 00:00:00 2001
From: Shivam Mishra
Date: Tue, 20 Aug 2019 19:31:54 +0530
Subject: [PATCH 288/484] fix: shopping cart item availability
---
erpnext/templates/includes/product_page.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/templates/includes/product_page.js b/erpnext/templates/includes/product_page.js
index 65949bb18c..90a1d862c3 100644
--- a/erpnext/templates/includes/product_page.js
+++ b/erpnext/templates/includes/product_page.js
@@ -32,7 +32,7 @@ frappe.ready(function() {
if(r.message.product_info.in_stock===0) {
$(".item-stock").html(" {{ _("Not in stock") }}
");
}
- else if(r.message.product_info.in_stock===1) {
+ else if(r.message.product_info.in_stock===1 && r.message.cart_settings.show_stock_availability) {
var qty_display = "{{ _("In stock") }}";
if (r.message.product_info.show_stock_qty) {
qty_display += " ("+r.message.product_info.stock_qty+")";
From 9f4dc3fcd41a69bd3f0f11ce3172189b01a823e6 Mon Sep 17 00:00:00 2001
From: Himanshu Warekar
Date: Tue, 20 Aug 2019 22:20:02 +0530
Subject: [PATCH 289/484] fix: call popup get contact name from number
---
erpnext/crm/doctype/utils.py | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/erpnext/crm/doctype/utils.py b/erpnext/crm/doctype/utils.py
index 9cfab15995..2257ee5cce 100644
--- a/erpnext/crm/doctype/utils.py
+++ b/erpnext/crm/doctype/utils.py
@@ -1,6 +1,7 @@
import frappe
from frappe import _
import json
+from frappe.contacts.doctype.contact.contact import get_contact_with_phone_number
@frappe.whitelist()
def get_document_with_phone_number(number):
@@ -11,10 +12,10 @@ def get_document_with_phone_number(number):
'phone': ['like', '%{}'.format(number)],
'mobile_no': ['like', '%{}'.format(number)]
}
- contacts = frappe.get_all('Contact', or_filters=number_filter, limit=1)
+ contact = get_contact_with_phone_number(number)
- if contacts:
- return frappe.get_doc('Contact', contacts[0].name)
+ if contact:
+ return frappe.get_doc('Contact', contact)
leads = frappe.get_all('Lead', or_filters=number_filter, limit=1)
From d79a16c9f3c33faeb14ea35aefcf71db5f1f9ae9 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Wed, 21 Aug 2019 09:03:26 +0530
Subject: [PATCH 290/484] fix: Warehouse selection login
- Rename item_loactions -> locations, reference_items -> items
- Add customer and work_order field
- fix "Get Items" button UX
- fix get_pending_work_orders query
Co-authored-by: Nabin Hait
---
.../doctype/work_order/work_order.py | 2 +-
erpnext/stock/doctype/pick_list/pick_list.js | 61 ++++++++-------
.../stock/doctype/pick_list/pick_list.json | 63 ++++++++++-----
erpnext/stock/doctype/pick_list/pick_list.py | 76 +++++++++++--------
.../stock/doctype/pick_list/test_pick_list.py | 6 +-
5 files changed, 126 insertions(+), 82 deletions(-)
diff --git a/erpnext/manufacturing/doctype/work_order/work_order.py b/erpnext/manufacturing/doctype/work_order/work_order.py
index c653deece3..988cd223f2 100644
--- a/erpnext/manufacturing/doctype/work_order/work_order.py
+++ b/erpnext/manufacturing/doctype/work_order/work_order.py
@@ -710,7 +710,7 @@ def get_work_order_operation_data(work_order, operation, workstation):
return d
@frappe.whitelist()
-def make_pick_list(source_name, target_doc=None):
+def create_pick_list(source_name, target_doc=None):
def update_item_quantity(source, target, source_parent):
qty = source.required_qty - source.transferred_qty
target.qty = qty
diff --git a/erpnext/stock/doctype/pick_list/pick_list.js b/erpnext/stock/doctype/pick_list/pick_list.js
index b9b317b732..bd893aafd0 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.js
+++ b/erpnext/stock/doctype/pick_list/pick_list.js
@@ -11,17 +11,33 @@ frappe.ui.form.on('Pick List', {
}
};
});
+ frm.set_query('work_order', () => {
+ return {
+ query: 'erpnext.stock.doctype.pick_list.pick_list.get_pending_work_orders',
+ filters: {
+ 'company': frm.doc.company
+ }
+ };
+ });
},
refresh: (frm) => {
- frm.add_custom_button(__('Delivery Note'), () => frm.trigger('make_delivery_note'), __('Create'));
+ frm.trigger('add_get_items_button');
- if (frm.doc.reference_items && frm.doc.reference_items.length) {
+ if (frm.doc.items && (frm.doc.items.length > 1 || frm.doc.items[0].item_code)) {
frm.add_custom_button(__('Get Item Locations'), () => {
frm.call('set_item_locations');
- });
+ }).addClass('btn-primary');
}
- frm.trigger('add_get_items_button');
+ frm.add_custom_button(__('Delivery Note'), () => frm.trigger('make_delivery_note'), __('Create'));
+ },
+ work_order: (frm) => {
+ frm.clear_table('items');
+ erpnext.utils.map_current_doc({
+ method: 'erpnext.manufacturing.doctype.work_order.work_order.create_pick_list',
+ target: frm,
+ source_name: frm.doc.work_order
+ });
},
items_based_on: (frm) => {
frm.trigger('add_get_items_button');
@@ -33,40 +49,29 @@ frappe.ui.form.on('Pick List', {
});
},
add_get_items_button(frm) {
- frm.remove_custom_button(__("Get items"));
let source_doctype = frm.doc.items_based_on;
- let date_field = 'transaction_date';
- let get_query_method = null;
+ if (source_doctype != 'Sales Order') return;
let get_query_filters = {
docstatus: 1,
per_delivered: ['<', 100],
- status: ['!=', '']
+ status: ['!=', ''],
+ customer: frm.doc.customer
};
- let method = 'erpnext.selling.doctype.sales_order.sales_order.make_pick_list';
- if (source_doctype === 'Work Order') {
- method = 'erpnext.manufacturing.doctype.work_order.work_order.make_pick_list';
- date_field = 'planned_start_date';
- get_query_method = 'erpnext.stock.doctype.pick_list.pick_list.get_pending_work_orders';
- get_query_filters = null;
- }
-
- let get_query = () => {
- return {
- 'query': get_query_method,
- 'filters': get_query_filters
- };
- };
-
- frm.add_custom_button(__("Get items"), () => {
+ frm.get_items_btn = frm.add_custom_button(__('Get Items'), () => {
+ if (!frm.doc.customer) {
+ frappe.msgprint(__('Please select Customer first'));
+ return;
+ }
erpnext.utils.map_current_doc({
- method: method,
- source_doctype: source_doctype,
+ method: 'erpnext.selling.doctype.sales_order.sales_order.make_pick_list',
+ source_doctype: 'Sales Order',
target: frm,
setters: {
company: frm.doc.company,
+ customer: frm.doc.customer
},
- date_field: date_field,
- get_query: get_query
+ date_field: 'transaction_date',
+ get_query_filters: get_query_filters
});
});
}
diff --git a/erpnext/stock/doctype/pick_list/pick_list.json b/erpnext/stock/doctype/pick_list/pick_list.json
index 70272bf584..1a33622167 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.json
+++ b/erpnext/stock/doctype/pick_list/pick_list.json
@@ -5,21 +5,25 @@
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
- "company",
- "column_break_4",
"items_based_on",
+ "customer",
+ "work_order",
+ "column_break_4",
"parent_warehouse",
+ "company",
"section_break_4",
- "reference_items",
+ "items",
"section_break_6",
- "item_locations"
+ "locations"
],
"fields": [
{
"fieldname": "company",
"fieldtype": "Link",
+ "in_list_view": 1,
"label": "Company",
- "options": "Company"
+ "options": "Company",
+ "reqd": 1
},
{
"fieldname": "column_break_4",
@@ -41,26 +45,45 @@
"options": "Warehouse"
},
{
- "fieldname": "item_locations",
+ "default": "Work Order",
+ "fieldname": "items_based_on",
+ "fieldtype": "Select",
+ "in_list_view": 1,
+ "label": "Items Based On",
+ "options": "Sales Order\nWork Order",
+ "reqd": 1
+ },
+ {
+ "depends_on": "eval:doc.items_based_on===\"Sales Order\"",
+ "fieldname": "customer",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Customer",
+ "options": "Customer",
+ "reqd": 1
+ },
+ {
+ "depends_on": "eval:doc.items_based_on===\"Work Order\"",
+ "fieldname": "work_order",
+ "fieldtype": "Link",
+ "label": "Work Order",
+ "options": "Work Order"
+ },
+ {
+ "fieldname": "items",
+ "fieldtype": "Table",
+ "label": "Items To Be Picked",
+ "options": "Pick List Reference Item",
+ "reqd": 1
+ },
+ {
+ "fieldname": "locations",
"fieldtype": "Table",
"label": "Item Locations",
"options": "Pick List Item"
- },
- {
- "fieldname": "reference_items",
- "fieldtype": "Table",
- "label": "Items To Be Picked",
- "options": "Pick List Reference Item"
- },
- {
- "default": "Sales Order",
- "fieldname": "items_based_on",
- "fieldtype": "Select",
- "label": "Items Based On",
- "options": "Sales Order\nWork Order"
}
],
- "modified": "2019-08-19 12:31:54.023456",
+ "modified": "2019-08-20 16:57:11.006221",
"modified_by": "Administrator",
"module": "Stock",
"name": "Pick List",
diff --git a/erpnext/stock/doctype/pick_list/pick_list.py b/erpnext/stock/doctype/pick_list/pick_list.py
index 91bdcb33ee..8699ee6e19 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.py
+++ b/erpnext/stock/doctype/pick_list/pick_list.py
@@ -14,25 +14,29 @@ from erpnext.selling.doctype.sales_order.sales_order import make_delivery_note a
class PickList(Document):
def set_item_locations(self):
- reference_items = self.reference_items
+ items = self.items
+ self.item_location_map = frappe._dict()
from_warehouses = None
if self.parent_warehouse:
from_warehouses = frappe.db.get_descendants('Warehouse', self.parent_warehouse)
# Reset
- self.delete_key('item_locations')
- for item_doc in reference_items:
- if frappe.get_cached_value('Item', item_doc.item_code, 'has_serial_no'):
- item_locations = get_item_locations_based_on_serial_nos(item_doc)
- elif frappe.get_cached_value('Item', item_doc.item_code, 'has_batch_no'):
- item_locations = get_item_locations_based_on_batch_nos(item_doc)
+ self.delete_key('locations')
+ for item_doc in items:
+ item_code = item_doc.item_code
+ if frappe.get_cached_value('Item', item_code, 'has_serial_no'):
+ locations = get_item_locations_based_on_serial_nos(item_doc)
+ elif frappe.get_cached_value('Item', item_code, 'has_batch_no'):
+ locations = get_item_locations_based_on_batch_nos(item_doc)
else:
- item_locations = get_items_with_warehouse_and_quantity(item_doc, from_warehouses)
+ if item_code not in self.item_location_map:
+ self.item_location_map[item_code] = get_available_items(item_code, from_warehouses)
+ locations = get_items_with_warehouse_and_quantity(item_doc, from_warehouses, self.item_location_map)
- for row in item_locations:
+ for row in locations:
row.update({
- 'item_code': item_doc.item_code,
+ 'item_code': item_code,
'sales_order': item_doc.sales_order,
'sales_order_item': item_doc.sales_order_item,
'uom': item_doc.uom,
@@ -41,14 +45,15 @@ class PickList(Document):
'stock_qty': row.get("qty", 0) * item_doc.conversion_factor,
'picked_qty': row.get("qty", 0) * item_doc.conversion_factor
})
- self.append('item_locations', row)
+ self.append('locations', row)
-def get_items_with_warehouse_and_quantity(item_doc, from_warehouses):
- item_locations = []
- item_location_map = get_available_items(item_doc.item_code, from_warehouses)
+def get_items_with_warehouse_and_quantity(item_doc, from_warehouses, item_location_map):
+ available_locations = item_location_map.get(item_doc.item_code)
+
+ locations = []
remaining_stock_qty = item_doc.stock_qty
- while remaining_stock_qty > 0 and item_location_map:
- item_location = item_location_map.pop(0)
+ while remaining_stock_qty > 0 and available_locations:
+ item_location = available_locations.pop(0)
stock_qty = remaining_stock_qty if item_location.qty >= remaining_stock_qty else item_location.qty
qty = stock_qty / (item_doc.conversion_factor or 1)
@@ -57,16 +62,25 @@ def get_items_with_warehouse_and_quantity(item_doc, from_warehouses):
qty = floor(qty)
stock_qty = qty * item_doc.conversion_factor
- item_locations.append({
+ locations.append({
'qty': qty,
'warehouse': item_location.warehouse
})
remaining_stock_qty -= stock_qty
+ qty_diff = item_location.qty - stock_qty
+ # if extra quantity is available push current warehouse to available locations
+ if qty_diff:
+ item_location.qty = qty_diff
+ available_locations = [item_location] + available_locations
+
if remaining_stock_qty:
frappe.msgprint('{0} {1} of {2} is not available.'
.format(remaining_stock_qty / item_doc.conversion_factor, item_doc.uom, item_doc.item_code))
- return item_locations
+
+ # update available locations for the item
+ item_location_map[item_doc.item_code] = available_locations
+ return locations
def get_available_items(item_code, from_warehouses):
# gets all items available in different warehouses
@@ -110,15 +124,15 @@ def get_item_locations_based_on_serial_nos(item_doc):
for serial_no, warehouse in serial_nos:
warehouse_serial_nos_map.setdefault(warehouse, []).append(serial_no)
- item_locations = []
+ locations = []
for warehouse, serial_nos in iteritems(warehouse_serial_nos_map):
- item_locations.append({
+ locations.append({
'qty': len(serial_nos),
'warehouse': warehouse,
'serial_no': '\n'.join(serial_nos)
})
- return item_locations
+ return locations
def get_item_locations_based_on_batch_nos(item_doc):
batch_qty = frappe.db.sql("""
@@ -143,7 +157,7 @@ def get_item_locations_based_on_batch_nos(item_doc):
'today': today()
}, as_dict=1)
- item_locations = []
+ locations = []
required_qty = item_doc.qty
for d in batch_qty:
if d.qty > required_qty:
@@ -151,7 +165,7 @@ def get_item_locations_based_on_batch_nos(item_doc):
else:
required_qty -= d.qty
- item_locations.append(d)
+ locations.append(d)
if required_qty <= 0:
break
@@ -159,12 +173,12 @@ def get_item_locations_based_on_batch_nos(item_doc):
if required_qty:
frappe.msgprint('No batches found for {} qty of {}.'.format(required_qty, item_doc.item_code))
- return item_locations
+ return locations
@frappe.whitelist()
def make_delivery_note(source_name, target_doc=None):
pick_list = frappe.get_doc('Pick List', source_name)
- sales_orders = [d.sales_order for d in pick_list.item_locations]
+ sales_orders = [d.sales_order for d in pick_list.locations]
sales_orders = set(sales_orders)
delivery_note = None
@@ -172,7 +186,7 @@ def make_delivery_note(source_name, target_doc=None):
delivery_note = make_delivery_note_from_sales_order(sales_order,
delivery_note, skip_item_mapping=True)
- for location in pick_list.item_locations:
+ for location in pick_list.locations:
sales_order_item = frappe.get_cached_doc('Sales Order Item', location.sales_order_item)
item_table_mapper = {
"doctype": "Delivery Note Item",
@@ -232,10 +246,11 @@ def get_pending_work_orders(doctype, txt, searchfield, start, page_length, filte
FROM
`tabWork Order`
WHERE
- `qty` > `produced_qty`
- AND `status` not in ('Completed', 'Stopped')
- AND name like %(txt)s
- AND docstatus = 1
+ `status` not in ('Completed', 'Stopped')
+ AND `qty` > `produced_qty`
+ AND `docstatus` = 1
+ AND `company` = %(company)s
+ AND `name` like %(txt)s
ORDER BY
if(locate(%(_txt)s, name), locate(%(_txt)s, name), 99999), name
LIMIT
@@ -245,4 +260,5 @@ def get_pending_work_orders(doctype, txt, searchfield, start, page_length, filte
'_txt': txt.replace('%', ''),
'start': start,
'page_length': frappe.utils.cint(page_length),
+ 'company': filters.get('company')
}, as_dict=as_dict)
diff --git a/erpnext/stock/doctype/pick_list/test_pick_list.py b/erpnext/stock/doctype/pick_list/test_pick_list.py
index ed4b6b58cc..4048e5d0b0 100644
--- a/erpnext/stock/doctype/pick_list/test_pick_list.py
+++ b/erpnext/stock/doctype/pick_list/test_pick_list.py
@@ -14,7 +14,7 @@ class TestPickList(unittest.TestCase):
pick_list = frappe.get_doc({
'doctype': 'Pick List',
'company': '_Test Company',
- 'reference_items': [{
+ 'items': [{
'item': '_Test Item Home Desktop 100',
'reference_doctype': 'Sales Order',
'qty': 5,
@@ -32,7 +32,7 @@ class TestPickList(unittest.TestCase):
pick_list = frappe.get_doc({
'doctype': 'Pick List',
'company': '_Test Company',
- 'reference_items': [{
+ 'items': [{
'item': '_Test Item Warehouse Group Wise Reorder',
'reference_doctype': 'Sales Order',
'qty': 1000,
@@ -68,7 +68,7 @@ class TestPickList(unittest.TestCase):
pick_list = frappe.get_doc({
'doctype': 'Pick List',
'company': '_Test Company',
- 'reference_items': [{
+ 'items': [{
'item': '_Test Serialized Item',
'reference_doctype': 'Sales Order',
'qty': 1000,
From 6affeaa9c1a80b1ad5024435bcd814b38412873d Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Wed, 21 Aug 2019 09:14:56 +0530
Subject: [PATCH 291/484] fix: check if number exists after striping '0'
- Absract number striping logic to separate method
- Rename a confusing variable name
- Remove leftout print statement
---
.../doctype/call_log/call_log.py | 31 +++++++++++--------
erpnext/crm/doctype/utils.py | 9 ++++++
2 files changed, 27 insertions(+), 13 deletions(-)
diff --git a/erpnext/communication/doctype/call_log/call_log.py b/erpnext/communication/doctype/call_log/call_log.py
index c9fdfbe447..00464170f3 100644
--- a/erpnext/communication/doctype/call_log/call_log.py
+++ b/erpnext/communication/doctype/call_log/call_log.py
@@ -6,15 +6,13 @@ from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.model.document import Document
-from erpnext.crm.doctype.utils import get_scheduled_employees_for_popup
+from erpnext.crm.doctype.utils import get_scheduled_employees_for_popup, strip_number
from frappe.contacts.doctype.contact.contact import get_contact_with_phone_number
from erpnext.crm.doctype.lead.lead import get_lead_with_phone_number
class CallLog(Document):
def before_insert(self):
- # strip 0 from the start of the number for proper number comparisions
- # eg. 07888383332 should match with 7888383332
- number = self.get('from').lstrip('0')
+ number = strip_number(self.get('from'))
self.contact = get_contact_with_phone_number(number)
self.lead = get_lead_with_phone_number(number)
@@ -48,13 +46,14 @@ def add_call_summary(call_log, summary):
doc.add_comment('Comment', frappe.bold(_('Call Summary')) + ' ' + summary)
def get_employees_with_number(number):
+ number = strip_number(number)
if not number: return []
employee_emails = frappe.cache().hget('employees_with_number', number)
if employee_emails: return employee_emails
employees = frappe.get_all('Employee', filters={
- 'cell_number': ['like', '%{}'.format(number.lstrip('0'))],
+ 'cell_number': ['like', '%{}'.format(number)],
'user_id': ['!=', '']
}, fields=['user_id'])
@@ -64,23 +63,29 @@ def get_employees_with_number(number):
return employee
def set_caller_information(doc, state):
- '''Called from hoooks on creation of Lead or Contact'''
+ '''Called from hooks on creation of Lead or Contact'''
if doc.doctype not in ['Lead', 'Contact']: return
numbers = [doc.get('phone'), doc.get('mobile_no')]
- for_doc = doc.doctype.lower()
+ # contact for Contact and lead for Lead
+ fieldname = doc.doctype.lower()
+
+ # contact_name or lead_name
+ display_name_field = '{}_name'.format(fieldname)
for number in numbers:
+ number = strip_number(number)
if not number: continue
- print(number)
+
filters = frappe._dict({
- 'from': ['like', '%{}'.format(number.lstrip('0'))],
- for_doc: ''
+ 'from': ['like', '%{}'.format(number)],
+ fieldname: ''
})
logs = frappe.get_all('Call Log', filters=filters)
for log in logs:
- call_log = frappe.get_doc('Call Log', log.name)
- call_log.set(for_doc, doc.name)
- call_log.save(ignore_permissions=True)
+ frappe.db.set_value('Call Log', log.name, {
+ fieldname: doc.name,
+ display_name_field: doc.get_title()
+ }, update_modified=False)
diff --git a/erpnext/crm/doctype/utils.py b/erpnext/crm/doctype/utils.py
index 55532761c2..535458af21 100644
--- a/erpnext/crm/doctype/utils.py
+++ b/erpnext/crm/doctype/utils.py
@@ -54,6 +54,8 @@ def get_last_issue_from_customer(customer_name):
def get_scheduled_employees_for_popup(communication_medium):
+ if not communication_medium: return []
+
now_time = frappe.utils.nowtime()
weekday = frappe.utils.get_weekday()
@@ -73,3 +75,10 @@ def get_scheduled_employees_for_popup(communication_medium):
employee_emails = set([employee.user_id for employee in employees])
return employee_emails
+
+def strip_number(number):
+ if not number: return
+ # strip 0 from the start of the number for proper number comparisions
+ # eg. 07888383332 should match with 7888383332
+ number = number.lstrip('0')
+ return number
\ No newline at end of file
From c6e02e2a74995f9eeb8dc96ff501223e22bf5f15 Mon Sep 17 00:00:00 2001
From: Himanshu Warekar
Date: Wed, 21 Aug 2019 13:36:41 +0530
Subject: [PATCH 292/484] fix: make contact structure call popup compatible
---
erpnext/communication/doctype/call_log/call_log.py | 6 +++++-
erpnext/crm/doctype/utils.py | 1 -
.../doctype/exotel_settings/exotel_settings.py | 1 -
3 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/erpnext/communication/doctype/call_log/call_log.py b/erpnext/communication/doctype/call_log/call_log.py
index c9fdfbe447..88965def45 100644
--- a/erpnext/communication/doctype/call_log/call_log.py
+++ b/erpnext/communication/doctype/call_log/call_log.py
@@ -70,9 +70,13 @@ def set_caller_information(doc, state):
numbers = [doc.get('phone'), doc.get('mobile_no')]
for_doc = doc.doctype.lower()
+ # Contact now has all the nos saved in child table
+ if doc.doctype == 'Contact':
+ numbers = [nos.phone for nos in doc.phone_nos]
+
for number in numbers:
if not number: continue
- print(number)
+
filters = frappe._dict({
'from': ['like', '%{}'.format(number.lstrip('0'))],
for_doc: ''
diff --git a/erpnext/crm/doctype/utils.py b/erpnext/crm/doctype/utils.py
index 756b0a2fc8..55532761c2 100644
--- a/erpnext/crm/doctype/utils.py
+++ b/erpnext/crm/doctype/utils.py
@@ -1,7 +1,6 @@
import frappe
from frappe import _
import json
-from frappe.contacts.doctype.contact.contact import get_contact_with_phone_number
@frappe.whitelist()
def get_last_interaction(contact=None, lead=None):
diff --git a/erpnext/erpnext_integrations/doctype/exotel_settings/exotel_settings.py b/erpnext/erpnext_integrations/doctype/exotel_settings/exotel_settings.py
index 77de84ce5c..6a846efad7 100644
--- a/erpnext/erpnext_integrations/doctype/exotel_settings/exotel_settings.py
+++ b/erpnext/erpnext_integrations/doctype/exotel_settings/exotel_settings.py
@@ -3,7 +3,6 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-# import frappe
from frappe.model.document import Document
import requests
import frappe
From e9e0c0e7d4b8eb40172bbf74e70fdef4bc02304d Mon Sep 17 00:00:00 2001
From: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com>
Date: Wed, 21 Aug 2019 14:40:35 +0530
Subject: [PATCH 293/484] fix: Minor fix in GSTR-1 report (#18797)
---
erpnext/regional/report/gstr_1/gstr_1.py | 18 +++---------------
1 file changed, 3 insertions(+), 15 deletions(-)
diff --git a/erpnext/regional/report/gstr_1/gstr_1.py b/erpnext/regional/report/gstr_1/gstr_1.py
index 2da1085732..c397133f33 100644
--- a/erpnext/regional/report/gstr_1/gstr_1.py
+++ b/erpnext/regional/report/gstr_1/gstr_1.py
@@ -156,33 +156,21 @@ class Gstr1Report(object):
if self.filters.get("type_of_business") == "B2B":
- customers = frappe.get_all("Customer",
- filters={
- "gst_category": ["in", ["Registered Regular", "Deemed Export", "SEZ"]]
- })
-
- if customers:
- conditions += """ and ifnull(gst_category, '') != 'Overseas' and is_return != 1
- and customer in ({0})""".format(", ".join([frappe.db.escape(c.name) for c in customers]))
+ conditions += "and ifnull(gst_category, '') in ('Registered Regular', 'Deemed Export', 'SEZ') and is_return != 1"
if self.filters.get("type_of_business") in ("B2C Large", "B2C Small"):
b2c_limit = frappe.db.get_single_value('GST Settings', 'b2c_limit')
if not b2c_limit:
frappe.throw(_("Please set B2C Limit in GST Settings."))
- customers = frappe.get_all("Customer",
- filters={
- "gst_category": ["in", ["Unregistered"]]
- })
-
if self.filters.get("type_of_business") == "B2C Large" and customers:
conditions += """ and SUBSTR(place_of_supply, 1, 2) != SUBSTR(company_gstin, 1, 2)
- and grand_total > {0} and is_return != 1 and customer in ({1})""".\
+ and grand_total > {0} and is_return != 1 and gst_category ='Unregistered' """.\
format(flt(b2c_limit), ", ".join([frappe.db.escape(c.name) for c in customers]))
elif self.filters.get("type_of_business") == "B2C Small" and customers:
conditions += """ and (
SUBSTR(place_of_supply, 1, 2) = SUBSTR(company_gstin, 1, 2)
- or grand_total <= {0}) and is_return != 1 and customer in ({1})""".\
+ or grand_total <= {0}) and is_return != 1 and gst_category ='Unregistered' """.\
format(flt(b2c_limit), ", ".join([frappe.db.escape(c.name) for c in customers]))
elif self.filters.get("type_of_business") == "CDNR":
From bcb0f6038e0742d73888720c2fafc4609ac3aa6a Mon Sep 17 00:00:00 2001
From: Nabin Hait
Date: Wed, 21 Aug 2019 14:47:33 +0530
Subject: [PATCH 294/484] fix: Single gl entry should only be considered once
either in opening or closing entry (#18792)
---
.../report/accounts_receivable/accounts_receivable.py | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
index 97e710450c..0e4ee12548 100755
--- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
+++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
@@ -197,8 +197,10 @@ class ReceivablePayableReport(object):
if self.filters.based_on_payment_terms and gl_entries_data:
self.payment_term_map = self.get_payment_term_detail(voucher_nos)
+ self.gle_inclusion_map = {}
for gle in gl_entries_data:
if self.is_receivable_or_payable(gle, self.dr_or_cr, future_vouchers, return_entries):
+ self.gle_inclusion_map[gle.name] = True
outstanding_amount, credit_note_amount, payment_amount = self.get_outstanding_amount(
gle,self.filters.report_date, self.dr_or_cr, return_entries)
temp_outstanding_amt = outstanding_amount
@@ -409,7 +411,9 @@ class ReceivablePayableReport(object):
for e in self.get_gl_entries_for(gle.party, gle.party_type, gle.voucher_type, gle.voucher_no):
if getdate(e.posting_date) <= report_date \
and (e.name!=gle.name or (e.voucher_no in return_entries and not return_entries.get(e.voucher_no))):
-
+ if e.name!=gle.name and self.gle_inclusion_map.get(e.name):
+ continue
+ self.gle_inclusion_map[e.name] = True
amount = flt(e.get(reverse_dr_or_cr), self.currency_precision) - flt(e.get(dr_or_cr), self.currency_precision)
if e.voucher_no not in return_entries:
payment_amount += amount
From 5619db28cba2b1e5dcf31e23ecfa193f09d5f732 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Wed, 21 Aug 2019 14:49:24 +0530
Subject: [PATCH 295/484] fix: fetch capital work in progress as expense
account (#18780)
---
erpnext/controllers/queries.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/controllers/queries.py b/erpnext/controllers/queries.py
index 57c063a72a..19ec053e74 100644
--- a/erpnext/controllers/queries.py
+++ b/erpnext/controllers/queries.py
@@ -371,7 +371,7 @@ def get_expense_account(doctype, txt, searchfield, start, page_len, filters):
return frappe.db.sql("""select tabAccount.name from `tabAccount`
where (tabAccount.report_type = "Profit and Loss"
- or tabAccount.account_type in ("Expense Account", "Fixed Asset", "Temporary", "Asset Received But Not Billed"))
+ or tabAccount.account_type in ("Expense Account", "Fixed Asset", "Temporary", "Asset Received But Not Billed", "Capital Work in Progress"))
and tabAccount.is_group=0
and tabAccount.docstatus!=2
and tabAccount.{key} LIKE %(txt)s
From 109a07b8344df9c2420c2cea7f9bd6419284c920 Mon Sep 17 00:00:00 2001
From: Suraj Shetty <13928957+surajshetty3416@users.noreply.github.com>
Date: Wed, 21 Aug 2019 15:19:08 +0530
Subject: [PATCH 296/484] fix: Fix get_employees_with_number query
if the passed number is 7039392929 then it should match
with the employee cell_number set as `7039392929, 0288382222`
---
erpnext/communication/doctype/call_log/call_log.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/communication/doctype/call_log/call_log.py b/erpnext/communication/doctype/call_log/call_log.py
index 00464170f3..2343632719 100644
--- a/erpnext/communication/doctype/call_log/call_log.py
+++ b/erpnext/communication/doctype/call_log/call_log.py
@@ -53,7 +53,7 @@ def get_employees_with_number(number):
if employee_emails: return employee_emails
employees = frappe.get_all('Employee', filters={
- 'cell_number': ['like', '%{}'.format(number)],
+ 'cell_number': ['like', '%{}%'.format(number)],
'user_id': ['!=', '']
}, fields=['user_id'])
From 81f20891c14432f3c6a4c413d7d13d289e6b8914 Mon Sep 17 00:00:00 2001
From: Himanshu Warekar
Date: Wed, 21 Aug 2019 16:09:35 +0530
Subject: [PATCH 297/484] fix: query
---
erpnext/communication/doctype/call_log/call_log.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/communication/doctype/call_log/call_log.py b/erpnext/communication/doctype/call_log/call_log.py
index 88965def45..29342042ff 100644
--- a/erpnext/communication/doctype/call_log/call_log.py
+++ b/erpnext/communication/doctype/call_log/call_log.py
@@ -54,7 +54,7 @@ def get_employees_with_number(number):
if employee_emails: return employee_emails
employees = frappe.get_all('Employee', filters={
- 'cell_number': ['like', '%{}'.format(number.lstrip('0'))],
+ 'cell_number': ['like', '{}'.format(number.lstrip('0'))],
'user_id': ['!=', '']
}, fields=['user_id'])
From 298d38cde3c8a5d74ee9ddb61464f4911f70ee92 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Wed, 21 Aug 2019 16:37:49 +0530
Subject: [PATCH 298/484] test: Fix existing tests
---
.../stock/doctype/pick_list/test_pick_list.py | 57 +++++++++++--------
1 file changed, 34 insertions(+), 23 deletions(-)
diff --git a/erpnext/stock/doctype/pick_list/test_pick_list.py b/erpnext/stock/doctype/pick_list/test_pick_list.py
index 4048e5d0b0..df42ff1256 100644
--- a/erpnext/stock/doctype/pick_list/test_pick_list.py
+++ b/erpnext/stock/doctype/pick_list/test_pick_list.py
@@ -14,37 +14,44 @@ class TestPickList(unittest.TestCase):
pick_list = frappe.get_doc({
'doctype': 'Pick List',
'company': '_Test Company',
+ 'customer': '_Test Customer',
+ 'items_based_on': 'Sales Order',
'items': [{
- 'item': '_Test Item Home Desktop 100',
- 'reference_doctype': 'Sales Order',
+ 'item_code': '_Test Item Home Desktop 100',
'qty': 5,
- 'reference_name': '_T-Sales Order-1',
- }],
+ 'stock_qty': 5,
+ 'conversion_factor': 1,
+ 'sales_order': '_T-Sales Order-1',
+ 'sales_item': '_T-Sales Order-1_item',
+ }]
})
-
pick_list.set_item_locations()
- self.assertEqual(pick_list.items_locations[0].item, '_Test Item Home Desktop 100')
- self.assertEqual(pick_list.items_locations[0].warehouse, '_Test Warehouse - _TC')
- self.assertEqual(pick_list.items_locations[0].qty, 5)
+ self.assertEqual(pick_list.locations[0].item_code, '_Test Item Home Desktop 100')
+ self.assertEqual(pick_list.locations[0].warehouse, '_Test Warehouse - _TC')
+ self.assertEqual(pick_list.locations[0].qty, 5)
def test_pick_list_skips_out_of_stock_item(self):
pick_list = frappe.get_doc({
'doctype': 'Pick List',
'company': '_Test Company',
+ 'customer': '_Test Customer',
+ 'items_based_on': 'Sales Order',
'items': [{
- 'item': '_Test Item Warehouse Group Wise Reorder',
- 'reference_doctype': 'Sales Order',
+ 'item_code': '_Test Item Warehouse Group Wise Reorder',
'qty': 1000,
- 'reference_name': '_T-Sales Order-1',
- }],
+ 'stock_qty': 1000,
+ 'conversion_factor': 1,
+ 'sales_order': '_T-Sales Order-1',
+ 'sales_item': '_T-Sales Order-1_item',
+ }]
})
pick_list.set_item_locations()
- self.assertEqual(pick_list.items_locations[0].item, '_Test Item Warehouse Group Wise Reorder')
- self.assertEqual(pick_list.items_locations[0].warehouse, '_Test Warehouse Group-C1 - _TC')
- self.assertEqual(pick_list.items_locations[0].qty, 30)
+ self.assertEqual(pick_list.locations[0].item_code, '_Test Item Warehouse Group Wise Reorder')
+ self.assertEqual(pick_list.locations[0].warehouse, '_Test Warehouse Group-C1 - _TC')
+ self.assertEqual(pick_list.locations[0].qty, 30)
def test_pick_list_skips_items_in_expired_batch(self):
@@ -68,19 +75,23 @@ class TestPickList(unittest.TestCase):
pick_list = frappe.get_doc({
'doctype': 'Pick List',
'company': '_Test Company',
+ 'customer': '_Test Customer',
+ 'items_based_on': 'Sales Order',
'items': [{
- 'item': '_Test Serialized Item',
- 'reference_doctype': 'Sales Order',
+ 'item_code': '_Test Serialized Item',
'qty': 1000,
- 'reference_name': '_T-Sales Order-1',
- }],
+ 'stock_qty': 1000,
+ 'conversion_factor': 1,
+ 'sales_order': '_T-Sales Order-1',
+ 'sales_item': '_T-Sales Order-1_item',
+ }]
})
pick_list.set_item_locations()
- self.assertEqual(pick_list.items_locations[0].item, '_Test Serialized Item')
- self.assertEqual(pick_list.items_locations[0].warehouse, '_Test Warehouse Group-C1 - _TC')
- self.assertEqual(pick_list.items_locations[0].qty, 30)
- self.assertEqual(pick_list.items_locations[0].serial_no, 30)
+ self.assertEqual(pick_list.locations[0].item_code, '_Test Serialized Item')
+ self.assertEqual(pick_list.locations[0].warehouse, '_Test Warehouse - _TC')
+ self.assertEqual(pick_list.locations[0].qty, 5)
+ self.assertEqual(pick_list.locations[0].serial_no, '123450\n123451\n123452\n123453\n123454')
def test_pick_list_for_multiple_reference_doctypes(self):
From a6c6e02c492568b65fe910a1f15966ae29d1e3cf Mon Sep 17 00:00:00 2001
From: Anastes Mp
Date: Wed, 21 Aug 2019 16:53:06 +0530
Subject: [PATCH 299/484] Incorrect database table (#18558)
Fixed Unknow Column tax_type error on offline pos
---
erpnext/accounts/doctype/sales_invoice/pos.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/accounts/doctype/sales_invoice/pos.py b/erpnext/accounts/doctype/sales_invoice/pos.py
index e2f99d6ea3..479548c6e3 100755
--- a/erpnext/accounts/doctype/sales_invoice/pos.py
+++ b/erpnext/accounts/doctype/sales_invoice/pos.py
@@ -307,7 +307,7 @@ def get_item_tax_data():
# example: {'Consulting Services': {'Excise 12 - TS': '12.000'}}
itemwise_tax = {}
- taxes = frappe.db.sql(""" select parent, tax_type, tax_rate from `tabItem Tax`""", as_dict=1)
+ taxes = frappe.db.sql(""" select parent, tax_type, tax_rate from `tabItem Tax Template Detail`""", as_dict=1)
for tax in taxes:
if tax.parent not in itemwise_tax:
From ec92486377fa7e8a1a56ca65129d00f2bec4220a Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Wed, 21 Aug 2019 22:10:27 +0530
Subject: [PATCH 300/484] fix: Add option to create Stock Entry from Pick List
---
erpnext/stock/doctype/pick_list/pick_list.js | 22 ++++-
erpnext/stock/doctype/pick_list/pick_list.py | 88 ++++++++++++++------
2 files changed, 80 insertions(+), 30 deletions(-)
diff --git a/erpnext/stock/doctype/pick_list/pick_list.js b/erpnext/stock/doctype/pick_list/pick_list.js
index bd893aafd0..08a388872d 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.js
+++ b/erpnext/stock/doctype/pick_list/pick_list.js
@@ -28,8 +28,11 @@ frappe.ui.form.on('Pick List', {
frm.call('set_item_locations');
}).addClass('btn-primary');
}
-
- frm.add_custom_button(__('Delivery Note'), () => frm.trigger('make_delivery_note'), __('Create'));
+ if (frm.doc.items_based_on === 'Sales Order') {
+ frm.add_custom_button(__('Delivery Note'), () => frm.trigger('create_delivery_note'), __('Create'));
+ } else {
+ frm.add_custom_button(__('Stock Entry'), () => frm.trigger('create_stock_entry'), __('Create'));
+ }
},
work_order: (frm) => {
frm.clear_table('items');
@@ -42,12 +45,23 @@ frappe.ui.form.on('Pick List', {
items_based_on: (frm) => {
frm.trigger('add_get_items_button');
},
- make_delivery_note(frm) {
+ create_delivery_note(frm) {
frappe.model.open_mapped_doc({
- method: 'erpnext.stock.doctype.pick_list.pick_list.make_delivery_note',
+ method: 'erpnext.stock.doctype.pick_list.pick_list.create_delivery_note',
frm: frm
});
},
+ create_stock_entry(frm) {
+ // TODO: show dialog for qty
+
+ frappe.xcall('erpnext.stock.doctype.pick_list.pick_list.create_stock_entry', {
+ 'pick_list': frm.doc,
+ 'qty': 1
+ }).then(stock_entry => {
+ frappe.model.sync(stock_entry);
+ frappe.set_route("Form", 'Stock Entry', stock_entry.name);
+ });
+ },
add_get_items_button(frm) {
let source_doctype = frm.doc.items_based_on;
if (source_doctype != 'Sales Order') return;
diff --git a/erpnext/stock/doctype/pick_list/pick_list.py b/erpnext/stock/doctype/pick_list/pick_list.py
index 8699ee6e19..34f1ab5895 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.py
+++ b/erpnext/stock/doctype/pick_list/pick_list.py
@@ -4,11 +4,12 @@
from __future__ import unicode_literals
import frappe
-from frappe.model.document import Document
+import json
from six import iteritems
-from frappe.model.mapper import get_mapped_doc, map_child_doc
+from frappe.model.document import Document
from frappe.utils import floor, flt, today
-from erpnext.selling.doctype.sales_order.sales_order import make_delivery_note as make_delivery_note_from_sales_order
+from frappe.model.mapper import get_mapped_doc, map_child_doc
+from erpnext.selling.doctype.sales_order.sales_order import make_delivery_note as create_delivery_note_from_sales_order
# TODO: Prioritize SO or WO group warehouse
@@ -49,7 +50,6 @@ class PickList(Document):
def get_items_with_warehouse_and_quantity(item_doc, from_warehouses, item_location_map):
available_locations = item_location_map.get(item_doc.item_code)
-
locations = []
remaining_stock_qty = item_doc.stock_qty
while remaining_stock_qty > 0 and available_locations:
@@ -98,15 +98,6 @@ def get_available_items(item_code, from_warehouses):
return available_items
-def set_serial_nos(item_doc):
- serial_nos = frappe.get_all('Serial No', {
- 'item_code': item_doc.item_code,
- 'warehouse': item_doc.warehouse
- }, limit=item_doc.stock_qty, order_by='purchase_date')
- item_doc.set('serial_no', '\n'.join([serial_no.name for serial_no in serial_nos]))
-
- # should we assume that all serialized item_code available in stock will have serial no?
-
def get_item_locations_based_on_serial_nos(item_doc):
serial_nos = frappe.get_all('Serial No',
fields = ['name', 'warehouse'],
@@ -176,26 +167,26 @@ def get_item_locations_based_on_batch_nos(item_doc):
return locations
@frappe.whitelist()
-def make_delivery_note(source_name, target_doc=None):
+def create_delivery_note(source_name, target_doc=None):
pick_list = frappe.get_doc('Pick List', source_name)
sales_orders = [d.sales_order for d in pick_list.locations]
sales_orders = set(sales_orders)
delivery_note = None
for sales_order in sales_orders:
- delivery_note = make_delivery_note_from_sales_order(sales_order,
+ delivery_note = create_delivery_note_from_sales_order(sales_order,
delivery_note, skip_item_mapping=True)
for location in pick_list.locations:
sales_order_item = frappe.get_cached_doc('Sales Order Item', location.sales_order_item)
item_table_mapper = {
- "doctype": "Delivery Note Item",
- "field_map": {
- "rate": "rate",
- "name": "so_detail",
- "parent": "against_sales_order",
+ 'doctype': 'Delivery Note Item',
+ 'field_map': {
+ 'rate': 'rate',
+ 'name': 'so_detail',
+ 'parent': 'against_sales_order',
},
- "condition": lambda doc: abs(doc.delivered_qty) < abs(doc.qty) and doc.delivered_by_supplier!=1
+ 'condition': lambda doc: abs(doc.delivered_qty) < abs(doc.qty) and doc.delivered_by_supplier!=1
}
dn_item = map_child_doc(sales_order_item, delivery_note, item_table_mapper)
@@ -211,11 +202,6 @@ def make_delivery_note(source_name, target_doc=None):
return delivery_note
-def set_delivery_note_missing_values(target):
- target.run_method("set_missing_values")
- target.run_method("set_po_nos")
- target.run_method("calculate_taxes_and_totals")
-
def update_delivery_note_item(source, target, delivery_note):
cost_center = frappe.db.get_value("Project", delivery_note.project, "cost_center")
if not cost_center:
@@ -238,6 +224,56 @@ def update_delivery_note_item(source, target, delivery_note):
target.cost_center = cost_center
+def set_delivery_note_missing_values(target):
+ target.run_method('set_missing_values')
+ target.run_method('set_po_nos')
+ target.run_method('calculate_taxes_and_totals')
+
+
+@frappe.whitelist()
+def create_stock_entry(pick_list, qty):
+ pick_list = frappe.get_doc(json.loads(pick_list))
+ work_order = frappe.get_doc("Work Order", pick_list.get('work_order'))
+ if not qty:
+ qty = work_order.qty - work_order.material_transferred_for_manufacturing
+ if not qty: return
+
+ stock_entry = frappe.new_doc('Stock Entry')
+ stock_entry.purpose = 'Material Transfer For Manufacture'
+ stock_entry.set_stock_entry_type()
+ stock_entry.work_order = work_order.name
+ stock_entry.company = work_order.company
+ stock_entry.from_bom = 1
+ stock_entry.bom_no = work_order.bom_no
+ stock_entry.use_multi_level_bom = work_order.use_multi_level_bom
+ stock_entry.fg_completed_qty = (flt(work_order.qty) - flt(work_order.produced_qty))
+ if work_order.bom_no:
+ stock_entry.inspection_required = frappe.db.get_value('BOM',
+ work_order.bom_no, 'inspection_required')
+
+ is_wip_warehouse_group = frappe.db.get_value('Warehouse', work_order.wip_warehouse, 'is_group')
+ if not (is_wip_warehouse_group and work_order.skip_transfer):
+ wip_warehouse = work_order.wip_warehouse
+ else:
+ wip_warehouse = None
+ stock_entry.to_warehouse = wip_warehouse
+
+ stock_entry.project = work_order.project
+
+ for location in pick_list.locations:
+ item = frappe._dict()
+ item.item_code = location.item_code
+ item.s_warehouse = location.warehouse
+ item.t_warehouse = wip_warehouse
+ item.qty = location.qty
+ item.uom = location.uom
+ item.conversion_factor = location.conversion_factor
+ item.stock_uom = location.stock_uom
+
+ stock_entry.append('items', item)
+
+ return stock_entry.as_dict()
+
@frappe.whitelist()
def get_pending_work_orders(doctype, txt, searchfield, start, page_length, filters, as_dict):
return frappe.db.sql("""
From c1f25ff9e302b2f0036d6394175b9cf8519cd496 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Thu, 22 Aug 2019 09:53:44 +0530
Subject: [PATCH 301/484] fix: Add option to select qty of finished goods Item
---
erpnext/stock/doctype/pick_list/pick_list.js | 31 ++++++++++++++-----
.../stock/doctype/pick_list/pick_list.json | 13 ++++++--
erpnext/stock/doctype/pick_list/pick_list.py | 7 ++---
3 files changed, 36 insertions(+), 15 deletions(-)
diff --git a/erpnext/stock/doctype/pick_list/pick_list.js b/erpnext/stock/doctype/pick_list/pick_list.js
index 08a388872d..e3064fe757 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.js
+++ b/erpnext/stock/doctype/pick_list/pick_list.js
@@ -36,10 +36,30 @@ frappe.ui.form.on('Pick List', {
},
work_order: (frm) => {
frm.clear_table('items');
- erpnext.utils.map_current_doc({
- method: 'erpnext.manufacturing.doctype.work_order.work_order.create_pick_list',
- target: frm,
- source_name: frm.doc.work_order
+ frappe.db.get_value('Work Order',
+ frm.doc.work_order,
+ ['qty', 'produced_qty']
+ ).then(data => {
+ let qty_data = data.message;
+ let max = qty_data.qty - qty_data.produced_qty;
+ frappe.prompt({
+ fieldtype: 'Float',
+ label: __('Qty'),
+ fieldname: 'qty',
+ description: __('Max: {0}', [max]),
+ default: max
+ }, (data) => {
+ frm.set_value('qty', data.qty);
+ if (data.qty > max) {
+ frappe.msgprint(__('Quantity must not be more than {0}', [max]));
+ return;
+ }
+ erpnext.utils.map_current_doc({
+ method: 'erpnext.manufacturing.doctype.work_order.work_order.create_pick_list',
+ target: frm,
+ source_name: frm.doc.work_order
+ });
+ }, __("Select Quantity"), __('Get Items'));
});
},
items_based_on: (frm) => {
@@ -52,11 +72,8 @@ frappe.ui.form.on('Pick List', {
});
},
create_stock_entry(frm) {
- // TODO: show dialog for qty
-
frappe.xcall('erpnext.stock.doctype.pick_list.pick_list.create_stock_entry', {
'pick_list': frm.doc,
- 'qty': 1
}).then(stock_entry => {
frappe.model.sync(stock_entry);
frappe.set_route("Form", 'Stock Entry', stock_entry.name);
diff --git a/erpnext/stock/doctype/pick_list/pick_list.json b/erpnext/stock/doctype/pick_list/pick_list.json
index 1a33622167..e321a0bf5b 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.json
+++ b/erpnext/stock/doctype/pick_list/pick_list.json
@@ -8,6 +8,7 @@
"items_based_on",
"customer",
"work_order",
+ "qty",
"column_break_4",
"parent_warehouse",
"company",
@@ -59,8 +60,7 @@
"fieldtype": "Link",
"in_list_view": 1,
"label": "Customer",
- "options": "Customer",
- "reqd": 1
+ "options": "Customer"
},
{
"depends_on": "eval:doc.items_based_on===\"Work Order\"",
@@ -81,9 +81,16 @@
"fieldtype": "Table",
"label": "Item Locations",
"options": "Pick List Item"
+ },
+ {
+ "depends_on": "work_order",
+ "description": "Qty of raw materials will be decided based on the qty of the Finished Goods Item",
+ "fieldname": "qty",
+ "fieldtype": "Float",
+ "label": "Qty of Finished Goods Item"
}
],
- "modified": "2019-08-20 16:57:11.006221",
+ "modified": "2019-08-22 09:50:01.099449",
"modified_by": "Administrator",
"module": "Stock",
"name": "Pick List",
diff --git a/erpnext/stock/doctype/pick_list/pick_list.py b/erpnext/stock/doctype/pick_list/pick_list.py
index 34f1ab5895..d7f420d8f6 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.py
+++ b/erpnext/stock/doctype/pick_list/pick_list.py
@@ -231,12 +231,9 @@ def set_delivery_note_missing_values(target):
@frappe.whitelist()
-def create_stock_entry(pick_list, qty):
+def create_stock_entry(pick_list):
pick_list = frappe.get_doc(json.loads(pick_list))
work_order = frappe.get_doc("Work Order", pick_list.get('work_order'))
- if not qty:
- qty = work_order.qty - work_order.material_transferred_for_manufacturing
- if not qty: return
stock_entry = frappe.new_doc('Stock Entry')
stock_entry.purpose = 'Material Transfer For Manufacture'
@@ -246,7 +243,7 @@ def create_stock_entry(pick_list, qty):
stock_entry.from_bom = 1
stock_entry.bom_no = work_order.bom_no
stock_entry.use_multi_level_bom = work_order.use_multi_level_bom
- stock_entry.fg_completed_qty = (flt(work_order.qty) - flt(work_order.produced_qty))
+ stock_entry.fg_completed_qty = pick_list.qty
if work_order.bom_no:
stock_entry.inspection_required = frappe.db.get_value('BOM',
work_order.bom_no, 'inspection_required')
From cd25d6dc7fb456602a9613db7c8b4b7f09a7df0d Mon Sep 17 00:00:00 2001
From: Sahil Khan
Date: Thu, 22 Aug 2019 13:30:17 +0550
Subject: [PATCH 302/484] bumped to version 12.0.8
---
erpnext/__init__.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/__init__.py b/erpnext/__init__.py
index 8c47111e01..2490f3b42e 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__ = '12.0.7'
+__version__ = '12.0.8'
def get_default_company(user=None):
'''Get default company for user'''
From 8d55f81baa26df3da82bda179abadbb6f4c95c6d Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Thu, 22 Aug 2019 16:37:44 +0530
Subject: [PATCH 303/484] fix: Fix raw matterial selection based on finished
item qty
---
.../doctype/work_order/work_order.py | 43 ++++++++++++++++---
erpnext/stock/doctype/pick_list/pick_list.js | 33 ++++++++++----
.../stock/doctype/pick_list/pick_list.json | 4 +-
erpnext/stock/doctype/pick_list/pick_list.py | 3 +-
4 files changed, 64 insertions(+), 19 deletions(-)
diff --git a/erpnext/manufacturing/doctype/work_order/work_order.py b/erpnext/manufacturing/doctype/work_order/work_order.py
index 988cd223f2..804d22ce6b 100644
--- a/erpnext/manufacturing/doctype/work_order/work_order.py
+++ b/erpnext/manufacturing/doctype/work_order/work_order.py
@@ -711,13 +711,29 @@ def get_work_order_operation_data(work_order, operation, workstation):
@frappe.whitelist()
def create_pick_list(source_name, target_doc=None):
+ pick_list = json.loads(target_doc)
+ max_finished_goods_qty = frappe.db.get_value('Work Order', source_name, 'qty')
def update_item_quantity(source, target, source_parent):
- qty = source.required_qty - source.transferred_qty
- target.qty = qty
- target.stock_qty = qty
- target.uom = frappe.get_value('Item', source.item_code, 'stock_uom')
- target.stock_uom = target.uom
- target.conversion_factor = 1
+ # qty = source.required_qty - source.transferred_qty
+ # target.qty = qty
+
+ pending_to_issue = flt(source.required_qty) - flt(source.transferred_qty)
+ desire_to_transfer = flt(source.required_qty) / max_finished_goods_qty * flt(pick_list.get('for_qty'))
+
+ qty = 0
+ if desire_to_transfer <= pending_to_issue:
+ qty = desire_to_transfer
+ elif pending_to_issue > 0:
+ qty = pending_to_issue
+
+ if qty:
+ target.qty = qty
+ target.stock_qty = qty
+ target.uom = frappe.get_value('Item', source.item_code, 'stock_uom')
+ target.stock_uom = target.uom
+ target.conversion_factor = 1
+ else:
+ target.delete()
doc = get_mapped_doc("Work Order", source_name, {
"Work Order": {
@@ -733,4 +749,17 @@ def create_pick_list(source_name, target_doc=None):
},
}, target_doc)
- return doc
+ # # aggregate qty for same item
+ # item_map = frappe._dict()
+ # for item in doc.items:
+ # item.idx = None
+ # if not item_map.get(item.item_code):
+ # item_map[item.item_code] = item
+ # else:
+ # item_map[item.item_code].qty += item.qty
+ # item_map[item.item_code].stock_qty += item.stock_qty
+
+ # doc.delete_key('items')
+ # doc.set('items', item_map.values())
+
+ return doc
\ No newline at end of file
diff --git a/erpnext/stock/doctype/pick_list/pick_list.js b/erpnext/stock/doctype/pick_list/pick_list.js
index e3064fe757..6f39d88a6b 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.js
+++ b/erpnext/stock/doctype/pick_list/pick_list.js
@@ -28,32 +28,35 @@ frappe.ui.form.on('Pick List', {
frm.call('set_item_locations');
}).addClass('btn-primary');
}
- if (frm.doc.items_based_on === 'Sales Order') {
- frm.add_custom_button(__('Delivery Note'), () => frm.trigger('create_delivery_note'), __('Create'));
- } else {
- frm.add_custom_button(__('Stock Entry'), () => frm.trigger('create_stock_entry'), __('Create'));
+ if (frm.doc.docstatus == 1) {
+ if (frm.doc.items_based_on === 'Sales Order') {
+ frm.add_custom_button(__('Delivery Note'), () => frm.trigger('create_delivery_note'), __('Create'));
+ } else {
+ frm.add_custom_button(__('Stock Entry'), () => frm.trigger('create_stock_entry'), __('Create'));
+ }
}
},
work_order: (frm) => {
- frm.clear_table('items');
frappe.db.get_value('Work Order',
frm.doc.work_order,
- ['qty', 'produced_qty']
+ ['qty', 'material_transferred_for_manufacturing']
).then(data => {
let qty_data = data.message;
- let max = qty_data.qty - qty_data.produced_qty;
+ let max = qty_data.qty - qty_data.material_transferred_for_manufacturing;
frappe.prompt({
fieldtype: 'Float',
- label: __('Qty'),
+ label: __('Qty of Finished Goods Item'),
fieldname: 'qty',
description: __('Max: {0}', [max]),
default: max
}, (data) => {
- frm.set_value('qty', data.qty);
+ frm.set_value('for_qty', data.qty);
if (data.qty > max) {
frappe.msgprint(__('Quantity must not be more than {0}', [max]));
return;
}
+ frm.clear_table('items');
+ frm.clear_table('locations');
erpnext.utils.map_current_doc({
method: 'erpnext.manufacturing.doctype.work_order.work_order.create_pick_list',
target: frm,
@@ -63,6 +66,8 @@ frappe.ui.form.on('Pick List', {
});
},
items_based_on: (frm) => {
+ frm.clear_table('items');
+ frm.clear_table('locations');
frm.trigger('add_get_items_button');
},
create_delivery_note(frm) {
@@ -107,3 +112,13 @@ frappe.ui.form.on('Pick List', {
});
}
});
+
+
+// frappe.ui.form.on('Pick List Reference Item', {
+// item_code: (frm, cdt, cdn) => {
+// let row = locals[cdt][cdn];
+// if (row.item_code) {
+// frappe.xcall('');
+// }
+// }
+// });
\ No newline at end of file
diff --git a/erpnext/stock/doctype/pick_list/pick_list.json b/erpnext/stock/doctype/pick_list/pick_list.json
index e321a0bf5b..0fd7dfbfc2 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.json
+++ b/erpnext/stock/doctype/pick_list/pick_list.json
@@ -8,7 +8,7 @@
"items_based_on",
"customer",
"work_order",
- "qty",
+ "for_qty",
"column_break_4",
"parent_warehouse",
"company",
@@ -85,7 +85,7 @@
{
"depends_on": "work_order",
"description": "Qty of raw materials will be decided based on the qty of the Finished Goods Item",
- "fieldname": "qty",
+ "fieldname": "for_qty",
"fieldtype": "Float",
"label": "Qty of Finished Goods Item"
}
diff --git a/erpnext/stock/doctype/pick_list/pick_list.py b/erpnext/stock/doctype/pick_list/pick_list.py
index d7f420d8f6..f69fbd53b3 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.py
+++ b/erpnext/stock/doctype/pick_list/pick_list.py
@@ -61,6 +61,7 @@ def get_items_with_warehouse_and_quantity(item_doc, from_warehouses, item_locati
if uom_must_be_whole_number:
qty = floor(qty)
stock_qty = qty * item_doc.conversion_factor
+ if not stock_qty: break
locations.append({
'qty': qty,
@@ -243,7 +244,7 @@ def create_stock_entry(pick_list):
stock_entry.from_bom = 1
stock_entry.bom_no = work_order.bom_no
stock_entry.use_multi_level_bom = work_order.use_multi_level_bom
- stock_entry.fg_completed_qty = pick_list.qty
+ stock_entry.fg_completed_qty = pick_list.for_qty
if work_order.bom_no:
stock_entry.inspection_required = frappe.db.get_value('BOM',
work_order.bom_no, 'inspection_required')
From 687b1a5b1f9bed8a763fc037dcb9ead4645b0983 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Thu, 22 Aug 2019 16:41:14 +0530
Subject: [PATCH 304/484] fix: Make pick list submittable and add few fields
- Add material request & item fields
- Add pick_list field to Stock Entry
- Add purpose field to pick list
---
.../stock/doctype/pick_list/pick_list.json | 76 ++++++++++++++++++-
erpnext/stock/doctype/pick_list/pick_list.py | 11 ++-
.../pick_list_reference_item.json | 23 +++++-
.../doctype/stock_entry/stock_entry.json | 11 ++-
4 files changed, 111 insertions(+), 10 deletions(-)
diff --git a/erpnext/stock/doctype/pick_list/pick_list.json b/erpnext/stock/doctype/pick_list/pick_list.json
index 0fd7dfbfc2..504a3fa14f 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.json
+++ b/erpnext/stock/doctype/pick_list/pick_list.json
@@ -5,6 +5,7 @@
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
+ "purpose",
"items_based_on",
"customer",
"work_order",
@@ -15,7 +16,8 @@
"section_break_4",
"items",
"section_break_6",
- "locations"
+ "locations",
+ "amended_from"
],
"fields": [
{
@@ -87,16 +89,36 @@
"description": "Qty of raw materials will be decided based on the qty of the Finished Goods Item",
"fieldname": "for_qty",
"fieldtype": "Float",
- "label": "Qty of Finished Goods Item"
+ "label": "Qty of Finished Goods Item",
+ "read_only": 1
+ },
+ {
+ "fieldname": "amended_from",
+ "fieldtype": "Link",
+ "label": "Amended From",
+ "no_copy": 1,
+ "options": "Pick List",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "default": "Material Transfer for manufacturing",
+ "fieldname": "purpose",
+ "fieldtype": "Select",
+ "label": "Purpose",
+ "options": "Material Transfer for manufacturing\nMaterial Issue\nMaterial Transfer\nDelivery against Sales Order"
}
],
- "modified": "2019-08-22 09:50:01.099449",
+ "is_submittable": 1,
+ "modified": "2019-08-22 13:36:18.912659",
"modified_by": "Administrator",
"module": "Stock",
"name": "Pick List",
"owner": "Administrator",
"permissions": [
{
+ "amend": 1,
+ "cancel": 1,
"create": 1,
"delete": 1,
"email": 1,
@@ -104,8 +126,54 @@
"print": 1,
"read": 1,
"report": 1,
- "role": "System Manager",
+ "role": "Stock Manager",
"share": 1,
+ "submit": 1,
+ "write": 1
+ },
+ {
+ "amend": 1,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Stock User",
+ "share": 1,
+ "submit": 1,
+ "write": 1
+ },
+ {
+ "amend": 1,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Manufacturing Manager",
+ "share": 1,
+ "submit": 1,
+ "write": 1
+ },
+ {
+ "amend": 1,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Manufacturing User",
+ "share": 1,
+ "submit": 1,
"write": 1
}
],
diff --git a/erpnext/stock/doctype/pick_list/pick_list.py b/erpnext/stock/doctype/pick_list/pick_list.py
index f69fbd53b3..550c70f2d1 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.py
+++ b/erpnext/stock/doctype/pick_list/pick_list.py
@@ -237,6 +237,7 @@ def create_stock_entry(pick_list):
work_order = frappe.get_doc("Work Order", pick_list.get('work_order'))
stock_entry = frappe.new_doc('Stock Entry')
+ stock_entry.pick_list = pick_list.get('name')
stock_entry.purpose = 'Material Transfer For Manufacture'
stock_entry.set_stock_entry_type()
stock_entry.work_order = work_order.name
@@ -264,12 +265,17 @@ def create_stock_entry(pick_list):
item.s_warehouse = location.warehouse
item.t_warehouse = wip_warehouse
item.qty = location.qty
+ item.transfer_qty = location.stock_qty
item.uom = location.uom
item.conversion_factor = location.conversion_factor
item.stock_uom = location.stock_uom
stock_entry.append('items', item)
+ stock_entry.set_incoming_rate()
+ stock_entry.set_actual_qty()
+ stock_entry.calculate_rate_and_amount(update_finished_item_rate=False)
+
return stock_entry.as_dict()
@frappe.whitelist()
@@ -281,7 +287,7 @@ def get_pending_work_orders(doctype, txt, searchfield, start, page_length, filte
`tabWork Order`
WHERE
`status` not in ('Completed', 'Stopped')
- AND `qty` > `produced_qty`
+ AND `qty` > `material_transferred_for_manufacturing`
AND `docstatus` = 1
AND `company` = %(company)s
AND `name` like %(txt)s
@@ -296,3 +302,6 @@ def get_pending_work_orders(doctype, txt, searchfield, start, page_length, filte
'page_length': frappe.utils.cint(page_length),
'company': filters.get('company')
}, as_dict=as_dict)
+
+def get_item_details(item_code):
+ pass
\ No newline at end of file
diff --git a/erpnext/stock/doctype/pick_list_reference_item/pick_list_reference_item.json b/erpnext/stock/doctype/pick_list_reference_item/pick_list_reference_item.json
index 0aa94feb37..e6984ef323 100644
--- a/erpnext/stock/doctype/pick_list_reference_item/pick_list_reference_item.json
+++ b/erpnext/stock/doctype/pick_list_reference_item/pick_list_reference_item.json
@@ -14,7 +14,9 @@
"conversion_factor",
"reference_section",
"sales_order",
- "sales_order_item"
+ "sales_order_item",
+ "material_request",
+ "material_request_item"
],
"fields": [
{
@@ -65,21 +67,34 @@
"fieldname": "sales_order",
"fieldtype": "Link",
"label": "Sales Order",
- "options": "Sales Order"
+ "options": "Sales Order",
+ "read_only": 1
},
{
"fieldname": "sales_order_item",
"fieldtype": "Data",
- "label": "Sales Order Item"
+ "label": "Sales Order Item",
+ "read_only": 1
},
{
"fieldname": "conversion_factor",
"fieldtype": "Float",
"label": "UOM Conversion Factor"
+ },
+ {
+ "fieldname": "material_request",
+ "fieldtype": "Link",
+ "label": "Material Request",
+ "options": "Material Request"
+ },
+ {
+ "fieldname": "material_request_item",
+ "fieldtype": "Data",
+ "label": "Material Request Item"
}
],
"istable": 1,
- "modified": "2019-08-14 18:38:28.867113",
+ "modified": "2019-08-22 14:19:19.725540",
"modified_by": "Administrator",
"module": "Stock",
"name": "Pick List Reference Item",
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.json b/erpnext/stock/doctype/stock_entry/stock_entry.json
index ee563cb4a0..22b84a18dd 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.json
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.json
@@ -17,6 +17,7 @@
"purchase_order",
"delivery_note_no",
"sales_invoice_no",
+ "pick_list",
"purchase_receipt_no",
"col2",
"posting_date",
@@ -613,12 +614,20 @@
{
"fieldname": "dimension_col_break",
"fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "pick_list",
+ "fieldtype": "Link",
+ "hidden": 1,
+ "label": "Pick List",
+ "options": "Pick List",
+ "read_only": 1
}
],
"icon": "fa fa-file-text",
"idx": 1,
"is_submittable": 1,
- "modified": "2019-07-14 17:41:39.257508",
+ "modified": "2019-08-22 13:09:55.344036",
"modified_by": "Administrator",
"module": "Stock",
"name": "Stock Entry",
From 210317c0b5e8cb50d7226fc9a796adfe9ec3be5e Mon Sep 17 00:00:00 2001
From: Anurag Mishra <32095923+Anurag810@users.noreply.github.com>
Date: Fri, 23 Aug 2019 00:21:26 +0530
Subject: [PATCH 305/484] fix: division by zero in asset Depereciation (#18637)
* fix: division by zero in asset Depereciation
* fix: requested changes
---
erpnext/assets/doctype/asset/asset.py | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py
index 45d2ec2c51..ab37e91538 100644
--- a/erpnext/assets/doctype/asset/asset.py
+++ b/erpnext/assets/doctype/asset/asset.py
@@ -255,9 +255,15 @@ class Asset(AccountsController):
precision = self.precision("gross_purchase_amount")
if row.depreciation_method in ("Straight Line", "Manual"):
+ depreciation_left = (cint(row.total_number_of_depreciations) - cint(self.number_of_depreciations_booked))
+
+ if not depreciation_left:
+ frappe.msgprint(_("All the depreciations has been booked"))
+ depreciation_amount = flt(row.expected_value_after_useful_life)
+ return depreciation_amount
+
depreciation_amount = (flt(row.value_after_depreciation) -
- flt(row.expected_value_after_useful_life)) / (cint(row.total_number_of_depreciations) -
- cint(self.number_of_depreciations_booked))
+ flt(row.expected_value_after_useful_life)) / depreciation_left
else:
depreciation_amount = flt(depreciable_value * (flt(row.rate_of_depreciation) / 100), precision)
@@ -275,7 +281,7 @@ class Asset(AccountsController):
flt(accumulated_depreciation_after_full_schedule),
self.precision('gross_purchase_amount'))
- if (row.expected_value_after_useful_life and
+ if (row.expected_value_after_useful_life and
row.expected_value_after_useful_life < asset_value_after_full_schedule):
frappe.throw(_("Depreciation Row {0}: Expected value after useful life must be greater than or equal to {1}")
.format(row.idx, asset_value_after_full_schedule))
From f2798eab502231ae5d0dce0bd26caa690baffc6b Mon Sep 17 00:00:00 2001
From: deepeshgarg007
Date: Fri, 23 Aug 2019 10:07:52 +0530
Subject: [PATCH 306/484] fix: Conside multiple stock entry against a purchase
order
---
erpnext/stock/doctype/stock_entry/stock_entry.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py
index 32a785f258..e04d4c9512 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.py
@@ -535,7 +535,7 @@ class StockEntry(StockController):
total_allowed = required_qty + (required_qty * (qty_allowance/100))
- if not total_allowed:
+ if not required_qty:
frappe.throw(_("Item {0} not found in 'Raw Materials Supplied' table in Purchase Order {1}")
.format(se_item.item_code, self.purchase_order))
total_supplied = frappe.db.sql("""select sum(transfer_qty)
From 88ee7d8dbeb62ff080247089219e2783d26c41d3 Mon Sep 17 00:00:00 2001
From: rohitwaghchaure
Date: Fri, 23 Aug 2019 11:13:58 +0530
Subject: [PATCH 307/484] fix: POS Sync Issue (#18807)
---
erpnext/accounts/doctype/sales_invoice/pos.py | 15 ++++-----------
erpnext/accounts/page/pos/pos.js | 11 ++---------
2 files changed, 6 insertions(+), 20 deletions(-)
diff --git a/erpnext/accounts/doctype/sales_invoice/pos.py b/erpnext/accounts/doctype/sales_invoice/pos.py
index 479548c6e3..e290b235a9 100755
--- a/erpnext/accounts/doctype/sales_invoice/pos.py
+++ b/erpnext/accounts/doctype/sales_invoice/pos.py
@@ -432,7 +432,6 @@ def get_customer_id(doc, customer=None):
return cust_id
-
def make_customer_and_address(customers):
customers_list = []
for customer, data in iteritems(customers):
@@ -449,7 +448,6 @@ def make_customer_and_address(customers):
frappe.db.commit()
return customers_list
-
def add_customer(data):
customer = data.get('full_name') or data.get('customer')
if frappe.db.exists("Customer", customer.strip()):
@@ -466,21 +464,18 @@ def add_customer(data):
frappe.db.commit()
return customer_doc.name
-
def get_territory(data):
if data.get('territory'):
return data.get('territory')
return frappe.db.get_single_value('Selling Settings','territory') or _('All Territories')
-
def get_customer_group(data):
if data.get('customer_group'):
return data.get('customer_group')
return frappe.db.get_single_value('Selling Settings', 'customer_group') or frappe.db.get_value('Customer Group', {'is_group': 0}, 'name')
-
def make_contact(args, customer):
if args.get('email_id') or args.get('phone'):
name = frappe.db.get_value('Dynamic Link',
@@ -506,7 +501,6 @@ def make_contact(args, customer):
doc.flags.ignore_mandatory = True
doc.save(ignore_permissions=True)
-
def make_address(args, customer):
if not args.get('address_line1'):
return
@@ -521,7 +515,10 @@ def make_address(args, customer):
address = frappe.get_doc('Address', name)
else:
address = frappe.new_doc('Address')
- address.country = frappe.get_cached_value('Company', args.get('company'), 'country')
+ if args.get('company'):
+ address.country = frappe.get_cached_value('Company',
+ args.get('company'), 'country')
+
address.append('links', {
'link_doctype': 'Customer',
'link_name': customer
@@ -533,7 +530,6 @@ def make_address(args, customer):
address.flags.ignore_mandatory = True
address.save(ignore_permissions=True)
-
def make_email_queue(email_queue):
name_list = []
for key, data in iteritems(email_queue):
@@ -550,7 +546,6 @@ def make_email_queue(email_queue):
return name_list
-
def validate_item(doc):
for item in doc.get('items'):
if not frappe.db.exists('Item', item.get('item_code')):
@@ -569,7 +564,6 @@ def validate_item(doc):
item_doc.save(ignore_permissions=True)
frappe.db.commit()
-
def submit_invoice(si_doc, name, doc, name_list):
try:
si_doc.insert()
@@ -585,7 +579,6 @@ def submit_invoice(si_doc, name, doc, name_list):
return name_list
-
def save_invoice(doc, name, name_list):
try:
if not frappe.db.exists('Sales Invoice', {'offline_pos_name': name}):
diff --git a/erpnext/accounts/page/pos/pos.js b/erpnext/accounts/page/pos/pos.js
index 3834c96bfb..b5a02d0e49 100755
--- a/erpnext/accounts/page/pos/pos.js
+++ b/erpnext/accounts/page/pos/pos.js
@@ -1762,18 +1762,11 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
this.si_docs = this.get_submitted_invoice() || [];
this.email_queue_list = this.get_email_queue() || {};
this.customers_list = this.get_customers_details() || {};
- if(this.customer_doc) {
- this.freeze = this.customer_doc.display
- }
-
- freeze_screen = this.freeze_screen || false;
-
- if ((this.si_docs.length || this.email_queue_list || this.customers_list) && !this.freeze) {
- this.freeze = true;
+ if (this.si_docs.length || this.email_queue_list || this.customers_list) {
frappe.call({
method: "erpnext.accounts.doctype.sales_invoice.pos.make_invoice",
- freeze: freeze_screen,
+ freeze: true,
args: {
doc_list: me.si_docs,
email_queue_list: me.email_queue_list,
From db88476f8b48965565bb0c45dd9a040e3d76bac2 Mon Sep 17 00:00:00 2001
From: Anurag Mishra <32095923+Anurag810@users.noreply.github.com>
Date: Fri, 23 Aug 2019 11:27:00 +0530
Subject: [PATCH 308/484] feat: refactor invoice_discounting (#18629)
* feat: refactor invoice_discountig
* Update invoice_discounting.py
* Update invoice_discounting.js
---
.../discounted_invoice.json | 13 ++++-
.../invoice_discounting.js | 53 +++++++++++++------
.../invoice_discounting.py | 13 ++++-
3 files changed, 59 insertions(+), 20 deletions(-)
diff --git a/erpnext/accounts/doctype/discounted_invoice/discounted_invoice.json b/erpnext/accounts/doctype/discounted_invoice/discounted_invoice.json
index 8d7ed74eb9..04d6303774 100644
--- a/erpnext/accounts/doctype/discounted_invoice/discounted_invoice.json
+++ b/erpnext/accounts/doctype/discounted_invoice/discounted_invoice.json
@@ -8,7 +8,8 @@
"customer",
"column_break_3",
"posting_date",
- "outstanding_amount"
+ "outstanding_amount",
+ "debit_to"
],
"fields": [
{
@@ -48,10 +49,18 @@
{
"fieldname": "column_break_3",
"fieldtype": "Column Break"
+ },
+ {
+ "fetch_from": "sales_invoice.debit_to",
+ "fieldname": "debit_to",
+ "fieldtype": "Link",
+ "label": "Debit to",
+ "options": "Account",
+ "read_only": 1
}
],
"istable": 1,
- "modified": "2019-05-30 19:27:29.436153",
+ "modified": "2019-08-07 15:13:55.808349",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Discounted Invoice",
diff --git a/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.js b/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.js
index 5563f031bb..f1f88a8d64 100644
--- a/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.js
+++ b/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.js
@@ -13,41 +13,57 @@ frappe.ui.form.on('Invoice Discounting', {
};
});
- frm.events.filter_accounts("bank_account", frm, {"account_type": "Bank"});
- frm.events.filter_accounts("bank_charges_account", frm, {"root_type": "Expense"});
- frm.events.filter_accounts("short_term_loan", frm, {"root_type": "Liability"});
- frm.events.filter_accounts("accounts_receivable_credit", frm, {"account_type": "Receivable"});
- frm.events.filter_accounts("accounts_receivable_discounted", frm, {"account_type": "Receivable"});
- frm.events.filter_accounts("accounts_receivable_unpaid", frm, {"account_type": "Receivable"});
+
+ frm.events.filter_accounts("bank_account", frm, [["account_type", "=", "Bank"]]);
+ frm.events.filter_accounts("bank_charges_account", frm, [["root_type", "=", "Expense"]]);
+ frm.events.filter_accounts("short_term_loan", frm, [["root_type", "=", "Liability"]]);
+ frm.events.filter_accounts("accounts_receivable_discounted", frm, [["account_type", "=", "Receivable"]]);
+ frm.events.filter_accounts("accounts_receivable_credit", frm, [["account_type", "=", "Receivable"]]);
+ frm.events.filter_accounts("accounts_receivable_unpaid", frm, [["account_type", "=", "Receivable"]]);
},
filter_accounts: (fieldname, frm, addl_filters) => {
- let filters = {
- "company": frm.doc.company,
- "is_group": 0
- };
- if(addl_filters) Object.assign(filters, addl_filters);
+ let filters = [
+ ["company", "=", frm.doc.company],
+ ["is_group", "=", 0]
+ ];
+ if(addl_filters){
+ filters = $.merge(filters , addl_filters);
+ }
frm.set_query(fieldname, () => { return { "filters": filters }; });
},
+ refresh_filters: (frm) =>{
+ let invoice_accounts = Object.keys(frm.doc.invoices).map(function(key) {
+ return frm.doc.invoices[key].debit_to;
+ });
+ let filters = [
+ ["account_type", "=", "Receivable"],
+ ["name", "not in", invoice_accounts]
+ ];
+ frm.events.filter_accounts("accounts_receivable_credit", frm, filters);
+ frm.events.filter_accounts("accounts_receivable_discounted", frm, filters);
+ frm.events.filter_accounts("accounts_receivable_unpaid", frm, filters);
+ },
+
refresh: (frm) => {
frm.events.show_general_ledger(frm);
- if(frm.doc.docstatus === 0) {
+ if (frm.doc.docstatus === 0) {
frm.add_custom_button(__('Get Invoices'), function() {
frm.events.get_invoices(frm);
});
}
- if(frm.doc.docstatus === 1 && frm.doc.status !== "Settled") {
- if(frm.doc.status == "Sanctioned") {
+ if (frm.doc.docstatus === 1 && frm.doc.status !== "Settled") {
+ if (frm.doc.status == "Sanctioned") {
frm.add_custom_button(__('Disburse Loan'), function() {
frm.events.create_disbursement_entry(frm);
}).addClass("btn-primary");
}
- if(frm.doc.status == "Disbursed") {
+ if (frm.doc.status == "Disbursed") {
frm.add_custom_button(__('Close Loan'), function() {
frm.events.close_loan(frm);
}).addClass("btn-primary");
@@ -64,7 +80,7 @@ frappe.ui.form.on('Invoice Discounting', {
},
set_end_date: (frm) => {
- if(frm.doc.loan_start_date && frm.doc.loan_period) {
+ if (frm.doc.loan_start_date && frm.doc.loan_period) {
let end_date = frappe.datetime.add_days(frm.doc.loan_start_date, frm.doc.loan_period);
frm.set_value("loan_end_date", end_date);
}
@@ -132,6 +148,7 @@ frappe.ui.form.on('Invoice Discounting', {
frm.doc.invoices = frm.doc.invoices.filter(row => row.sales_invoice);
let row = frm.add_child("invoices");
$.extend(row, v);
+ frm.events.refresh_filters(frm);
});
refresh_field("invoices");
}
@@ -190,8 +207,10 @@ frappe.ui.form.on('Invoice Discounting', {
frappe.ui.form.on('Discounted Invoice', {
sales_invoice: (frm) => {
frm.events.calculate_total_amount(frm);
+ frm.events.refresh_filters(frm);
},
invoices_remove: (frm) => {
frm.events.calculate_total_amount(frm);
+ frm.events.refresh_filters(frm);
}
-});
\ No newline at end of file
+});
diff --git a/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.py b/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.py
index 29475d5644..36c29113ea 100644
--- a/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.py
+++ b/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.py
@@ -12,6 +12,7 @@ from erpnext.accounts.general_ledger import make_gl_entries
class InvoiceDiscounting(AccountsController):
def validate(self):
self.validate_mandatory()
+ self.validate_invoices()
self.calculate_total_amount()
self.set_status()
self.set_end_date()
@@ -24,6 +25,15 @@ class InvoiceDiscounting(AccountsController):
if self.docstatus == 1 and not (self.loan_start_date and self.loan_period):
frappe.throw(_("Loan Start Date and Loan Period are mandatory to save the Invoice Discounting"))
+ def validate_invoices(self):
+ discounted_invoices = [record.sales_invoice for record in
+ frappe.get_all("Discounted Invoice",fields = ["sales_invoice"], filters= {"docstatus":1})]
+
+ for record in self.invoices:
+ if record.sales_invoice in discounted_invoices:
+ frappe.throw("Row({0}): {1} is already discounted in {2}"
+ .format(record.idx, frappe.bold(record.sales_invoice), frappe.bold(record.parent)))
+
def calculate_total_amount(self):
self.total_amount = sum([flt(d.outstanding_amount) for d in self.invoices])
@@ -212,7 +222,8 @@ def get_invoices(filters):
name as sales_invoice,
customer,
posting_date,
- outstanding_amount
+ outstanding_amount,
+ debit_to
from `tabSales Invoice` si
where
docstatus = 1
From 680e098b872f51c9c2b1e899b5548c492b8d7873 Mon Sep 17 00:00:00 2001
From: Michelle Alva <50285544+michellealva@users.noreply.github.com>
Date: Fri, 23 Aug 2019 11:32:43 +0530
Subject: [PATCH 309/484] fix(dash): Added Tax exemption category and sub
category in Employee Tax and Benefits (#18545)
section
From 56d03a456b44890602ddd00130107893f6f223e1 Mon Sep 17 00:00:00 2001
From: Harshit <46772424+harshit-30@users.noreply.github.com>
Date: Fri, 23 Aug 2019 11:34:25 +0530
Subject: [PATCH 310/484] fix: add contract to CRM module (#18817)
---
erpnext/config/crm.py | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/erpnext/config/crm.py b/erpnext/config/crm.py
index 70784f3d5f..eba6c7a02a 100644
--- a/erpnext/config/crm.py
+++ b/erpnext/config/crm.py
@@ -41,6 +41,11 @@ def get_data():
"name": "Lead Source",
"description": _("Track Leads by Lead Source.")
},
+ {
+ "type": "doctype",
+ "name": "Contract",
+ "description": _("Helps you keep tracks of Contracts based on Supplier, Customer and Employee"),
+ },
]
},
{
From 23b5f4ec99d0f22348ba3b8f1384c9f14f9660ee Mon Sep 17 00:00:00 2001
From: KanchanChauhan
Date: Fri, 23 Aug 2019 11:40:09 +0530
Subject: [PATCH 311/484] fix: Leave Application status filter (#18770)
When we click on Status Open in list view it throws an error.
After fix, it filters the results on Open status
---
erpnext/hr/doctype/leave_application/leave_application_list.js | 2 ++
1 file changed, 2 insertions(+)
diff --git a/erpnext/hr/doctype/leave_application/leave_application_list.js b/erpnext/hr/doctype/leave_application/leave_application_list.js
index f69b182737..cbb4b73227 100644
--- a/erpnext/hr/doctype/leave_application/leave_application_list.js
+++ b/erpnext/hr/doctype/leave_application/leave_application_list.js
@@ -5,6 +5,8 @@ frappe.listview_settings['Leave Application'] = {
return [__("Approved"), "green", "status,=,Approved"];
} else if (doc.status === "Rejected") {
return [__("Rejected"), "red", "status,=,Rejected"];
+ } else {
+ return [__("Open"), "red", "status,=,Open"];
}
}
};
From f3d78dd29c4c98d303fbcfe7f7e1db447c466a82 Mon Sep 17 00:00:00 2001
From: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com>
Date: Fri, 23 Aug 2019 11:42:35 +0530
Subject: [PATCH 312/484] fix: Duplicate items check in Sales Invoice (#18660)
* fix: Duplicate items check in sales Invoice
* fix: Commonified function for duplicate items check in selling controller
* fix: Set valuation rate and transaction date in child tabel
---
erpnext/controllers/selling_controller.py | 29 +++++++++++++++++++
.../doctype/sales_order/sales_order.py | 9 ------
.../doctype/delivery_note/delivery_note.py | 17 -----------
3 files changed, 29 insertions(+), 26 deletions(-)
diff --git a/erpnext/controllers/selling_controller.py b/erpnext/controllers/selling_controller.py
index 2cbe596770..52d58dce62 100644
--- a/erpnext/controllers/selling_controller.py
+++ b/erpnext/controllers/selling_controller.py
@@ -45,6 +45,7 @@ class SellingController(StockController):
self.set_gross_profit()
set_default_income_account_for_item(self)
self.set_customer_address()
+ self.validate_for_duplicate_items()
def set_missing_values(self, for_validate=False):
@@ -381,6 +382,34 @@ class SellingController(StockController):
if self.get(address_field):
self.set(address_display_field, get_address_display(self.get(address_field)))
+ def validate_for_duplicate_items(self):
+ check_list, chk_dupl_itm = [], []
+ if cint(frappe.db.get_single_value("Selling Settings", "allow_multiple_items")):
+ return
+
+ for d in self.get('items'):
+ if self.doctype == "Sales Invoice":
+ e = [d.item_code, d.description, d.warehouse, d.sales_order or d.delivery_note, d.batch_no or '']
+ f = [d.item_code, d.description, d.sales_order or d.delivery_note]
+ elif self.doctype == "Delivery Note":
+ e = [d.item_code, d.description, d.warehouse, d.against_sales_order or d.against_sales_invoice, d.batch_no or '']
+ f = [d.item_code, d.description, d.against_sales_order or d.against_sales_invoice]
+ elif self.doctype == "Sales Order":
+ e = [d.item_code, d.description, d.warehouse, d.batch_no or '']
+ f = [d.item_code, d.description]
+
+ if frappe.db.get_value("Item", d.item_code, "is_stock_item") == 1:
+ if e in check_list:
+ frappe.throw(_("Note: Item {0} entered multiple times").format(d.item_code))
+ else:
+ check_list.append(e)
+ else:
+ if f in chk_dupl_itm:
+ frappe.throw(_("Note: Item {0} entered multiple times").format(d.item_code))
+ else:
+ chk_dupl_itm.append(f)
+
+
def validate_items(self):
# validate items to see if they have is_sales_item enabled
from erpnext.controllers.buying_controller import validate_item_type
diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py
index 09dc9a9932..4342af5e19 100755
--- a/erpnext/selling/doctype/sales_order/sales_order.py
+++ b/erpnext/selling/doctype/sales_order/sales_order.py
@@ -72,9 +72,7 @@ class SalesOrder(SellingController):
frappe.msgprint(_("Warning: Sales Order {0} already exists against Customer's Purchase Order {1}").format(so[0][0], self.po_no))
def validate_for_items(self):
- check_list = []
for d in self.get('items'):
- check_list.append(cstr(d.item_code))
# used for production plan
d.transaction_date = self.transaction_date
@@ -83,13 +81,6 @@ class SalesOrder(SellingController):
where item_code = %s and warehouse = %s", (d.item_code, d.warehouse))
d.projected_qty = tot_avail_qty and flt(tot_avail_qty[0][0]) or 0
- # check for same entry multiple times
- unique_chk_list = set(check_list)
- if len(unique_chk_list) != len(check_list) and \
- not cint(frappe.db.get_single_value("Selling Settings", "allow_multiple_items")):
- frappe.msgprint(_("Same item has been entered multiple times"),
- title=_("Warning"), indicator='orange')
-
def product_bundle_has_stock_item(self, product_bundle):
"""Returns true if product bundle has stock item"""
ret = len(frappe.db.sql("""select i.name from tabItem i, `tabProduct Bundle Item` pbi
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.py b/erpnext/stock/doctype/delivery_note/delivery_note.py
index 2de9b975da..f79d127984 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.py
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.py
@@ -166,24 +166,7 @@ class DeliveryNote(SellingController):
frappe.throw(_("Customer {0} does not belong to project {1}").format(self.customer, self.project))
def validate_for_items(self):
- check_list, chk_dupl_itm = [], []
- if cint(frappe.db.get_single_value("Selling Settings", "allow_multiple_items")):
- return
-
for d in self.get('items'):
- e = [d.item_code, d.description, d.warehouse, d.against_sales_order or d.against_sales_invoice, d.batch_no or '']
- f = [d.item_code, d.description, d.against_sales_order or d.against_sales_invoice]
-
- if frappe.db.get_value("Item", d.item_code, "is_stock_item") == 1:
- if e in check_list:
- frappe.msgprint(_("Note: Item {0} entered multiple times").format(d.item_code))
- else:
- check_list.append(e)
- else:
- if f in chk_dupl_itm:
- frappe.msgprint(_("Note: Item {0} entered multiple times").format(d.item_code))
- else:
- chk_dupl_itm.append(f)
#Customer Provided parts will have zero valuation rate
if frappe.db.get_value('Item', d.item_code, 'is_customer_provided_item'):
d.allow_zero_valuation_rate = 1
From c890401fec89eb97a0656a1e18a297b78fe805de Mon Sep 17 00:00:00 2001
From: Michelle Alva <50285544+michellealva@users.noreply.github.com>
Date: Fri, 23 Aug 2019 11:50:48 +0530
Subject: [PATCH 313/484] fix: added payroll period in HR module (#18543)
From 8b4d604cfda01e1a67503d10ce7ce175fed51f8a Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Fri, 23 Aug 2019 11:57:16 +0530
Subject: [PATCH 314/484] fix: Use purpose field and remove item_base_on field
---
.../doctype/sales_order/sales_order.py | 5 ++---
erpnext/stock/doctype/pick_list/pick_list.js | 19 +++++++++++-------
.../stock/doctype/pick_list/pick_list.json | 20 +++++--------------
erpnext/stock/doctype/pick_list/pick_list.py | 14 +++++++++++--
.../doctype/stock_entry/stock_entry.json | 3 +--
5 files changed, 32 insertions(+), 29 deletions(-)
diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py
index dd156d0473..426b00484c 100755
--- a/erpnext/selling/doctype/sales_order/sales_order.py
+++ b/erpnext/selling/doctype/sales_order/sales_order.py
@@ -1010,9 +1010,6 @@ def make_pick_list(source_name, target_doc=None):
doc = get_mapped_doc("Sales Order", source_name, {
"Sales Order": {
"doctype": "Pick List",
- "field_map": {
- "doctype": "items_based_on"
- },
"validation": {
"docstatus": ["=", 1]
}
@@ -1028,4 +1025,6 @@ def make_pick_list(source_name, target_doc=None):
},
}, target_doc)
+ doc.purpose = 'Delivery against Sales Order'
+
return doc
diff --git a/erpnext/stock/doctype/pick_list/pick_list.js b/erpnext/stock/doctype/pick_list/pick_list.js
index 6f39d88a6b..c2dddab4c9 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.js
+++ b/erpnext/stock/doctype/pick_list/pick_list.js
@@ -23,16 +23,21 @@ frappe.ui.form.on('Pick List', {
refresh: (frm) => {
frm.trigger('add_get_items_button');
- if (frm.doc.items && (frm.doc.items.length > 1 || frm.doc.items[0].item_code)) {
+ if (frm.doc.items && (frm.doc.items.length > 1 || frm.doc.items[0].item_code) && frm.doc.docstatus === 0) {
frm.add_custom_button(__('Get Item Locations'), () => {
frm.call('set_item_locations');
}).addClass('btn-primary');
}
- if (frm.doc.docstatus == 1) {
- if (frm.doc.items_based_on === 'Sales Order') {
+ if (frm.doc.docstatus === 1) {
+ if (frm.doc.purpose === 'Delivery against Sales Order') {
frm.add_custom_button(__('Delivery Note'), () => frm.trigger('create_delivery_note'), __('Create'));
} else {
- frm.add_custom_button(__('Stock Entry'), () => frm.trigger('create_stock_entry'), __('Create'));
+ frappe.xcall('erpnext.stock.doctype.pick_list.pick_list.stock_entry_exists', {
+ 'pick_list_name': frm.doc.name
+ }).then(exists => {
+ if (exists) return;
+ frm.add_custom_button(__('Stock Entry'), () => frm.trigger('create_stock_entry'), __('Create'));
+ });
}
}
},
@@ -65,7 +70,7 @@ frappe.ui.form.on('Pick List', {
}, __("Select Quantity"), __('Get Items'));
});
},
- items_based_on: (frm) => {
+ purpose: (frm) => {
frm.clear_table('items');
frm.clear_table('locations');
frm.trigger('add_get_items_button');
@@ -85,8 +90,8 @@ frappe.ui.form.on('Pick List', {
});
},
add_get_items_button(frm) {
- let source_doctype = frm.doc.items_based_on;
- if (source_doctype != 'Sales Order') return;
+ let purpose = frm.doc.purpose;
+ if (purpose != 'Delivery against Sales Order' || frm.doc.docstatus !== 0) return;
let get_query_filters = {
docstatus: 1,
per_delivered: ['<', 100],
diff --git a/erpnext/stock/doctype/pick_list/pick_list.json b/erpnext/stock/doctype/pick_list/pick_list.json
index 504a3fa14f..6eca1c67d4 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.json
+++ b/erpnext/stock/doctype/pick_list/pick_list.json
@@ -6,7 +6,6 @@
"engine": "InnoDB",
"field_order": [
"purpose",
- "items_based_on",
"customer",
"work_order",
"for_qty",
@@ -48,16 +47,7 @@
"options": "Warehouse"
},
{
- "default": "Work Order",
- "fieldname": "items_based_on",
- "fieldtype": "Select",
- "in_list_view": 1,
- "label": "Items Based On",
- "options": "Sales Order\nWork Order",
- "reqd": 1
- },
- {
- "depends_on": "eval:doc.items_based_on===\"Sales Order\"",
+ "depends_on": "eval:doc.purpose==='Delivery against Sales Order'",
"fieldname": "customer",
"fieldtype": "Link",
"in_list_view": 1,
@@ -65,7 +55,7 @@
"options": "Customer"
},
{
- "depends_on": "eval:doc.items_based_on===\"Work Order\"",
+ "depends_on": "eval:doc.purpose==='Material Transfer for Manufacture'",
"fieldname": "work_order",
"fieldtype": "Link",
"label": "Work Order",
@@ -102,15 +92,15 @@
"read_only": 1
},
{
- "default": "Material Transfer for manufacturing",
+ "default": "Material Transfer for Manufacture",
"fieldname": "purpose",
"fieldtype": "Select",
"label": "Purpose",
- "options": "Material Transfer for manufacturing\nMaterial Issue\nMaterial Transfer\nDelivery against Sales Order"
+ "options": "Material Transfer for Manufacture\nMaterial Issue\nMaterial Transfer\nDelivery against Sales Order"
}
],
"is_submittable": 1,
- "modified": "2019-08-22 13:36:18.912659",
+ "modified": "2019-08-22 16:58:07.270447",
"modified_by": "Administrator",
"module": "Stock",
"name": "Pick List",
diff --git a/erpnext/stock/doctype/pick_list/pick_list.py b/erpnext/stock/doctype/pick_list/pick_list.py
index 550c70f2d1..9b8bdfe6ee 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.py
+++ b/erpnext/stock/doctype/pick_list/pick_list.py
@@ -7,6 +7,7 @@ import frappe
import json
from six import iteritems
from frappe.model.document import Document
+from frappe import _
from frappe.utils import floor, flt, today
from frappe.model.mapper import get_mapped_doc, map_child_doc
from erpnext.selling.doctype.sales_order.sales_order import make_delivery_note as create_delivery_note_from_sales_order
@@ -234,11 +235,14 @@ def set_delivery_note_missing_values(target):
@frappe.whitelist()
def create_stock_entry(pick_list):
pick_list = frappe.get_doc(json.loads(pick_list))
+ if stock_entry_exists(pick_list.get('name')):
+ return frappe.msgprint(_('Stock Entry already exists against this Pick List'))
+
work_order = frappe.get_doc("Work Order", pick_list.get('work_order'))
stock_entry = frappe.new_doc('Stock Entry')
stock_entry.pick_list = pick_list.get('name')
- stock_entry.purpose = 'Material Transfer For Manufacture'
+ stock_entry.purpose = pick_list.get('purpose')
stock_entry.set_stock_entry_type()
stock_entry.work_order = work_order.name
stock_entry.company = work_order.company
@@ -304,4 +308,10 @@ def get_pending_work_orders(doctype, txt, searchfield, start, page_length, filte
}, as_dict=as_dict)
def get_item_details(item_code):
- pass
\ No newline at end of file
+ pass
+
+@frappe.whitelist()
+def stock_entry_exists(pick_list_name):
+ return frappe.db.exists('Stock Entry', {
+ 'pick_list': pick_list_name
+ })
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.json b/erpnext/stock/doctype/stock_entry/stock_entry.json
index 22b84a18dd..f9e6d29104 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.json
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.json
@@ -618,7 +618,6 @@
{
"fieldname": "pick_list",
"fieldtype": "Link",
- "hidden": 1,
"label": "Pick List",
"options": "Pick List",
"read_only": 1
@@ -627,7 +626,7 @@
"icon": "fa fa-file-text",
"idx": 1,
"is_submittable": 1,
- "modified": "2019-08-22 13:09:55.344036",
+ "modified": "2019-08-22 17:11:42.074154",
"modified_by": "Administrator",
"module": "Stock",
"name": "Stock Entry",
From 6e7b9b5cb794705c15e8aa1575e7be206ef1470b Mon Sep 17 00:00:00 2001
From: Nabin Hait
Date: Fri, 23 Aug 2019 12:27:05 +0530
Subject: [PATCH 315/484] Update sales_invoice.py
---
erpnext/accounts/doctype/sales_invoice/sales_invoice.py | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index 4f80b78c88..95c5dd5cd4 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -206,9 +206,9 @@ class SalesInvoice(SellingController):
total_amount_in_payments = 0
for payment in self.payments:
total_amount_in_payments += payment.amount
-
- if total_amount_in_payments < self.rounded_total:
- frappe.throw(_("Total payments amount can't be greater than {}".format(-self.rounded_total)))
+ invoice_total = self.rounded_total or self.grand_total
+ if total_amount_in_payments < invoice_total:
+ frappe.throw(_("Total payments amount can't be greater than {}".format(-invoice_total)))
def validate_pos_paid_amount(self):
if len(self.payments) == 0 and self.is_pos:
@@ -1510,4 +1510,4 @@ def create_invoice_discounting(source_name, target_doc=None):
"outstanding_amount": invoice.outstanding_amount
})
- return invoice_discounting
\ No newline at end of file
+ return invoice_discounting
From 59432418c6fe6dccfbc440f26c2c946ac0fbda59 Mon Sep 17 00:00:00 2001
From: deepeshgarg007
Date: Fri, 23 Aug 2019 12:45:48 +0530
Subject: [PATCH 316/484] fix: Consider multiple stock entry against a purchase
order
---
erpnext/stock/doctype/stock_entry/stock_entry.py | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py
index e04d4c9512..2a7760edf0 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.py
@@ -1165,8 +1165,11 @@ class StockEntry(StockController):
and po.name = %s""", self.purchase_order))
#Update Supplied Qty in PO Supplied Items
- frappe.db.sql("""UPDATE `tabPurchase Order Item Supplied` pos, `tabStock Entry Detail` sed
- SET pos.supplied_qty = sed.transfer_qty where pos.name = sed.po_detail""")
+
+ frappe.db.sql("""UPDATE `tabPurchase Order Item Supplied` pos
+ SET pos.supplied_qty = (SELECT ifnull(sum(transfer_qty), 0) FROM `tabStock Entry Detail` sed
+ WHERE pos.name = sed.po_detail and sed.docstatus = 1)
+ WHERE pos.docstatus = 1""")
#Update reserved sub contracted quantity in bin based on Supplied Item Details and
for d in self.get("items"):
From a7ab51c5ba95ae387302fca2d7d222344eccbf5c Mon Sep 17 00:00:00 2001
From: Tufan Kaynak <31142607+toofun666@users.noreply.github.com>
Date: Fri, 23 Aug 2019 10:20:52 +0300
Subject: [PATCH 317/484] Update vehicle_expenses.py (#18768)
---
erpnext/hr/report/vehicle_expenses/vehicle_expenses.py | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/erpnext/hr/report/vehicle_expenses/vehicle_expenses.py b/erpnext/hr/report/vehicle_expenses/vehicle_expenses.py
index e2989e29c0..e5622b7ae1 100644
--- a/erpnext/hr/report/vehicle_expenses/vehicle_expenses.py
+++ b/erpnext/hr/report/vehicle_expenses/vehicle_expenses.py
@@ -23,7 +23,8 @@ def get_columns():
_("Model") + ":data:50", _("Location") + ":data:100",
_("Log") + ":Link/Vehicle Log:100", _("Odometer") + ":Int:80",
_("Date") + ":Date:100", _("Fuel Qty") + ":Float:80",
- _("Fuel Price") + ":Float:100",_("Service Expense") + ":Float:100"
+ _("Fuel Price") + ":Float:100",_("Fuel Expense") + ":Float:100",
+ _("Service Expense") + ":Float:100"
]
return columns
@@ -32,7 +33,8 @@ def get_log_data(filters):
data = frappe.db.sql("""select
vhcl.license_plate as "License", vhcl.make as "Make", vhcl.model as "Model",
vhcl.location as "Location", log.name as "Log", log.odometer as "Odometer",
- log.date as "Date", log.fuel_qty as "Fuel Qty", log.price as "Fuel Price"
+ log.date as "Date", log.fuel_qty as "Fuel Qty", log.price as "Fuel Price",
+ log.fuel_qty * log.price as "Fuel Expense"
from
`tabVehicle` vhcl,`tabVehicle Log` log
where
@@ -58,7 +60,7 @@ def get_chart_data(data,period_list):
total_ser_exp=0
for row in data:
if row["Date"] <= period.to_date and row["Date"] >= period.from_date:
- total_fuel_exp+=flt(row["Fuel Price"])
+ total_fuel_exp+=flt(row["Fuel Expense"])
total_ser_exp+=flt(row["Service Expense"])
fueldata.append([period.key,total_fuel_exp])
servicedata.append([period.key,total_ser_exp])
@@ -84,4 +86,4 @@ def get_chart_data(data,period_list):
}
}
chart["type"] = "line"
- return chart
\ No newline at end of file
+ return chart
From d94a389dd3d66ad74d47300fa572a0179684056a Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Fri, 23 Aug 2019 16:31:09 +0530
Subject: [PATCH 318/484] chore: remove unwanted code (#18645)
---
.../doctype/payment_order/regional/india.js | 29 ---
erpnext/patches.txt | 4 +-
.../make_custom_fields_for_bank_remittance.py | 12 --
.../remove_bank_remittance_custom_fields.py | 14 ++
erpnext/regional/india/bank_remittance.py | 190 ------------------
erpnext/regional/india/setup.py | 8 -
6 files changed, 16 insertions(+), 241 deletions(-)
delete mode 100644 erpnext/accounts/doctype/payment_order/regional/india.js
delete mode 100644 erpnext/patches/v12_0/make_custom_fields_for_bank_remittance.py
create mode 100644 erpnext/patches/v12_0/remove_bank_remittance_custom_fields.py
delete mode 100644 erpnext/regional/india/bank_remittance.py
diff --git a/erpnext/accounts/doctype/payment_order/regional/india.js b/erpnext/accounts/doctype/payment_order/regional/india.js
deleted file mode 100644
index 66d0f60c61..0000000000
--- a/erpnext/accounts/doctype/payment_order/regional/india.js
+++ /dev/null
@@ -1,29 +0,0 @@
-frappe.ui.form.on('Payment Order', {
- refresh: function(frm) {
- if (frm.doc.docstatus==1 && frm.doc.payment_order_type==='Payment Entry') {
- frm.add_custom_button(__('Generate Text File'), function() {
- frm.trigger("generate_text_and_download_file");
- });
- }
- },
- generate_text_and_download_file: (frm) => {
- return frappe.call({
- method: "erpnext.regional.india.bank_remittance.generate_report",
- args: {
- name: frm.doc.name
- },
- freeze: true,
- callback: function(r) {
- {
- frm.reload_doc();
- const a = document.createElement('a');
- let file_obj = r.message;
- a.href = file_obj.file_url;
- a.target = '_blank';
- a.download = file_obj.file_name;
- a.click();
- }
- }
- });
- }
-});
\ No newline at end of file
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 7b8280975d..dc6c6daa13 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -605,7 +605,6 @@ erpnext.patches.v11_1.rename_depends_on_lwp
execute:frappe.delete_doc("Report", "Inactive Items")
erpnext.patches.v11_1.delete_scheduling_tool
erpnext.patches.v12_0.rename_tolerance_fields
-erpnext.patches.v12_0.make_custom_fields_for_bank_remittance #14-06-2019
execute:frappe.delete_doc_if_exists("Page", "support-analytics")
erpnext.patches.v12_0.remove_patient_medical_record_page
erpnext.patches.v11_1.move_customer_lead_to_dynamic_column
@@ -626,4 +625,5 @@ erpnext.patches.v12_0.add_default_buying_selling_terms_in_company
erpnext.patches.v12_0.update_ewaybill_field_position
erpnext.patches.v12_0.create_accounting_dimensions_in_missing_doctypes
erpnext.patches.v11_1.set_status_for_material_request_type_manufacture
-erpnext.patches.v12_0.generate_leave_ledger_entries
\ No newline at end of file
+erpnext.patches.v12_0.remove_bank_remittance_custom_fields
+erpnext.patches.v12_0.generate_leave_ledger_entries
diff --git a/erpnext/patches/v12_0/make_custom_fields_for_bank_remittance.py b/erpnext/patches/v12_0/make_custom_fields_for_bank_remittance.py
deleted file mode 100644
index 3d4a9952c7..0000000000
--- a/erpnext/patches/v12_0/make_custom_fields_for_bank_remittance.py
+++ /dev/null
@@ -1,12 +0,0 @@
-from __future__ import unicode_literals
-import frappe
-from erpnext.regional.india.setup import make_custom_fields
-
-def execute():
- frappe.reload_doc("accounts", "doctype", "tax_category")
- frappe.reload_doc("stock", "doctype", "item_manufacturer")
- company = frappe.get_all('Company', filters = {'country': 'India'})
- if not company:
- return
-
- make_custom_fields()
\ No newline at end of file
diff --git a/erpnext/patches/v12_0/remove_bank_remittance_custom_fields.py b/erpnext/patches/v12_0/remove_bank_remittance_custom_fields.py
new file mode 100644
index 0000000000..d1446b3227
--- /dev/null
+++ b/erpnext/patches/v12_0/remove_bank_remittance_custom_fields.py
@@ -0,0 +1,14 @@
+from __future__ import unicode_literals
+import frappe
+from erpnext.regional.india.setup import make_custom_fields
+
+def execute():
+ frappe.reload_doc("accounts", "doctype", "tax_category")
+ frappe.reload_doc("stock", "doctype", "item_manufacturer")
+ company = frappe.get_all('Company', filters = {'country': 'India'})
+ if not company:
+ return
+ if frappe.db.exists("Custom Field", "Company-bank_remittance_section"):
+ deprecated_fields = ['bank_remittance_section', 'client_code', 'remittance_column_break', 'product_code']
+ for i in range(len(deprecated_fields)):
+ frappe.delete_doc("Custom Field", 'Company-'+deprecated_fields[i])
\ No newline at end of file
diff --git a/erpnext/regional/india/bank_remittance.py b/erpnext/regional/india/bank_remittance.py
deleted file mode 100644
index 85c9564722..0000000000
--- a/erpnext/regional/india/bank_remittance.py
+++ /dev/null
@@ -1,190 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2018, Frappe and contributors
-# For license information, please see license.txt
-
-from __future__ import unicode_literals
-import frappe
-from frappe.model.document import Document
-from frappe.utils import cint,cstr, today
-from frappe import _
-import re
-import datetime
-from collections import OrderedDict
-
-def create_bank_remittance_txt(name):
- payment_order = frappe.get_cached_doc("Payment Order", name)
-
- no_of_records = len(payment_order.get("references"))
- total_amount = sum(entry.get("amount") for entry in payment_order.get("references"))
-
- product_code, client_code, company_email = frappe.db.get_value("Company",
- filters={'name' : payment_order.company},
- fieldname=['product_code', 'client_code', 'email'])
-
- header, file_name = get_header_row(payment_order, client_code)
- batch = get_batch_row(payment_order, no_of_records, total_amount, product_code)
-
- detail = []
- for ref_doc in payment_order.get("references"):
- detail += get_detail_row(ref_doc, payment_order, company_email)
-
- trailer = get_trailer_row(no_of_records, total_amount)
- detail_records = "\n".join(detail)
-
- return "\n".join([header, batch, detail_records, trailer]), file_name
-
-@frappe.whitelist()
-def generate_report(name):
- data, file_name = create_bank_remittance_txt(name)
-
- f = frappe.get_doc({
- 'doctype': 'File',
- 'file_name': file_name,
- 'content': data,
- "attached_to_doctype": 'Payment Order',
- "attached_to_name": name,
- 'is_private': True
- })
- f.save()
- return {
- 'file_url': f.file_url,
- 'file_name': file_name
- }
-
-def generate_file_name(name, company_account, date):
- ''' generate file name with format (account_code)_mmdd_(payment_order_no) '''
- bank, acc_no = frappe.db.get_value("Bank Account", {"name": company_account}, ['bank', 'bank_account_no'])
- return bank[:1]+str(acc_no)[-4:]+'_'+date.strftime("%m%d")+sanitize_data(name, '')[4:]+'.txt'
-
-def get_header_row(doc, client_code):
- ''' Returns header row and generated file name '''
- file_name = generate_file_name(doc.name, doc.company_bank_account, doc.posting_date)
- header = ["H"]
- header.append(validate_field_size(client_code, "Client Code", 20))
- header += [''] * 3
- header.append(validate_field_size(file_name, "File Name", 20))
- return "~".join(header), file_name
-
-def get_batch_row(doc, no_of_records, total_amount, product_code):
- batch = ["B"]
- batch.append(validate_field_size(no_of_records, "No Of Records", 5))
- batch.append(validate_amount(format(total_amount, '0.2f'), 17))
- batch.append(sanitize_data(doc.name, '_')[:20])
- batch.append(format_date(doc.posting_date))
- batch.append(validate_field_size(product_code,"Product Code", 20))
- return "~".join(batch)
-
-def get_detail_row(ref_doc, payment_entry, company_email):
-
- payment_date = format_date(payment_entry.posting_date)
- payment_entry = frappe.get_cached_doc('Payment Entry', ref_doc.payment_entry)
- supplier_bank_details = frappe.get_cached_doc('Bank Account', ref_doc.bank_account)
- company_bank_acc_no = frappe.db.get_value("Bank Account", {'name': payment_entry.bank_account}, ['bank_account_no'])
-
- addr_link = frappe.db.get_value('Dynamic Link',
- {
- 'link_doctype': 'Supplier',
- 'link_name': 'Sample Supplier',
- 'parenttype':'Address',
- 'parent': ('like', '%-Billing')
- }, 'parent')
-
- supplier_billing_address = frappe.get_cached_doc('Address', addr_link)
- email = ','.join(filter(None, [supplier_billing_address.email_id, company_email]))
-
- detail = OrderedDict(
- record_identifier='D',
- payment_ref_no=sanitize_data(ref_doc.payment_entry),
- payment_type=cstr(payment_entry.mode_of_payment)[:10],
- amount=str(validate_amount(format(ref_doc.amount, '.2f'),13)),
- payment_date=payment_date,
- instrument_date=payment_date,
- instrument_number='',
- dr_account_no_client=str(validate_field_size(company_bank_acc_no, "Company Bank Account", 20)),
- dr_description='',
- dr_ref_no='',
- cr_ref_no='',
- bank_code_indicator='M',
- beneficiary_code='',
- beneficiary_name=sanitize_data(validate_information(payment_entry, "party", 160), ' '),
- beneficiary_bank=sanitize_data(validate_information(supplier_bank_details, "bank", 10)),
- beneficiary_branch_code=cstr(validate_information(supplier_bank_details, "branch_code", 11)),
- beneficiary_acc_no=validate_information(supplier_bank_details, "bank_account_no", 20),
- location='',
- print_location='',
- beneficiary_address_1=validate_field_size(sanitize_data(cstr(supplier_billing_address.address_line1), ' '), " Beneficiary Address 1", 50),
- beneficiary_address_2=validate_field_size(sanitize_data(cstr(supplier_billing_address.address_line2), ' '), " Beneficiary Address 2", 50),
- beneficiary_address_3='',
- beneficiary_address_4='',
- beneficiary_address_5='',
- beneficiary_city=validate_field_size(cstr(supplier_billing_address.city), "Beneficiary City", 20),
- beneficiary_zipcode=validate_field_size(cstr(supplier_billing_address.pincode), "Pin Code", 6),
- beneficiary_state=validate_field_size(cstr(supplier_billing_address.state), "Beneficiary State", 20),
- beneficiary_email=cstr(email)[:255],
- beneficiary_mobile=validate_field_size(cstr(supplier_billing_address.phone), "Beneficiary Mobile", 10),
- payment_details_1='',
- payment_details_2='',
- payment_details_3='',
- payment_details_4='',
- delivery_mode=''
- )
- detail_record = ["~".join(list(detail.values()))]
-
- detail_record += get_advice_rows(payment_entry)
- return detail_record
-
-def get_advice_rows(payment_entry):
- ''' Returns multiple advice rows for a single detail entry '''
- payment_entry_date = payment_entry.posting_date.strftime("%b%y%d%m").upper()
- mode_of_payment = payment_entry.mode_of_payment
- advice_rows = []
- for record in payment_entry.references:
- advice = ['E']
- advice.append(cstr(mode_of_payment))
- advice.append(cstr(record.total_amount))
- advice.append('')
- advice.append(cstr(record.outstanding_amount))
- advice.append(record.reference_name)
- advice.append(format_date(record.due_date))
- advice.append(payment_entry_date)
- advice_rows.append("~".join(advice))
- return advice_rows
-
-def get_trailer_row(no_of_records, total_amount):
- ''' Returns trailer row '''
- trailer = ["T"]
- trailer.append(validate_field_size(no_of_records, "No of Records", 5))
- trailer.append(validate_amount(format(total_amount, "0.2f"), 17))
- return "~".join(trailer)
-
-def sanitize_data(val, replace_str=''):
- ''' Remove all the non-alphanumeric characters from string '''
- pattern = re.compile('[\W_]+')
- return pattern.sub(replace_str, val)
-
-def format_date(val):
- ''' Convert a datetime object to DD/MM/YYYY format '''
- return val.strftime("%d/%m/%Y")
-
-def validate_amount(val, max_int_size):
- ''' Validate amount to be within the allowed limits '''
- int_size = len(str(val).split('.')[0])
-
- if int_size > max_int_size:
- frappe.throw(_("Amount for a single transaction exceeds maximum allowed amount, create a separate payment order by splitting the transactions"))
-
- return val
-
-def validate_information(obj, attr, max_size):
- ''' Checks if the information is not set in the system and is within the size '''
- if hasattr(obj, attr):
- return validate_field_size(getattr(obj, attr), frappe.unscrub(attr), max_size)
-
- else:
- frappe.throw(_("{0} is mandatory for generating remittance payments, set the field and try again".format(frappe.unscrub(attr))))
-
-def validate_field_size(val, label, max_size):
- ''' check the size of the val '''
- if len(cstr(val)) > max_size:
- frappe.throw(_("{0} field is limited to size {1}".format(label, max_size)))
- return cstr(val)
\ No newline at end of file
diff --git a/erpnext/regional/india/setup.py b/erpnext/regional/india/setup.py
index 40b98ed19a..756c17dc3b 100644
--- a/erpnext/regional/india/setup.py
+++ b/erpnext/regional/india/setup.py
@@ -407,14 +407,6 @@ def make_custom_fields(update=True):
fieldtype='Link', options='Salary Component', insert_after='basic_component'),
dict(fieldname='arrear_component', label='Arrear Component',
fieldtype='Link', options='Salary Component', insert_after='hra_component'),
- dict(fieldname='bank_remittance_section', label='Bank Remittance Settings',
- fieldtype='Section Break', collapsible=1, insert_after='arrear_component'),
- dict(fieldname='client_code', label='Client Code', fieldtype='Data',
- insert_after='bank_remittance_section'),
- dict(fieldname='remittance_column_break', fieldtype='Column Break',
- insert_after='client_code'),
- dict(fieldname='product_code', label='Product Code', fieldtype='Data',
- insert_after='remittance_column_break'),
],
'Employee Tax Exemption Declaration':[
dict(fieldname='hra_section', label='HRA Exemption',
From fe579c2efdfe13fae20ef33986d535646dc6c579 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Fri, 23 Aug 2019 16:31:20 +0530
Subject: [PATCH 319/484] fix: show a descriptive message on submission of
duplicate account (#18486)
* fix: show a descriptive message on submission of duplicate account
* Update account.py
---
erpnext/accounts/doctype/account/account.py | 21 ++++++++++++++++++++-
1 file changed, 20 insertions(+), 1 deletion(-)
diff --git a/erpnext/accounts/doctype/account/account.py b/erpnext/accounts/doctype/account/account.py
index 0e57b3f198..1adc4c4d2f 100644
--- a/erpnext/accounts/doctype/account/account.py
+++ b/erpnext/accounts/doctype/account/account.py
@@ -128,7 +128,8 @@ class Account(NestedSet):
"account_currency": self.account_currency,
"parent_account": parent_acc_name_map[company]
})
- doc.save()
+ if not self.check_if_child_acc_exists(doc):
+ doc.save()
frappe.msgprint(_("Account {0} is added in the child company {1}")
.format(doc.name, company))
@@ -172,6 +173,24 @@ class Account(NestedSet):
if frappe.db.get_value("GL Entry", {"account": self.name}):
frappe.throw(_("Currency can not be changed after making entries using some other currency"))
+ def check_if_child_acc_exists(self, doc):
+ ''' Checks if a account in parent company exists in the '''
+ info = frappe.db.get_value("Account", {
+ "account_name": doc.account_name,
+ "account_number": doc.account_number
+ }, ['company', 'account_currency', 'is_group', 'root_type', 'account_type', 'balance_must_be', 'account_name'], as_dict=1)
+
+ if not info:
+ return
+
+ doc = vars(doc)
+ dict_diff = [k for k in info if k in doc and info[k] != doc[k] and k != "company"]
+ if dict_diff:
+ frappe.throw(_("Account {0} already exists in child company {1}. The following fields have different values, they should be same:")
+ .format(info.account_name, info.company, ''.join(dict_diff)))
+ else:
+ return True
+
def convert_group_to_ledger(self):
if self.check_if_child_exists():
throw(_("Account with child nodes cannot be converted to ledger"))
From d8c262fd5c9611c65a33bafac57c2084f3dc8bbb Mon Sep 17 00:00:00 2001
From: Nabin Hait
Date: Fri, 23 Aug 2019 16:32:58 +0530
Subject: [PATCH 320/484] fix: Translations of strings (#18825)
---
erpnext/accounts/report/balance_sheet/balance_sheet.py | 6 +++---
.../payment_period_based_on_invoice_date.js | 4 ++--
.../payment_period_based_on_invoice_date.py | 10 +++++-----
.../profit_and_loss_statement.py | 6 +++---
erpnext/selling/page/point_of_sale/point_of_sale.js | 2 +-
5 files changed, 14 insertions(+), 14 deletions(-)
diff --git a/erpnext/accounts/report/balance_sheet/balance_sheet.py b/erpnext/accounts/report/balance_sheet/balance_sheet.py
index 7d9acf26ed..97ce4f21e8 100644
--- a/erpnext/accounts/report/balance_sheet/balance_sheet.py
+++ b/erpnext/accounts/report/balance_sheet/balance_sheet.py
@@ -135,11 +135,11 @@ def get_chart_data(filters, columns, asset, liability, equity):
datasets = []
if asset_data:
- datasets.append({'name':'Assets', 'values': asset_data})
+ datasets.append({'name': _('Assets'), 'values': asset_data})
if liability_data:
- datasets.append({'name':'Liabilities', 'values': liability_data})
+ datasets.append({'name': _('Liabilities'), 'values': liability_data})
if equity_data:
- datasets.append({'name':'Equity', 'values': equity_data})
+ datasets.append({'name': _('Equity'), 'values': equity_data})
chart = {
"data": {
diff --git a/erpnext/accounts/report/payment_period_based_on_invoice_date/payment_period_based_on_invoice_date.js b/erpnext/accounts/report/payment_period_based_on_invoice_date/payment_period_based_on_invoice_date.js
index ca243944e9..2343eaa846 100644
--- a/erpnext/accounts/report/payment_period_based_on_invoice_date/payment_period_based_on_invoice_date.js
+++ b/erpnext/accounts/report/payment_period_based_on_invoice_date/payment_period_based_on_invoice_date.js
@@ -27,8 +27,8 @@ frappe.query_reports["Payment Period Based On Invoice Date"] = {
fieldname:"payment_type",
label: __("Payment Type"),
fieldtype: "Select",
- options: "Incoming\nOutgoing",
- default: "Incoming"
+ options: __("Incoming") + "\n" + __("Outgoing"),
+ default: __("Incoming")
},
{
"fieldname":"party_type",
diff --git a/erpnext/accounts/report/payment_period_based_on_invoice_date/payment_period_based_on_invoice_date.py b/erpnext/accounts/report/payment_period_based_on_invoice_date/payment_period_based_on_invoice_date.py
index 89e0113fc8..24b5d87b5b 100644
--- a/erpnext/accounts/report/payment_period_based_on_invoice_date/payment_period_based_on_invoice_date.py
+++ b/erpnext/accounts/report/payment_period_based_on_invoice_date/payment_period_based_on_invoice_date.py
@@ -39,8 +39,8 @@ def execute(filters=None):
return columns, data
def validate_filters(filters):
- if (filters.get("payment_type") == "Incoming" and filters.get("party_type") == "Supplier") or \
- (filters.get("payment_type") == "Outgoing" and filters.get("party_type") == "Customer"):
+ if (filters.get("payment_type") == _("Incoming") and filters.get("party_type") == "Supplier") or \
+ (filters.get("payment_type") == _("Outgoing") and filters.get("party_type") == "Customer"):
frappe.throw(_("{0} payment entries can not be filtered by {1}")\
.format(filters.payment_type, filters.party_type))
@@ -51,7 +51,7 @@ def get_columns(filters):
_("Party Type") + "::100",
_("Party") + ":Dynamic Link/Party Type:140",
_("Posting Date") + ":Date:100",
- _("Invoice") + (":Link/Purchase Invoice:130" if filters.get("payment_type") == "Outgoing" else ":Link/Sales Invoice:130"),
+ _("Invoice") + (":Link/Purchase Invoice:130" if filters.get("payment_type") == _("Outgoing") else ":Link/Sales Invoice:130"),
_("Invoice Posting Date") + ":Date:130",
_("Payment Due Date") + ":Date:130",
_("Debit") + ":Currency:120",
@@ -69,7 +69,7 @@ def get_conditions(filters):
conditions = []
if not filters.party_type:
- if filters.payment_type == "Outgoing":
+ if filters.payment_type == _("Outgoing"):
filters.party_type = "Supplier"
else:
filters.party_type = "Customer"
@@ -101,7 +101,7 @@ def get_entries(filters):
def get_invoice_posting_date_map(filters):
invoice_details = {}
- dt = "Sales Invoice" if filters.get("payment_type") == "Incoming" else "Purchase Invoice"
+ dt = "Sales Invoice" if filters.get("payment_type") == _("Incoming") else "Purchase Invoice"
for t in frappe.db.sql("select name, posting_date, due_date from `tab{0}`".format(dt), as_dict=1):
invoice_details[t.name] = t
diff --git a/erpnext/accounts/report/profit_and_loss_statement/profit_and_loss_statement.py b/erpnext/accounts/report/profit_and_loss_statement/profit_and_loss_statement.py
index ac11868cab..d500c8116e 100644
--- a/erpnext/accounts/report/profit_and_loss_statement/profit_and_loss_statement.py
+++ b/erpnext/accounts/report/profit_and_loss_statement/profit_and_loss_statement.py
@@ -75,11 +75,11 @@ def get_chart_data(filters, columns, income, expense, net_profit_loss):
datasets = []
if income_data:
- datasets.append({'name': 'Income', 'values': income_data})
+ datasets.append({'name': _('Income'), 'values': income_data})
if expense_data:
- datasets.append({'name': 'Expense', 'values': expense_data})
+ datasets.append({'name': _('Expense'), 'values': expense_data})
if net_profit:
- datasets.append({'name': 'Net Profit/Loss', 'values': net_profit})
+ datasets.append({'name': _('Net Profit/Loss'), 'values': net_profit})
chart = {
"data": {
diff --git a/erpnext/selling/page/point_of_sale/point_of_sale.js b/erpnext/selling/page/point_of_sale/point_of_sale.js
index d233b41787..d2c2d70dbe 100644
--- a/erpnext/selling/page/point_of_sale/point_of_sale.js
+++ b/erpnext/selling/page/point_of_sale/point_of_sale.js
@@ -4,7 +4,7 @@ frappe.provide('erpnext.pos');
frappe.pages['point-of-sale'].on_page_load = function(wrapper) {
frappe.ui.make_app_page({
parent: wrapper,
- title: 'Point of Sale',
+ title: __('Point of Sale'),
single_column: true
});
From 92095709374ddfdb68c155bcf0f1107fd8527454 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Mon, 26 Aug 2019 06:33:27 +0530
Subject: [PATCH 321/484] feat: Add option to create pick list from material
request
---
.../material_request/material_request.py | 21 ++++++++++++++
erpnext/stock/doctype/pick_list/pick_list.js | 28 +++++++++++--------
.../stock/doctype/pick_list/pick_list.json | 10 ++++++-
erpnext/stock/doctype/pick_list/pick_list.py | 25 ++++++++++++++++-
.../pick_list_item/pick_list_item.json | 17 +++++++++--
5 files changed, 86 insertions(+), 15 deletions(-)
diff --git a/erpnext/stock/doctype/material_request/material_request.py b/erpnext/stock/doctype/material_request/material_request.py
index f2fe44879d..a1cf2f269a 100644
--- a/erpnext/stock/doctype/material_request/material_request.py
+++ b/erpnext/stock/doctype/material_request/material_request.py
@@ -502,3 +502,24 @@ def raise_work_orders(material_request):
frappe.throw(_("Productions Orders cannot be raised for:") + '\n' + new_line_sep(errors))
return work_orders
+
+@frappe.whitelist()
+def create_pick_list(source_name, target_doc=None):
+ doc = get_mapped_doc('Material Request', source_name, {
+ 'Material Request': {
+ 'doctype': 'Pick List',
+ 'validation': {
+ 'docstatus': ['=', 1]
+ }
+ },
+ 'Material Request Item': {
+ 'doctype': 'Pick List Reference Item',
+ 'field_map': {
+ 'name': 'material_request_item',
+ 'qty': 'stock_qty'
+ },
+ # 'condition': lambda doc: abs(doc.transferred_qty) < abs(doc.required_qty)
+ },
+ }, target_doc)
+
+ return doc
\ No newline at end of file
diff --git a/erpnext/stock/doctype/pick_list/pick_list.js b/erpnext/stock/doctype/pick_list/pick_list.js
index c2dddab4c9..0f5ba57bc1 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.js
+++ b/erpnext/stock/doctype/pick_list/pick_list.js
@@ -19,6 +19,13 @@ frappe.ui.form.on('Pick List', {
}
};
});
+ frm.set_query('material_request', () => {
+ return {
+ filters: {
+ 'material_request_type': ['=', frm.doc.purpose]
+ }
+ };
+ });
},
refresh: (frm) => {
frm.trigger('add_get_items_button');
@@ -70,6 +77,15 @@ frappe.ui.form.on('Pick List', {
}, __("Select Quantity"), __('Get Items'));
});
},
+ material_request: (frm) => {
+ frm.clear_table('items');
+ frm.clear_table('locations');
+ erpnext.utils.map_current_doc({
+ method: 'erpnext.stock.doctype.material_request.material_request.create_pick_list',
+ target: frm,
+ source_name: frm.doc.material_request
+ });
+ },
purpose: (frm) => {
frm.clear_table('items');
frm.clear_table('locations');
@@ -116,14 +132,4 @@ frappe.ui.form.on('Pick List', {
});
});
}
-});
-
-
-// frappe.ui.form.on('Pick List Reference Item', {
-// item_code: (frm, cdt, cdn) => {
-// let row = locals[cdt][cdn];
-// if (row.item_code) {
-// frappe.xcall('');
-// }
-// }
-// });
\ No newline at end of file
+});
\ No newline at end of file
diff --git a/erpnext/stock/doctype/pick_list/pick_list.json b/erpnext/stock/doctype/pick_list/pick_list.json
index 6eca1c67d4..91fc6f8321 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.json
+++ b/erpnext/stock/doctype/pick_list/pick_list.json
@@ -8,6 +8,7 @@
"purpose",
"customer",
"work_order",
+ "material_request",
"for_qty",
"column_break_4",
"parent_warehouse",
@@ -97,10 +98,17 @@
"fieldtype": "Select",
"label": "Purpose",
"options": "Material Transfer for Manufacture\nMaterial Issue\nMaterial Transfer\nDelivery against Sales Order"
+ },
+ {
+ "depends_on": "eval:['Material Transfer', 'Material Issue'].includes(doc.purpose)",
+ "fieldname": "material_request",
+ "fieldtype": "Link",
+ "label": "Material Request",
+ "options": "Material Request"
}
],
"is_submittable": 1,
- "modified": "2019-08-22 16:58:07.270447",
+ "modified": "2019-08-23 12:34:00.223445",
"modified_by": "Administrator",
"module": "Stock",
"name": "Pick List",
diff --git a/erpnext/stock/doctype/pick_list/pick_list.py b/erpnext/stock/doctype/pick_list/pick_list.py
index 9b8bdfe6ee..a8955def74 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.py
+++ b/erpnext/stock/doctype/pick_list/pick_list.py
@@ -41,6 +41,8 @@ class PickList(Document):
'item_code': item_code,
'sales_order': item_doc.sales_order,
'sales_order_item': item_doc.sales_order_item,
+ 'material_request': item_doc.material_request,
+ 'material_request_item': item_doc.material_request_item,
'uom': item_doc.uom,
'stock_uom': item_doc.stock_uom,
'conversion_factor': item_doc.conversion_factor,
@@ -231,7 +233,6 @@ def set_delivery_note_missing_values(target):
target.run_method('set_po_nos')
target.run_method('calculate_taxes_and_totals')
-
@frappe.whitelist()
def create_stock_entry(pick_list):
pick_list = frappe.get_doc(json.loads(pick_list))
@@ -282,6 +283,28 @@ def create_stock_entry(pick_list):
return stock_entry.as_dict()
+
+@frappe.whitelist()
+def create_stock_entry_with_material_request_items(pick_list):
+ stock_entry = frappe.new_doc('Stock Entry')
+ stock_entry.pick_list = pick_list.get('name')
+ stock_entry.purpose = pick_list.get('purpose')
+ stock_entry.set_stock_entry_type()
+
+ doc = get_mapped_doc("Work Order", source_name, {
+ "Work Order": {
+ "doctype": "Pick List",
+ "validation": {
+ "docstatus": ["=", 1]
+ }
+ },
+ "Work Order Item": {
+ "doctype": "Pick List Reference Item",
+ "postprocess": update_item_quantity,
+ "condition": lambda doc: abs(doc.transferred_qty) < abs(doc.required_qty)
+ },
+ }, target_doc)
+
@frappe.whitelist()
def get_pending_work_orders(doctype, txt, searchfield, start, page_length, filters, as_dict):
return frappe.db.sql("""
diff --git a/erpnext/stock/doctype/pick_list_item/pick_list_item.json b/erpnext/stock/doctype/pick_list_item/pick_list_item.json
index 9ee806acf5..0a8f4cbebe 100644
--- a/erpnext/stock/doctype/pick_list_item/pick_list_item.json
+++ b/erpnext/stock/doctype/pick_list_item/pick_list_item.json
@@ -24,7 +24,9 @@
"batch_no",
"column_break_15",
"sales_order",
- "sales_order_item"
+ "sales_order_item",
+ "material_request",
+ "material_request_item"
],
"fields": [
{
@@ -152,10 +154,21 @@
{
"fieldname": "column_break_20",
"fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "material_request",
+ "fieldtype": "Link",
+ "label": "Material Request",
+ "options": "Material Request"
+ },
+ {
+ "fieldname": "material_request_item",
+ "fieldtype": "Data",
+ "label": "Material Request Item"
}
],
"istable": 1,
- "modified": "2019-08-14 18:41:37.727388",
+ "modified": "2019-08-23 14:13:11.088354",
"modified_by": "Administrator",
"module": "Stock",
"name": "Pick List Item",
From a1dc15269548767dfd40edde60aa5827117a192f Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Mon, 26 Aug 2019 06:57:43 +0530
Subject: [PATCH 322/484] fix: Move get items location button below items table
---
erpnext/stock/doctype/pick_list/pick_list.js | 13 ++++++++-----
erpnext/stock/doctype/pick_list/pick_list.json | 9 ++++++++-
.../doctype/pick_list_item/pick_list_item.json | 8 +++++---
.../pick_list_reference_item.json | 8 +++++---
4 files changed, 26 insertions(+), 12 deletions(-)
diff --git a/erpnext/stock/doctype/pick_list/pick_list.js b/erpnext/stock/doctype/pick_list/pick_list.js
index 0f5ba57bc1..75d0511e50 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.js
+++ b/erpnext/stock/doctype/pick_list/pick_list.js
@@ -27,14 +27,17 @@ frappe.ui.form.on('Pick List', {
};
});
},
+ get_item_locations(frm) {
+ frm.call('set_item_locations');
+ },
refresh: (frm) => {
frm.trigger('add_get_items_button');
- if (frm.doc.items && (frm.doc.items.length > 1 || frm.doc.items[0].item_code) && frm.doc.docstatus === 0) {
- frm.add_custom_button(__('Get Item Locations'), () => {
- frm.call('set_item_locations');
- }).addClass('btn-primary');
- }
+ // if (frm.doc.items && (frm.doc.items.length > 1 || frm.doc.items[0].item_code) && frm.doc.docstatus === 0) {
+ // frm.add_custom_button(__('Get Item Locations'), () => {
+ // frm.call('set_item_locations');
+ // }).addClass('btn-primary');
+ // }
if (frm.doc.docstatus === 1) {
if (frm.doc.purpose === 'Delivery against Sales Order') {
frm.add_custom_button(__('Delivery Note'), () => frm.trigger('create_delivery_note'), __('Create'));
diff --git a/erpnext/stock/doctype/pick_list/pick_list.json b/erpnext/stock/doctype/pick_list/pick_list.json
index 91fc6f8321..dbfd7d1bf2 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.json
+++ b/erpnext/stock/doctype/pick_list/pick_list.json
@@ -15,6 +15,7 @@
"company",
"section_break_4",
"items",
+ "get_item_locations",
"section_break_6",
"locations",
"amended_from"
@@ -105,10 +106,16 @@
"fieldtype": "Link",
"label": "Material Request",
"options": "Material Request"
+ },
+ {
+ "depends_on": "eval: doc.items.length && (doc.items.length > 1 || doc.items[0].item_code) && doc.docstatus === 0",
+ "fieldname": "get_item_locations",
+ "fieldtype": "Button",
+ "label": "Get Item Locations"
}
],
"is_submittable": 1,
- "modified": "2019-08-23 12:34:00.223445",
+ "modified": "2019-08-26 06:52:04.532885",
"modified_by": "Administrator",
"module": "Stock",
"name": "Pick List",
diff --git a/erpnext/stock/doctype/pick_list_item/pick_list_item.json b/erpnext/stock/doctype/pick_list_item/pick_list_item.json
index 0a8f4cbebe..fdac9e58cf 100644
--- a/erpnext/stock/doctype/pick_list_item/pick_list_item.json
+++ b/erpnext/stock/doctype/pick_list_item/pick_list_item.json
@@ -159,16 +159,18 @@
"fieldname": "material_request",
"fieldtype": "Link",
"label": "Material Request",
- "options": "Material Request"
+ "options": "Material Request",
+ "read_only": 1
},
{
"fieldname": "material_request_item",
"fieldtype": "Data",
- "label": "Material Request Item"
+ "label": "Material Request Item",
+ "read_only": 1
}
],
"istable": 1,
- "modified": "2019-08-23 14:13:11.088354",
+ "modified": "2019-08-26 06:54:06.783255",
"modified_by": "Administrator",
"module": "Stock",
"name": "Pick List Item",
diff --git a/erpnext/stock/doctype/pick_list_reference_item/pick_list_reference_item.json b/erpnext/stock/doctype/pick_list_reference_item/pick_list_reference_item.json
index e6984ef323..b549a08e10 100644
--- a/erpnext/stock/doctype/pick_list_reference_item/pick_list_reference_item.json
+++ b/erpnext/stock/doctype/pick_list_reference_item/pick_list_reference_item.json
@@ -85,16 +85,18 @@
"fieldname": "material_request",
"fieldtype": "Link",
"label": "Material Request",
- "options": "Material Request"
+ "options": "Material Request",
+ "read_only": 1
},
{
"fieldname": "material_request_item",
"fieldtype": "Data",
- "label": "Material Request Item"
+ "label": "Material Request Item",
+ "read_only": 1
}
],
"istable": 1,
- "modified": "2019-08-22 14:19:19.725540",
+ "modified": "2019-08-26 06:54:50.702552",
"modified_by": "Administrator",
"module": "Stock",
"name": "Pick List Reference Item",
From be9f4ea48702b115c20c68de036ab3012c4d8830 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Mon, 26 Aug 2019 08:38:37 +0530
Subject: [PATCH 323/484] fix: Add button to create pick list from material
request
---
.../doctype/material_request/material_request.js | 15 ++++++++++++++-
.../doctype/material_request/material_request.py | 3 +++
2 files changed, 17 insertions(+), 1 deletion(-)
diff --git a/erpnext/stock/doctype/material_request/material_request.js b/erpnext/stock/doctype/material_request/material_request.js
index 96e31ff6ff..feaa4132b8 100644
--- a/erpnext/stock/doctype/material_request/material_request.js
+++ b/erpnext/stock/doctype/material_request/material_request.js
@@ -55,13 +55,19 @@ frappe.ui.form.on('Material Request', {
if (frm.doc.docstatus == 1 && frm.doc.status != 'Stopped') {
if (flt(frm.doc.per_ordered, 2) < 100) {
- // make
+ let add_create_pick_list_button = () => {
+ frm.add_custom_button(__('Pick List'),
+ () => frm.events.create_pick_list(frm), __('Create'));
+ }
+
if (frm.doc.material_request_type === "Material Transfer") {
+ add_create_pick_list_button();
frm.add_custom_button(__("Transfer Material"),
() => frm.events.make_stock_entry(frm), __('Create'));
}
if (frm.doc.material_request_type === "Material Issue") {
+ add_create_pick_list_button();
frm.add_custom_button(__("Issue Material"),
() => frm.events.make_stock_entry(frm), __('Create'));
}
@@ -258,6 +264,13 @@ frappe.ui.form.on('Material Request', {
});
},
+ create_pick_list: (frm) => {
+ frappe.model.open_mapped_doc({
+ method: "erpnext.stock.doctype.material_request.material_request.create_pick_list",
+ frm: frm
+ });
+ },
+
raise_work_orders: function(frm) {
frappe.call({
method:"erpnext.stock.doctype.material_request.material_request.raise_work_orders",
diff --git a/erpnext/stock/doctype/material_request/material_request.py b/erpnext/stock/doctype/material_request/material_request.py
index a1cf2f269a..7040d83215 100644
--- a/erpnext/stock/doctype/material_request/material_request.py
+++ b/erpnext/stock/doctype/material_request/material_request.py
@@ -508,6 +508,9 @@ def create_pick_list(source_name, target_doc=None):
doc = get_mapped_doc('Material Request', source_name, {
'Material Request': {
'doctype': 'Pick List',
+ 'field_map': {
+ 'material_request_type': 'purpose'
+ },
'validation': {
'docstatus': ['=', 1]
}
From ecc801d3d835e117c09345e6c0a7ff63ea2f4f63 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Mon, 26 Aug 2019 08:39:11 +0530
Subject: [PATCH 324/484] fix: Add pick list field to delivery note
---
.../doctype/delivery_note/delivery_note.json | 5480 ++++-------------
1 file changed, 1137 insertions(+), 4343 deletions(-)
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.json b/erpnext/stock/doctype/delivery_note/delivery_note.json
index b5f2c3404e..1116273ace 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.json
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.json
@@ -1,4514 +1,1308 @@
{
- "allow_copy": 0,
- "allow_events_in_timeline": 0,
- "allow_guest_to_view": 0,
- "allow_import": 1,
- "allow_rename": 0,
- "autoname": "naming_series:",
- "beta": 0,
- "creation": "2013-05-24 19:29:09",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "Document",
- "editable_grid": 0,
+ "allow_import": 1,
+ "autoname": "naming_series:",
+ "creation": "2013-05-24 19:29:09",
+ "doctype": "DocType",
+ "document_type": "Document",
+ "field_order": [
+ "delivery_to_section",
+ "column_break0",
+ "title",
+ "naming_series",
+ "customer",
+ "customer_name",
+ "column_break1",
+ "amended_from",
+ "company",
+ "posting_date",
+ "posting_time",
+ "set_posting_time",
+ "is_return",
+ "issue_credit_note",
+ "return_against",
+ "customer_po_details",
+ "po_no",
+ "section_break_18",
+ "pick_list",
+ "column_break_17",
+ "po_date",
+ "contact_info",
+ "shipping_address_name",
+ "shipping_address",
+ "contact_person",
+ "contact_display",
+ "contact_mobile",
+ "contact_email",
+ "col_break21",
+ "customer_address",
+ "tax_id",
+ "address_display",
+ "company_address",
+ "company_address_display",
+ "currency_and_price_list",
+ "currency",
+ "conversion_rate",
+ "col_break23",
+ "selling_price_list",
+ "price_list_currency",
+ "plc_conversion_rate",
+ "ignore_pricing_rule",
+ "sec_warehouse",
+ "set_warehouse",
+ "col_break_warehouse",
+ "to_warehouse",
+ "items_section",
+ "scan_barcode",
+ "items",
+ "pricing_rule_details",
+ "pricing_rules",
+ "packing_list",
+ "packed_items",
+ "product_bundle_help",
+ "section_break_31",
+ "total_qty",
+ "base_total",
+ "base_net_total",
+ "column_break_33",
+ "total",
+ "net_total",
+ "total_net_weight",
+ "taxes_section",
+ "tax_category",
+ "column_break_39",
+ "shipping_rule",
+ "section_break_41",
+ "taxes_and_charges",
+ "taxes",
+ "sec_tax_breakup",
+ "other_charges_calculation",
+ "section_break_44",
+ "base_total_taxes_and_charges",
+ "column_break_47",
+ "total_taxes_and_charges",
+ "section_break_49",
+ "apply_discount_on",
+ "base_discount_amount",
+ "column_break_51",
+ "additional_discount_percentage",
+ "discount_amount",
+ "totals",
+ "base_grand_total",
+ "base_rounding_adjustment",
+ "base_rounded_total",
+ "base_in_words",
+ "column_break3",
+ "grand_total",
+ "rounding_adjustment",
+ "rounded_total",
+ "in_words",
+ "terms_section_break",
+ "tc_name",
+ "terms",
+ "transporter_info",
+ "transporter",
+ "driver",
+ "lr_no",
+ "vehicle_no",
+ "col_break34",
+ "transporter_name",
+ "driver_name",
+ "lr_date",
+ "more_info",
+ "project",
+ "campaign",
+ "source",
+ "column_break5",
+ "per_billed",
+ "customer_group",
+ "territory",
+ "printing_details",
+ "letter_head",
+ "select_print_heading",
+ "language",
+ "column_break_88",
+ "print_without_amount",
+ "group_same_items",
+ "section_break_83",
+ "status",
+ "per_installed",
+ "installation_status",
+ "column_break_89",
+ "excise_page",
+ "instructions",
+ "subscription_section",
+ "auto_repeat",
+ "sales_team_section_break",
+ "sales_partner",
+ "column_break7",
+ "commission_rate",
+ "total_commission",
+ "section_break1",
+ "sales_team"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "delivery_to_section",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Delivery To",
- "length": 0,
- "no_copy": 0,
- "options": "fa fa-user",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "delivery_to_section",
+ "fieldtype": "Section Break",
+ "label": "Delivery To",
+ "options": "fa fa-user"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break0",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "oldfieldtype": "Column Break",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "print_width": "50%",
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
+ "fieldname": "column_break0",
+ "fieldtype": "Column Break",
+ "oldfieldtype": "Column Break",
+ "print_width": "50%",
"width": "50%"
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "{customer_name}",
- "fieldname": "title",
- "fieldtype": "Data",
- "hidden": 1,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Title",
- "length": 0,
- "no_copy": 1,
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "allow_on_submit": 1,
+ "default": "{customer_name}",
+ "fieldname": "title",
+ "fieldtype": "Data",
+ "hidden": 1,
+ "label": "Title",
+ "no_copy": 1,
+ "print_hide": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "",
- "fieldname": "naming_series",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Series",
- "length": 0,
- "no_copy": 1,
- "oldfieldname": "naming_series",
- "oldfieldtype": "Select",
- "options": "MAT-DN-.YYYY.-",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 1,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "naming_series",
+ "fieldtype": "Select",
+ "label": "Series",
+ "no_copy": 1,
+ "oldfieldname": "naming_series",
+ "oldfieldtype": "Select",
+ "options": "MAT-DN-.YYYY.-",
+ "print_hide": 1,
+ "reqd": 1,
+ "set_only_once": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "customer",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 1,
- "in_list_view": 0,
- "in_standard_filter": 1,
- "label": "Customer",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "customer",
- "oldfieldtype": "Link",
- "options": "Customer",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 1,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "customer",
+ "fieldtype": "Link",
+ "in_global_search": 1,
+ "in_standard_filter": 1,
+ "label": "Customer",
+ "oldfieldname": "customer",
+ "oldfieldtype": "Link",
+ "options": "Customer",
+ "print_hide": 1,
+ "reqd": 1,
+ "search_index": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 1,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "customer",
- "fetch_from": "customer.customer_name",
- "fieldname": "customer_name",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 1,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Customer Name",
- "length": 0,
- "no_copy": 0,
- "options": "",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "bold": 1,
+ "depends_on": "customer",
+ "fetch_from": "customer.customer_name",
+ "fieldname": "customer_name",
+ "fieldtype": "Data",
+ "in_global_search": 1,
+ "label": "Customer Name",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break1",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "oldfieldtype": "Column Break",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "column_break1",
+ "fieldtype": "Column Break",
+ "oldfieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "amended_from",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 1,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Amended From",
- "length": 0,
- "no_copy": 1,
- "oldfieldname": "amended_from",
- "oldfieldtype": "Data",
- "options": "Delivery Note",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "print_width": "150px",
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
+ "fieldname": "amended_from",
+ "fieldtype": "Link",
+ "ignore_user_permissions": 1,
+ "label": "Amended From",
+ "no_copy": 1,
+ "oldfieldname": "amended_from",
+ "oldfieldtype": "Data",
+ "options": "Delivery Note",
+ "print_hide": 1,
+ "print_width": "150px",
+ "read_only": 1,
"width": "150px"
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "",
- "fieldname": "company",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 1,
- "label": "Company",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "company",
- "oldfieldtype": "Link",
- "options": "Company",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "print_width": "150px",
- "read_only": 0,
- "remember_last_selected_value": 1,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "in_standard_filter": 1,
+ "label": "Company",
+ "oldfieldname": "company",
+ "oldfieldtype": "Link",
+ "options": "Company",
+ "print_hide": 1,
+ "print_width": "150px",
+ "remember_last_selected_value": 1,
+ "reqd": 1,
"width": "150px"
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "Today",
- "depends_on": "",
- "fieldname": "posting_date",
- "fieldtype": "Date",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Date",
- "length": 0,
- "no_copy": 1,
- "oldfieldname": "posting_date",
- "oldfieldtype": "Date",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "print_width": "100px",
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 1,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
+ "default": "Today",
+ "fieldname": "posting_date",
+ "fieldtype": "Date",
+ "label": "Date",
+ "no_copy": 1,
+ "oldfieldname": "posting_date",
+ "oldfieldtype": "Date",
+ "print_width": "100px",
+ "reqd": 1,
+ "search_index": 1,
"width": "100px"
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
- "description": "",
- "fieldname": "posting_time",
- "fieldtype": "Time",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Posting Time",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "posting_time",
- "oldfieldtype": "Time",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "print_width": "100px",
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
+ "fieldname": "posting_time",
+ "fieldtype": "Time",
+ "label": "Posting Time",
+ "oldfieldname": "posting_time",
+ "oldfieldtype": "Time",
+ "print_hide": 1,
+ "print_width": "100px",
+ "reqd": 1,
"width": "100px"
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:doc.docstatus==0",
- "fieldname": "set_posting_time",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Edit Posting Date and Time",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "default": "0",
+ "depends_on": "eval:doc.docstatus==0",
+ "fieldname": "set_posting_time",
+ "fieldtype": "Check",
+ "label": "Edit Posting Date and Time",
+ "print_hide": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "is_return",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Is Return",
- "length": 0,
- "no_copy": 1,
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "default": "0",
+ "fieldname": "is_return",
+ "fieldtype": "Check",
+ "label": "Is Return",
+ "no_copy": 1,
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "is_return",
- "fieldname": "issue_credit_note",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Issue Credit Note",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "default": "0",
+ "depends_on": "is_return",
+ "fieldname": "issue_credit_note",
+ "fieldtype": "Check",
+ "label": "Issue Credit Note"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "is_return",
- "fieldname": "return_against",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Return Against Delivery Note",
- "length": 0,
- "no_copy": 1,
- "options": "Delivery Note",
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "depends_on": "is_return",
+ "fieldname": "return_against",
+ "fieldtype": "Link",
+ "label": "Return Against Delivery Note",
+ "no_copy": 1,
+ "options": "Delivery Note",
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "collapsible_depends_on": "po_no",
- "columns": 0,
- "fieldname": "customer_po_details",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Customer PO Details",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "collapsible": 1,
+ "collapsible_depends_on": "po_no",
+ "fieldname": "customer_po_details",
+ "fieldtype": "Section Break",
+ "label": "Customer PO Details"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "po_no",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Customer's Purchase Order No",
- "length": 0,
- "no_copy": 1,
- "oldfieldname": "po_no",
- "oldfieldtype": "Data",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "print_width": "100px",
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
+ "allow_on_submit": 1,
+ "fieldname": "po_no",
+ "fieldtype": "Data",
+ "label": "Customer's Purchase Order No",
+ "no_copy": 1,
+ "oldfieldname": "po_no",
+ "oldfieldtype": "Data",
+ "print_hide": 1,
+ "print_width": "100px",
"width": "100px"
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_17",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "column_break_17",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:doc.po_no",
- "fieldname": "po_date",
- "fieldtype": "Date",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Customer's Purchase Order Date",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "po_date",
- "oldfieldtype": "Data",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "print_width": "100px",
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
+ "depends_on": "eval:doc.po_no",
+ "fieldname": "po_date",
+ "fieldtype": "Date",
+ "label": "Customer's Purchase Order Date",
+ "oldfieldname": "po_date",
+ "oldfieldtype": "Data",
+ "print_hide": 1,
+ "print_width": "100px",
+ "read_only": 1,
"width": "100px"
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "columns": 0,
- "depends_on": "customer",
- "fieldname": "contact_info",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Address and Contact",
- "length": 0,
- "no_copy": 0,
- "options": "fa fa-bullhorn",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "collapsible": 1,
+ "depends_on": "customer",
+ "fieldname": "contact_info",
+ "fieldtype": "Section Break",
+ "label": "Address and Contact",
+ "options": "fa fa-bullhorn"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "shipping_address_name",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Shipping Address",
- "length": 0,
- "no_copy": 0,
- "options": "Address",
- "permlevel": 0,
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "shipping_address_name",
+ "fieldtype": "Link",
+ "label": "Shipping Address",
+ "options": "Address",
+ "print_hide": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "shipping_address",
- "fieldtype": "Small Text",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Shipping Address",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "shipping_address",
+ "fieldtype": "Small Text",
+ "label": "Shipping Address",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "contact_person",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Contact Person",
- "length": 0,
- "no_copy": 0,
- "options": "Contact",
- "permlevel": 0,
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "contact_person",
+ "fieldtype": "Link",
+ "label": "Contact Person",
+ "options": "Contact",
+ "print_hide": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "contact_display",
- "fieldtype": "Small Text",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 1,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Contact",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "contact_display",
+ "fieldtype": "Small Text",
+ "in_global_search": 1,
+ "label": "Contact",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "contact_mobile",
- "fieldtype": "Small Text",
- "hidden": 1,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Mobile No",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "contact_mobile",
+ "fieldtype": "Small Text",
+ "hidden": 1,
+ "label": "Mobile No",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "contact_email",
- "fieldtype": "Data",
- "hidden": 1,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Contact Email",
- "length": 0,
- "no_copy": 0,
- "options": "Email",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "contact_email",
+ "fieldtype": "Data",
+ "hidden": 1,
+ "label": "Contact Email",
+ "options": "Email",
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "col_break21",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "print_width": "50%",
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
+ "fieldname": "col_break21",
+ "fieldtype": "Column Break",
+ "print_width": "50%",
"width": "50%"
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "customer",
- "fieldname": "customer_address",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Billing Address Name",
- "length": 0,
- "no_copy": 0,
- "options": "Address",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "depends_on": "customer",
+ "fieldname": "customer_address",
+ "fieldtype": "Link",
+ "label": "Billing Address Name",
+ "options": "Address",
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "tax_id",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Tax Id",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "tax_id",
+ "fieldtype": "Data",
+ "label": "Tax Id",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "address_display",
- "fieldtype": "Small Text",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Billing Address",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "address_display",
+ "fieldtype": "Small Text",
+ "label": "Billing Address",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "company_address",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Company Address Name",
- "length": 0,
- "no_copy": 0,
- "options": "Address",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "company_address",
+ "fieldtype": "Link",
+ "label": "Company Address Name",
+ "options": "Address"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "company_address_display",
- "fieldtype": "Small Text",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Company Address",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "company_address_display",
+ "fieldtype": "Small Text",
+ "label": "Company Address"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "columns": 0,
- "fieldname": "currency_and_price_list",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Currency and Price List",
- "length": 0,
- "no_copy": 0,
- "options": "fa fa-tag",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "collapsible": 1,
+ "fieldname": "currency_and_price_list",
+ "fieldtype": "Section Break",
+ "label": "Currency and Price List",
+ "options": "fa fa-tag"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "currency",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Currency",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "currency",
- "oldfieldtype": "Select",
- "options": "Currency",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "currency",
+ "fieldtype": "Link",
+ "label": "Currency",
+ "oldfieldname": "currency",
+ "oldfieldtype": "Select",
+ "options": "Currency",
+ "print_hide": 1,
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "Rate at which customer's currency is converted to company's base currency",
- "fieldname": "conversion_rate",
- "fieldtype": "Float",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Exchange Rate",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "conversion_rate",
- "oldfieldtype": "Currency",
- "permlevel": 0,
- "precision": "9",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "description": "Rate at which customer's currency is converted to company's base currency",
+ "fieldname": "conversion_rate",
+ "fieldtype": "Float",
+ "label": "Exchange Rate",
+ "oldfieldname": "conversion_rate",
+ "oldfieldtype": "Currency",
+ "precision": "9",
+ "print_hide": 1,
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "col_break23",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "col_break23",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "selling_price_list",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Price List",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "price_list_name",
- "oldfieldtype": "Select",
- "options": "Price List",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "selling_price_list",
+ "fieldtype": "Link",
+ "label": "Price List",
+ "oldfieldname": "price_list_name",
+ "oldfieldtype": "Select",
+ "options": "Price List",
+ "print_hide": 1,
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "price_list_currency",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Price List Currency",
- "length": 0,
- "no_copy": 0,
- "options": "Currency",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "price_list_currency",
+ "fieldtype": "Link",
+ "label": "Price List Currency",
+ "options": "Currency",
+ "print_hide": 1,
+ "read_only": 1,
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "Rate at which Price list currency is converted to company's base currency",
- "fieldname": "plc_conversion_rate",
- "fieldtype": "Float",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Price List Exchange Rate",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "9",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "description": "Rate at which Price list currency is converted to company's base currency",
+ "fieldname": "plc_conversion_rate",
+ "fieldtype": "Float",
+ "label": "Price List Exchange Rate",
+ "precision": "9",
+ "print_hide": 1,
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "ignore_pricing_rule",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Ignore Pricing Rule",
- "length": 0,
- "no_copy": 1,
- "permlevel": 1,
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "default": "0",
+ "fieldname": "ignore_pricing_rule",
+ "fieldtype": "Check",
+ "label": "Ignore Pricing Rule",
+ "no_copy": 1,
+ "permlevel": 1,
+ "print_hide": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "sec_warehouse",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "sec_warehouse",
+ "fieldtype": "Section Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "set_warehouse",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Set Source Warehouse",
- "length": 0,
- "no_copy": 0,
- "options": "Warehouse",
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "set_warehouse",
+ "fieldtype": "Link",
+ "label": "Set Source Warehouse",
+ "options": "Warehouse",
+ "print_hide": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "col_break_warehouse",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "col_break_warehouse",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "Required only for sample item.",
- "fieldname": "to_warehouse",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 1,
- "label": "To Warehouse",
- "length": 0,
- "no_copy": 1,
- "oldfieldname": "to_warehouse",
- "oldfieldtype": "Link",
- "options": "Warehouse",
- "permlevel": 0,
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "description": "Required only for sample item.",
+ "fieldname": "to_warehouse",
+ "fieldtype": "Link",
+ "in_standard_filter": 1,
+ "label": "To Warehouse",
+ "no_copy": 1,
+ "oldfieldname": "to_warehouse",
+ "oldfieldtype": "Link",
+ "options": "Warehouse",
+ "print_hide": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "items_section",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "",
- "length": 0,
- "no_copy": 0,
- "oldfieldtype": "Section Break",
- "options": "fa fa-shopping-cart",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "items_section",
+ "fieldtype": "Section Break",
+ "oldfieldtype": "Section Break",
+ "options": "fa fa-shopping-cart"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "scan_barcode",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Scan Barcode",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "scan_barcode",
+ "fieldtype": "Data",
+ "label": "Scan Barcode"
+ },
{
- "allow_bulk_edit": 1,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "items",
- "fieldtype": "Table",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Items",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "delivery_note_details",
- "oldfieldtype": "Table",
- "options": "Delivery Note Item",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "allow_bulk_edit": 1,
+ "fieldname": "items",
+ "fieldtype": "Table",
+ "label": "Items",
+ "oldfieldname": "delivery_note_details",
+ "oldfieldtype": "Table",
+ "options": "Delivery Note Item",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "collapsible_depends_on": "",
- "columns": 0,
- "fieldname": "pricing_rule_details",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Pricing Rules",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "pricing_rule_details",
+ "fieldtype": "Section Break",
+ "label": "Pricing Rules"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "collapsible_depends_on": "",
- "columns": 0,
- "fieldname": "pricing_rules",
- "fieldtype": "Table",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Pricing Rule Detail",
- "length": 0,
- "no_copy": 0,
- "options": "Pricing Rule Detail",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "pricing_rules",
+ "fieldtype": "Table",
+ "label": "Pricing Rule Detail",
+ "options": "Pricing Rule Detail",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "collapsible_depends_on": "packed_items",
- "columns": 0,
- "fieldname": "packing_list",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Packing List",
- "length": 0,
- "no_copy": 0,
- "oldfieldtype": "Section Break",
- "options": "fa fa-suitcase",
- "permlevel": 0,
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "collapsible": 1,
+ "collapsible_depends_on": "packed_items",
+ "fieldname": "packing_list",
+ "fieldtype": "Section Break",
+ "label": "Packing List",
+ "oldfieldtype": "Section Break",
+ "options": "fa fa-suitcase",
+ "print_hide": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "packed_items",
- "fieldtype": "Table",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Packed Items",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "packing_details",
- "oldfieldtype": "Table",
- "options": "Packed Item",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "packed_items",
+ "fieldtype": "Table",
+ "label": "Packed Items",
+ "oldfieldname": "packing_details",
+ "oldfieldtype": "Table",
+ "options": "Packed Item",
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "product_bundle_help",
- "fieldtype": "HTML",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Product Bundle Help",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "product_bundle_help",
+ "fieldtype": "HTML",
+ "label": "Product Bundle Help",
+ "print_hide": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "section_break_31",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "section_break_31",
+ "fieldtype": "Section Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "total_qty",
- "fieldtype": "Float",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Total Quantity",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "total_qty",
+ "fieldtype": "Float",
+ "label": "Total Quantity",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "base_total",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Total (Company Currency)",
- "length": 0,
- "no_copy": 0,
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "base_total",
+ "fieldtype": "Currency",
+ "label": "Total (Company Currency)",
+ "options": "Company:company:default_currency",
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "base_net_total",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Net Total (Company Currency)",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "net_total",
- "oldfieldtype": "Currency",
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "print_width": "150px",
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
+ "fieldname": "base_net_total",
+ "fieldtype": "Currency",
+ "label": "Net Total (Company Currency)",
+ "oldfieldname": "net_total",
+ "oldfieldtype": "Currency",
+ "options": "Company:company:default_currency",
+ "print_hide": 1,
+ "print_width": "150px",
+ "read_only": 1,
"width": "150px"
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
- "fieldname": "column_break_33",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "column_break_33",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "total",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Total",
- "length": 0,
- "no_copy": 0,
- "options": "currency",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "total",
+ "fieldtype": "Currency",
+ "label": "Total",
+ "options": "currency",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "net_total",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Net Total",
- "length": 0,
- "no_copy": 0,
- "options": "currency",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "net_total",
+ "fieldtype": "Currency",
+ "label": "Net Total",
+ "options": "currency",
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "total_net_weight",
- "fieldtype": "Float",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Total Net Weight",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "total_net_weight",
+ "fieldtype": "Float",
+ "label": "Total Net Weight",
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "taxes_section",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Taxes and Charges",
- "length": 0,
- "no_copy": 0,
- "oldfieldtype": "Section Break",
- "options": "fa fa-money",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "taxes_section",
+ "fieldtype": "Section Break",
+ "label": "Taxes and Charges",
+ "oldfieldtype": "Section Break",
+ "options": "fa fa-money"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "tax_category",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Tax Category",
- "length": 0,
- "no_copy": 0,
- "options": "Tax Category",
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "tax_category",
+ "fieldtype": "Link",
+ "label": "Tax Category",
+ "options": "Tax Category",
+ "print_hide": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_39",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "column_break_39",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "shipping_rule",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Shipping Rule",
- "length": 0,
- "no_copy": 0,
- "oldfieldtype": "Button",
- "options": "Shipping Rule",
- "permlevel": 0,
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "shipping_rule",
+ "fieldtype": "Link",
+ "label": "Shipping Rule",
+ "oldfieldtype": "Button",
+ "options": "Shipping Rule",
+ "print_hide": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "section_break_41",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "section_break_41",
+ "fieldtype": "Section Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "If you have created a standard template in Sales Taxes and Charges Template, select one and click on the button below.",
- "fieldname": "taxes_and_charges",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Sales Taxes and Charges Template",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "charge",
- "oldfieldtype": "Link",
- "options": "Sales Taxes and Charges Template",
- "permlevel": 0,
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "description": "If you have created a standard template in Sales Taxes and Charges Template, select one and click on the button below.",
+ "fieldname": "taxes_and_charges",
+ "fieldtype": "Link",
+ "label": "Sales Taxes and Charges Template",
+ "oldfieldname": "charge",
+ "oldfieldtype": "Link",
+ "options": "Sales Taxes and Charges Template",
+ "print_hide": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "taxes",
- "fieldtype": "Table",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Sales Taxes and Charges",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "other_charges",
- "oldfieldtype": "Table",
- "options": "Sales Taxes and Charges",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "taxes",
+ "fieldtype": "Table",
+ "label": "Sales Taxes and Charges",
+ "oldfieldname": "other_charges",
+ "oldfieldtype": "Table",
+ "options": "Sales Taxes and Charges"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "columns": 0,
- "fieldname": "sec_tax_breakup",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Tax Breakup",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "collapsible": 1,
+ "fieldname": "sec_tax_breakup",
+ "fieldtype": "Section Break",
+ "label": "Tax Breakup"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "other_charges_calculation",
- "fieldtype": "Text",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Taxes and Charges Calculation",
- "length": 0,
- "no_copy": 1,
- "oldfieldtype": "HTML",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "other_charges_calculation",
+ "fieldtype": "Text",
+ "label": "Taxes and Charges Calculation",
+ "no_copy": 1,
+ "oldfieldtype": "HTML",
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "section_break_44",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "section_break_44",
+ "fieldtype": "Section Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "base_total_taxes_and_charges",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Total Taxes and Charges (Company Currency)",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "other_charges_total",
- "oldfieldtype": "Currency",
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "print_width": "150px",
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
+ "fieldname": "base_total_taxes_and_charges",
+ "fieldtype": "Currency",
+ "label": "Total Taxes and Charges (Company Currency)",
+ "oldfieldname": "other_charges_total",
+ "oldfieldtype": "Currency",
+ "options": "Company:company:default_currency",
+ "print_hide": 1,
+ "print_width": "150px",
+ "read_only": 1,
"width": "150px"
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_47",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "column_break_47",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "total_taxes_and_charges",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Total Taxes and Charges",
- "length": 0,
- "no_copy": 0,
- "options": "currency",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "total_taxes_and_charges",
+ "fieldtype": "Currency",
+ "label": "Total Taxes and Charges",
+ "options": "currency",
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "collapsible_depends_on": "discount_amount",
- "columns": 0,
- "fieldname": "section_break_49",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Additional Discount",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "collapsible": 1,
+ "collapsible_depends_on": "discount_amount",
+ "fieldname": "section_break_49",
+ "fieldtype": "Section Break",
+ "label": "Additional Discount"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "Grand Total",
- "fieldname": "apply_discount_on",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Apply Additional Discount On",
- "length": 0,
- "no_copy": 0,
- "options": "\nGrand Total\nNet Total",
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "default": "Grand Total",
+ "fieldname": "apply_discount_on",
+ "fieldtype": "Select",
+ "label": "Apply Additional Discount On",
+ "options": "\nGrand Total\nNet Total",
+ "print_hide": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "base_discount_amount",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Additional Discount Amount (Company Currency)",
- "length": 0,
- "no_copy": 0,
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "base_discount_amount",
+ "fieldtype": "Currency",
+ "label": "Additional Discount Amount (Company Currency)",
+ "options": "Company:company:default_currency",
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_51",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "column_break_51",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "additional_discount_percentage",
- "fieldtype": "Float",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Additional Discount Percentage",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "additional_discount_percentage",
+ "fieldtype": "Float",
+ "label": "Additional Discount Percentage",
+ "print_hide": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "discount_amount",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Additional Discount Amount",
- "length": 0,
- "no_copy": 0,
- "options": "currency",
- "permlevel": 0,
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "discount_amount",
+ "fieldtype": "Currency",
+ "label": "Additional Discount Amount",
+ "options": "currency",
+ "print_hide": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "totals",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "",
- "length": 0,
- "no_copy": 0,
- "oldfieldtype": "Section Break",
- "options": "fa fa-money",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "totals",
+ "fieldtype": "Section Break",
+ "oldfieldtype": "Section Break",
+ "options": "fa fa-money"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "base_grand_total",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Grand Total (Company Currency)",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "grand_total",
- "oldfieldtype": "Currency",
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "print_width": "150px",
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
+ "fieldname": "base_grand_total",
+ "fieldtype": "Currency",
+ "label": "Grand Total (Company Currency)",
+ "oldfieldname": "grand_total",
+ "oldfieldtype": "Currency",
+ "options": "Company:company:default_currency",
+ "print_hide": 1,
+ "print_width": "150px",
+ "read_only": 1,
"width": "150px"
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "base_rounding_adjustment",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Rounding Adjustment (Company Currency)",
- "length": 0,
- "no_copy": 1,
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "base_rounding_adjustment",
+ "fieldtype": "Currency",
+ "label": "Rounding Adjustment (Company Currency)",
+ "no_copy": 1,
+ "options": "Company:company:default_currency",
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "base_rounded_total",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Rounded Total (Company Currency)",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "rounded_total",
- "oldfieldtype": "Currency",
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "print_width": "150px",
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
+ "fieldname": "base_rounded_total",
+ "fieldtype": "Currency",
+ "label": "Rounded Total (Company Currency)",
+ "oldfieldname": "rounded_total",
+ "oldfieldtype": "Currency",
+ "options": "Company:company:default_currency",
+ "print_hide": 1,
+ "print_width": "150px",
+ "read_only": 1,
"width": "150px"
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "In Words will be visible once you save the Delivery Note.",
- "fieldname": "base_in_words",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "In Words (Company Currency)",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "in_words",
- "oldfieldtype": "Data",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "print_width": "200px",
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
+ "description": "In Words will be visible once you save the Delivery Note.",
+ "fieldname": "base_in_words",
+ "fieldtype": "Data",
+ "label": "In Words (Company Currency)",
+ "oldfieldname": "in_words",
+ "oldfieldtype": "Data",
+ "print_hide": 1,
+ "print_width": "200px",
+ "read_only": 1,
"width": "200px"
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break3",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "oldfieldtype": "Column Break",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "column_break3",
+ "fieldtype": "Column Break",
+ "oldfieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "grand_total",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Grand Total",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "grand_total_export",
- "oldfieldtype": "Currency",
- "options": "currency",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "print_width": "150px",
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
+ "fieldname": "grand_total",
+ "fieldtype": "Currency",
+ "in_list_view": 1,
+ "label": "Grand Total",
+ "oldfieldname": "grand_total_export",
+ "oldfieldtype": "Currency",
+ "options": "currency",
+ "print_width": "150px",
+ "read_only": 1,
"width": "150px"
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "rounding_adjustment",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Rounding Adjustment",
- "length": 0,
- "no_copy": 1,
- "options": "currency",
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "rounding_adjustment",
+ "fieldtype": "Currency",
+ "label": "Rounding Adjustment",
+ "no_copy": 1,
+ "options": "currency",
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 1,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "rounded_total",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Rounded Total",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "rounded_total_export",
- "oldfieldtype": "Currency",
- "options": "currency",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "print_width": "150px",
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
+ "bold": 1,
+ "fieldname": "rounded_total",
+ "fieldtype": "Currency",
+ "label": "Rounded Total",
+ "oldfieldname": "rounded_total_export",
+ "oldfieldtype": "Currency",
+ "options": "currency",
+ "print_width": "150px",
+ "read_only": 1,
"width": "150px"
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "In Words (Export) will be visible once you save the Delivery Note.",
- "fieldname": "in_words",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "In Words",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "in_words_export",
- "oldfieldtype": "Data",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "print_width": "150px",
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
+ "description": "In Words (Export) will be visible once you save the Delivery Note.",
+ "fieldname": "in_words",
+ "fieldtype": "Data",
+ "label": "In Words",
+ "oldfieldname": "in_words_export",
+ "oldfieldtype": "Data",
+ "print_hide": 1,
+ "print_width": "150px",
+ "read_only": 1,
"width": "150px"
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "collapsible_depends_on": "terms",
- "columns": 0,
- "fieldname": "terms_section_break",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Terms and Conditions",
- "length": 0,
- "no_copy": 0,
- "oldfieldtype": "Section Break",
- "options": "fa fa-legal",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "collapsible": 1,
+ "collapsible_depends_on": "terms",
+ "fieldname": "terms_section_break",
+ "fieldtype": "Section Break",
+ "label": "Terms and Conditions",
+ "oldfieldtype": "Section Break",
+ "options": "fa fa-legal"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "tc_name",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Terms",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "tc_name",
- "oldfieldtype": "Link",
- "options": "Terms and Conditions",
- "permlevel": 0,
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "tc_name",
+ "fieldtype": "Link",
+ "label": "Terms",
+ "oldfieldname": "tc_name",
+ "oldfieldtype": "Link",
+ "options": "Terms and Conditions",
+ "print_hide": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "terms",
- "fieldtype": "Text Editor",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Terms and Conditions Details",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "terms",
- "oldfieldtype": "Text Editor",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "terms",
+ "fieldtype": "Text Editor",
+ "label": "Terms and Conditions Details",
+ "oldfieldname": "terms",
+ "oldfieldtype": "Text Editor"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "collapsible_depends_on": "transporter",
- "columns": 0,
- "fieldname": "transporter_info",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Transporter Info",
- "length": 0,
- "no_copy": 0,
- "options": "fa fa-truck",
- "permlevel": 0,
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "collapsible": 1,
+ "collapsible_depends_on": "transporter",
+ "fieldname": "transporter_info",
+ "fieldtype": "Section Break",
+ "label": "Transporter Info",
+ "options": "fa fa-truck",
+ "print_hide": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "transporter",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Transporter",
- "length": 0,
- "no_copy": 0,
- "options": "Supplier",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "print_width": "150px",
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
+ "fieldname": "transporter",
+ "fieldtype": "Link",
+ "label": "Transporter",
+ "options": "Supplier",
+ "print_hide": 1,
+ "print_width": "150px",
"width": "150px"
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "driver",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Driver",
- "length": 0,
- "no_copy": 0,
- "options": "Driver",
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "driver",
+ "fieldtype": "Link",
+ "label": "Driver",
+ "options": "Driver",
+ "print_hide": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "",
- "fieldname": "lr_no",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Transport Receipt No",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "lr_no",
- "oldfieldtype": "Data",
- "options": "",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "print_width": "100px",
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
+ "fieldname": "lr_no",
+ "fieldtype": "Data",
+ "label": "Transport Receipt No",
+ "oldfieldname": "lr_no",
+ "oldfieldtype": "Data",
+ "print_hide": 1,
+ "print_width": "100px",
"width": "100px"
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "vehicle_no",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Vehicle No",
- "length": 0,
- "no_copy": 0,
- "options": "",
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "vehicle_no",
+ "fieldtype": "Data",
+ "label": "Vehicle No",
+ "print_hide": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "col_break34",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "print_width": "50%",
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
+ "fieldname": "col_break34",
+ "fieldtype": "Column Break",
+ "print_width": "50%",
"width": "50%"
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_from": "transporter.name",
- "fieldname": "transporter_name",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Transporter Name",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fetch_from": "transporter.name",
+ "fieldname": "transporter_name",
+ "fieldtype": "Data",
+ "label": "Transporter Name",
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_from": "driver.full_name",
- "fieldname": "driver_name",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Driver Name",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fetch_from": "driver.full_name",
+ "fieldname": "driver_name",
+ "fieldtype": "Data",
+ "label": "Driver Name",
+ "print_hide": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "Today",
- "description": "",
- "fieldname": "lr_date",
- "fieldtype": "Date",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Transport Receipt Date",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "lr_date",
- "oldfieldtype": "Date",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "print_width": "100px",
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
+ "default": "Today",
+ "fieldname": "lr_date",
+ "fieldtype": "Date",
+ "label": "Transport Receipt Date",
+ "oldfieldname": "lr_date",
+ "oldfieldtype": "Date",
+ "print_hide": 1,
+ "print_width": "100px",
"width": "100px"
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "columns": 0,
- "fieldname": "more_info",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "More Information",
- "length": 0,
- "no_copy": 0,
- "oldfieldtype": "Section Break",
- "options": "fa fa-file-text",
- "permlevel": 0,
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "collapsible": 1,
+ "fieldname": "more_info",
+ "fieldtype": "Section Break",
+ "label": "More Information",
+ "oldfieldtype": "Section Break",
+ "options": "fa fa-file-text",
+ "print_hide": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "Track this Delivery Note against any Project",
- "fieldname": "project",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Project",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "project",
- "oldfieldtype": "Link",
- "options": "Project",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "description": "Track this Delivery Note against any Project",
+ "fieldname": "project",
+ "fieldtype": "Link",
+ "label": "Project",
+ "oldfieldname": "project",
+ "oldfieldtype": "Link",
+ "options": "Project"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
- "fieldname": "campaign",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Campaign",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "campaign",
- "oldfieldtype": "Link",
- "options": "Campaign",
- "permlevel": 0,
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "campaign",
+ "fieldtype": "Link",
+ "label": "Campaign",
+ "oldfieldname": "campaign",
+ "oldfieldtype": "Link",
+ "options": "Campaign",
+ "print_hide": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "source",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Source",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "source",
- "oldfieldtype": "Select",
- "options": "Lead Source",
- "permlevel": 0,
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "source",
+ "fieldtype": "Link",
+ "label": "Source",
+ "oldfieldname": "source",
+ "oldfieldtype": "Select",
+ "options": "Lead Source",
+ "print_hide": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break5",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "oldfieldtype": "Column Break",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "print_width": "50%",
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
+ "fieldname": "column_break5",
+ "fieldtype": "Column Break",
+ "oldfieldtype": "Column Break",
+ "print_hide": 1,
+ "print_width": "50%",
"width": "50%"
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "per_billed",
- "fieldtype": "Percent",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "% Amount Billed",
- "length": 0,
- "no_copy": 1,
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "per_billed",
+ "fieldtype": "Percent",
+ "label": "% Amount Billed",
+ "no_copy": 1,
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "",
- "fieldname": "customer_group",
- "fieldtype": "Link",
- "hidden": 1,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Customer Group",
- "length": 0,
- "no_copy": 0,
- "options": "Customer Group",
- "permlevel": 0,
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "customer_group",
+ "fieldtype": "Link",
+ "hidden": 1,
+ "label": "Customer Group",
+ "options": "Customer Group",
+ "print_hide": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "",
- "fieldname": "territory",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Territory",
- "length": 0,
- "no_copy": 0,
- "options": "Territory",
- "permlevel": 0,
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "territory",
+ "fieldtype": "Link",
+ "label": "Territory",
+ "options": "Territory",
+ "print_hide": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "columns": 0,
- "fieldname": "printing_details",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Printing Details",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "collapsible": 1,
+ "fieldname": "printing_details",
+ "fieldtype": "Section Break",
+ "label": "Printing Details"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "letter_head",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Letter Head",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "letter_head",
- "oldfieldtype": "Link",
- "options": "Letter Head",
- "permlevel": 0,
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "allow_on_submit": 1,
+ "fieldname": "letter_head",
+ "fieldtype": "Link",
+ "label": "Letter Head",
+ "oldfieldname": "letter_head",
+ "oldfieldtype": "Link",
+ "options": "Letter Head",
+ "print_hide": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "select_print_heading",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Print Heading",
- "length": 0,
- "no_copy": 1,
- "oldfieldname": "select_print_heading",
- "oldfieldtype": "Link",
- "options": "Print Heading",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 1,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "allow_on_submit": 1,
+ "fieldname": "select_print_heading",
+ "fieldtype": "Link",
+ "label": "Print Heading",
+ "no_copy": 1,
+ "oldfieldname": "select_print_heading",
+ "oldfieldtype": "Link",
+ "options": "Print Heading",
+ "print_hide": 1,
+ "report_hide": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "language",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Print Language",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "language",
+ "fieldtype": "Data",
+ "label": "Print Language",
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_88",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "column_break_88",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "print_without_amount",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Print Without Amount",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "print_without_amount",
- "oldfieldtype": "Check",
- "permlevel": 0,
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "allow_on_submit": 1,
+ "default": "0",
+ "fieldname": "print_without_amount",
+ "fieldtype": "Check",
+ "label": "Print Without Amount",
+ "oldfieldname": "print_without_amount",
+ "oldfieldtype": "Check",
+ "print_hide": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "group_same_items",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Group same items",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "allow_on_submit": 1,
+ "default": "0",
+ "fieldname": "group_same_items",
+ "fieldtype": "Check",
+ "label": "Group same items",
+ "print_hide": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "columns": 0,
- "fieldname": "section_break_83",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Status",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "collapsible": 1,
+ "fieldname": "section_break_83",
+ "fieldtype": "Section Break",
+ "label": "Status"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "Draft",
- "fieldname": "status",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 1,
- "label": "Status",
- "length": 0,
- "no_copy": 1,
- "oldfieldname": "status",
- "oldfieldtype": "Select",
- "options": "\nDraft\nTo Bill\nCompleted\nCancelled\nClosed",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "print_width": "150px",
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 1,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
+ "default": "Draft",
+ "fieldname": "status",
+ "fieldtype": "Select",
+ "in_standard_filter": 1,
+ "label": "Status",
+ "no_copy": 1,
+ "oldfieldname": "status",
+ "oldfieldtype": "Select",
+ "options": "\nDraft\nTo Bill\nCompleted\nCancelled\nClosed",
+ "print_hide": 1,
+ "print_width": "150px",
+ "read_only": 1,
+ "reqd": 1,
+ "search_index": 1,
"width": "150px"
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:!doc.__islocal",
- "description": "% of materials delivered against this Delivery Note",
- "fieldname": "per_installed",
- "fieldtype": "Percent",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "% Installed",
- "length": 0,
- "no_copy": 1,
- "oldfieldname": "per_installed",
- "oldfieldtype": "Currency",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "depends_on": "eval:!doc.__islocal",
+ "description": "% of materials delivered against this Delivery Note",
+ "fieldname": "per_installed",
+ "fieldtype": "Percent",
+ "in_list_view": 1,
+ "label": "% Installed",
+ "no_copy": 1,
+ "oldfieldname": "per_installed",
+ "oldfieldtype": "Currency",
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "installation_status",
- "fieldtype": "Select",
- "hidden": 1,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Installation Status",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "installation_status",
+ "fieldtype": "Select",
+ "hidden": 1,
+ "label": "Installation Status",
+ "print_hide": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_89",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "column_break_89",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "excise_page",
- "fieldtype": "Data",
- "hidden": 1,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Excise Page Number",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "excise_page",
- "oldfieldtype": "Data",
- "permlevel": 0,
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "excise_page",
+ "fieldtype": "Data",
+ "hidden": 1,
+ "label": "Excise Page Number",
+ "oldfieldname": "excise_page",
+ "oldfieldtype": "Data",
+ "print_hide": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "instructions",
- "fieldtype": "Text",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Instructions",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "instructions",
- "oldfieldtype": "Text",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "instructions",
+ "fieldtype": "Text",
+ "label": "Instructions",
+ "oldfieldname": "instructions",
+ "oldfieldtype": "Text"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "subscription_section",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Subscription Section",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "subscription_section",
+ "fieldtype": "Section Break",
+ "label": "Subscription Section"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "auto_repeat",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Auto Repeat",
- "length": 0,
- "no_copy": 1,
- "options": "Auto Repeat",
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "auto_repeat",
+ "fieldtype": "Link",
+ "label": "Auto Repeat",
+ "no_copy": 1,
+ "options": "Auto Repeat",
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "collapsible_depends_on": "total_commission",
- "columns": 0,
- "fieldname": "sales_team_section_break",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Commission",
- "length": 0,
- "no_copy": 0,
- "oldfieldtype": "Section Break",
- "options": "fa fa-group",
- "permlevel": 0,
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "collapsible": 1,
+ "collapsible_depends_on": "total_commission",
+ "fieldname": "sales_team_section_break",
+ "fieldtype": "Section Break",
+ "label": "Commission",
+ "oldfieldtype": "Section Break",
+ "options": "fa fa-group",
+ "print_hide": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "sales_partner",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Sales Partner",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "sales_partner",
- "oldfieldtype": "Link",
- "options": "Sales Partner",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "print_width": "150px",
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
+ "fieldname": "sales_partner",
+ "fieldtype": "Link",
+ "label": "Sales Partner",
+ "oldfieldname": "sales_partner",
+ "oldfieldtype": "Link",
+ "options": "Sales Partner",
+ "print_hide": 1,
+ "print_width": "150px",
"width": "150px"
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break7",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "print_width": "50%",
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
+ "fieldname": "column_break7",
+ "fieldtype": "Column Break",
+ "print_hide": 1,
+ "print_width": "50%",
"width": "50%"
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "commission_rate",
- "fieldtype": "Float",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Commission Rate (%)",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "commission_rate",
- "oldfieldtype": "Currency",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "print_width": "100px",
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
+ "fieldname": "commission_rate",
+ "fieldtype": "Float",
+ "label": "Commission Rate (%)",
+ "oldfieldname": "commission_rate",
+ "oldfieldtype": "Currency",
+ "print_hide": 1,
+ "print_width": "100px",
"width": "100px"
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "total_commission",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Total Commission",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "total_commission",
- "oldfieldtype": "Currency",
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "total_commission",
+ "fieldtype": "Currency",
+ "label": "Total Commission",
+ "oldfieldname": "total_commission",
+ "oldfieldtype": "Currency",
+ "options": "Company:company:default_currency",
+ "print_hide": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "collapsible_depends_on": "sales_team",
- "columns": 0,
- "fieldname": "section_break1",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Sales Team",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "collapsible": 1,
+ "collapsible_depends_on": "sales_team",
+ "fieldname": "section_break1",
+ "fieldtype": "Section Break",
+ "label": "Sales Team",
+ "print_hide": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "sales_team",
- "fieldtype": "Table",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Sales Team1",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "sales_team",
- "oldfieldtype": "Table",
- "options": "Sales Team",
- "permlevel": 0,
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
+ "allow_on_submit": 1,
+ "fieldname": "sales_team",
+ "fieldtype": "Table",
+ "label": "Sales Team",
+ "oldfieldname": "sales_team",
+ "oldfieldtype": "Table",
+ "options": "Sales Team",
+ "print_hide": 1
+ },
+ {
+ "fieldname": "pick_list",
+ "fieldtype": "Link",
+ "hidden": 1,
+ "label": "Pick List",
+ "options": "Pick List",
+ "read_only": 1
+ },
+ {
+ "fieldname": "section_break_18",
+ "fieldtype": "Section Break"
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "icon": "fa fa-truck",
- "idx": 146,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 1,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "menu_index": 0,
- "modified": "2019-02-13 01:06:29.783590",
- "modified_by": "Administrator",
- "module": "Stock",
- "name": "Delivery Note",
- "owner": "Administrator",
+ ],
+ "icon": "fa fa-truck",
+ "idx": 146,
+ "is_submittable": 1,
+ "modified": "2019-08-26 07:37:39.766014",
+ "modified_by": "Administrator",
+ "module": "Stock",
+ "name": "Delivery Note",
+ "owner": "Administrator",
"permissions": [
{
- "amend": 1,
- "cancel": 1,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Stock User",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 1,
+ "amend": 1,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Stock User",
+ "share": 1,
+ "submit": 1,
"write": 1
- },
+ },
{
- "amend": 1,
- "cancel": 1,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Stock Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 1,
+ "amend": 1,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Stock Manager",
+ "share": 1,
+ "submit": 1,
"write": 1
- },
+ },
{
- "amend": 1,
- "cancel": 1,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Sales User",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 1,
+ "amend": 1,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Sales User",
+ "share": 1,
+ "submit": 1,
"write": 1
- },
+ },
{
- "amend": 0,
- "cancel": 0,
- "create": 0,
- "delete": 0,
- "email": 0,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 0,
- "read": 1,
- "report": 1,
- "role": "Accounts User",
- "set_user_permissions": 0,
- "share": 0,
- "submit": 0,
- "write": 0
- },
+ "read": 1,
+ "report": 1,
+ "role": "Accounts User"
+ },
{
- "amend": 0,
- "cancel": 0,
- "create": 0,
- "delete": 0,
- "email": 0,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 1,
- "print": 0,
- "read": 1,
- "report": 0,
- "role": "Stock Manager",
- "set_user_permissions": 0,
- "share": 0,
- "submit": 0,
+ "permlevel": 1,
+ "read": 1,
+ "role": "Stock Manager",
"write": 1
}
- ],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 1,
- "search_fields": "status,customer,customer_name, territory,base_grand_total",
- "show_name_in_global_search": 1,
- "sort_field": "modified",
- "sort_order": "DESC",
- "timeline_field": "customer",
- "title_field": "title",
- "track_changes": 1,
- "track_seen": 1,
- "track_views": 0
-}
+ ],
+ "search_fields": "status,customer,customer_name, territory,base_grand_total",
+ "show_name_in_global_search": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "timeline_field": "customer",
+ "title_field": "title",
+ "track_changes": 1,
+ "track_seen": 1
+}
\ No newline at end of file
From 94d7096c8ccd1c7a1fbde5491b22f093cb6982a4 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Mon, 26 Aug 2019 08:40:02 +0530
Subject: [PATCH 325/484] fix: Show create button only if target doc does not
exists
---
erpnext/stock/doctype/pick_list/pick_list.js | 25 +--
erpnext/stock/doctype/pick_list/pick_list.py | 185 +++++++++++--------
2 files changed, 120 insertions(+), 90 deletions(-)
diff --git a/erpnext/stock/doctype/pick_list/pick_list.js b/erpnext/stock/doctype/pick_list/pick_list.js
index 75d0511e50..a0082b859c 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.js
+++ b/erpnext/stock/doctype/pick_list/pick_list.js
@@ -32,23 +32,18 @@ frappe.ui.form.on('Pick List', {
},
refresh: (frm) => {
frm.trigger('add_get_items_button');
-
- // if (frm.doc.items && (frm.doc.items.length > 1 || frm.doc.items[0].item_code) && frm.doc.docstatus === 0) {
- // frm.add_custom_button(__('Get Item Locations'), () => {
- // frm.call('set_item_locations');
- // }).addClass('btn-primary');
- // }
if (frm.doc.docstatus === 1) {
- if (frm.doc.purpose === 'Delivery against Sales Order') {
- frm.add_custom_button(__('Delivery Note'), () => frm.trigger('create_delivery_note'), __('Create'));
- } else {
- frappe.xcall('erpnext.stock.doctype.pick_list.pick_list.stock_entry_exists', {
- 'pick_list_name': frm.doc.name
- }).then(exists => {
- if (exists) return;
+ frappe.xcall('erpnext.stock.doctype.pick_list.pick_list.target_document_exists', {
+ 'pick_list_name': frm.doc.name,
+ 'purpose': frm.doc.purpose
+ }).then(target_document_exists => {
+ if (target_document_exists) return;
+ if (frm.doc.purpose === 'Delivery against Sales Order') {
+ frm.add_custom_button(__('Delivery Note'), () => frm.trigger('create_delivery_note'), __('Create'));
+ } else {
frm.add_custom_button(__('Stock Entry'), () => frm.trigger('create_stock_entry'), __('Create'));
- });
- }
+ }
+ });
}
},
work_order: (frm) => {
diff --git a/erpnext/stock/doctype/pick_list/pick_list.py b/erpnext/stock/doctype/pick_list/pick_list.py
index a8955def74..16bb9e6dc7 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.py
+++ b/erpnext/stock/doctype/pick_list/pick_list.py
@@ -170,6 +170,7 @@ def get_item_locations_based_on_batch_nos(item_doc):
return locations
+
@frappe.whitelist()
def create_delivery_note(source_name, target_doc=None):
pick_list = frappe.get_doc('Pick List', source_name)
@@ -181,18 +182,18 @@ def create_delivery_note(source_name, target_doc=None):
delivery_note = create_delivery_note_from_sales_order(sales_order,
delivery_note, skip_item_mapping=True)
+ item_table_mapper = {
+ 'doctype': 'Delivery Note Item',
+ 'field_map': {
+ 'rate': 'rate',
+ 'name': 'so_detail',
+ 'parent': 'against_sales_order',
+ },
+ 'condition': lambda doc: abs(doc.delivered_qty) < abs(doc.qty) and doc.delivered_by_supplier!=1
+ }
+
for location in pick_list.locations:
sales_order_item = frappe.get_cached_doc('Sales Order Item', location.sales_order_item)
- item_table_mapper = {
- 'doctype': 'Delivery Note Item',
- 'field_map': {
- 'rate': 'rate',
- 'name': 'so_detail',
- 'parent': 'against_sales_order',
- },
- 'condition': lambda doc: abs(doc.delivered_qty) < abs(doc.qty) and doc.delivered_by_supplier!=1
- }
-
dn_item = map_child_doc(sales_order_item, delivery_note, item_table_mapper)
if dn_item:
@@ -203,79 +204,26 @@ def create_delivery_note(source_name, target_doc=None):
set_delivery_note_missing_values(delivery_note)
+ delivery_note.pick_list = pick_list.name
+
return delivery_note
-
-def update_delivery_note_item(source, target, delivery_note):
- cost_center = frappe.db.get_value("Project", delivery_note.project, "cost_center")
- if not cost_center:
- cost_center = frappe.db.get_value('Item Default',
- fieldname=['buying_cost_center'],
- filters={
- 'parent': source.item_code,
- 'parenttype': 'Item',
- 'company': delivery_note.company
- })
-
- if not cost_center:
- cost_center = frappe.db.get_value('Item Default',
- fieldname=['buying_cost_center'],
- filters={
- 'parent': source.item_group,
- 'parenttype': 'Item Group',
- 'company': delivery_note.company
- })
-
- target.cost_center = cost_center
-
-def set_delivery_note_missing_values(target):
- target.run_method('set_missing_values')
- target.run_method('set_po_nos')
- target.run_method('calculate_taxes_and_totals')
-
@frappe.whitelist()
def create_stock_entry(pick_list):
pick_list = frappe.get_doc(json.loads(pick_list))
- if stock_entry_exists(pick_list.get('name')):
- return frappe.msgprint(_('Stock Entry already exists against this Pick List'))
- work_order = frappe.get_doc("Work Order", pick_list.get('work_order'))
+ if stock_entry_exists(pick_list.get('name')):
+ return frappe.msgprint(_('Stock Entry has been already created against this Pick List'))
stock_entry = frappe.new_doc('Stock Entry')
stock_entry.pick_list = pick_list.get('name')
stock_entry.purpose = pick_list.get('purpose')
stock_entry.set_stock_entry_type()
- stock_entry.work_order = work_order.name
- stock_entry.company = work_order.company
- stock_entry.from_bom = 1
- stock_entry.bom_no = work_order.bom_no
- stock_entry.use_multi_level_bom = work_order.use_multi_level_bom
- stock_entry.fg_completed_qty = pick_list.for_qty
- if work_order.bom_no:
- stock_entry.inspection_required = frappe.db.get_value('BOM',
- work_order.bom_no, 'inspection_required')
- is_wip_warehouse_group = frappe.db.get_value('Warehouse', work_order.wip_warehouse, 'is_group')
- if not (is_wip_warehouse_group and work_order.skip_transfer):
- wip_warehouse = work_order.wip_warehouse
- else:
- wip_warehouse = None
- stock_entry.to_warehouse = wip_warehouse
-
- stock_entry.project = work_order.project
-
- for location in pick_list.locations:
- item = frappe._dict()
- item.item_code = location.item_code
- item.s_warehouse = location.warehouse
- item.t_warehouse = wip_warehouse
- item.qty = location.qty
- item.transfer_qty = location.stock_qty
- item.uom = location.uom
- item.conversion_factor = location.conversion_factor
- item.stock_uom = location.stock_uom
-
- stock_entry.append('items', item)
+ if pick_list.get('work_order'):
+ stock_entry = update_stock_entry_based_on_work_order(pick_list, stock_entry)
+ elif pick_list.get('material_request'):
+ stock_entry = update_stock_entry_based_on_material_request(pick_list, stock_entry)
stock_entry.set_incoming_rate()
stock_entry.set_actual_qty()
@@ -283,7 +231,6 @@ def create_stock_entry(pick_list):
return stock_entry.as_dict()
-
@frappe.whitelist()
def create_stock_entry_with_material_request_items(pick_list):
stock_entry = frappe.new_doc('Stock Entry')
@@ -330,11 +277,99 @@ def get_pending_work_orders(doctype, txt, searchfield, start, page_length, filte
'company': filters.get('company')
}, as_dict=as_dict)
-def get_item_details(item_code):
- pass
-
@frappe.whitelist()
+def target_document_exists(pick_list_name, purpose):
+ if purpose == 'Delivery against Sales Order':
+ return frappe.db.exists('Delivery Note', {
+ 'pick_list': pick_list_name
+ })
+
+ return stock_entry_exists(pick_list_name)
+
+
+def update_delivery_note_item(source, target, delivery_note):
+ cost_center = frappe.db.get_value('Project', delivery_note.project, 'cost_center')
+ if not cost_center:
+ cost_center = get_cost_center(source.item_code, 'Item', delivery_note.company)
+
+ if not cost_center:
+ cost_center = get_cost_center(source.item_group, 'Item Group', delivery_note.company)
+
+ target.cost_center = cost_center
+
+def get_cost_center(for_item, from_doctype, company):
+ '''Returns Cost Center for Item or Item Group'''
+ return frappe.db.get_value('Item Default',
+ fieldname=['buying_cost_center'],
+ filters={
+ 'parent': for_item,
+ 'parenttype': from_doctype,
+ 'company': company
+ })
+
+def set_delivery_note_missing_values(target):
+ target.run_method('set_missing_values')
+ target.run_method('set_po_nos')
+ target.run_method('calculate_taxes_and_totals')
+
def stock_entry_exists(pick_list_name):
return frappe.db.exists('Stock Entry', {
'pick_list': pick_list_name
})
+
+def get_item_details(item_code):
+ pass
+
+def update_stock_entry_based_on_work_order(pick_list, stock_entry):
+ work_order = frappe.get_doc("Work Order", pick_list.get('work_order'))
+
+ stock_entry.work_order = work_order.name
+ stock_entry.company = work_order.company
+ stock_entry.from_bom = 1
+ stock_entry.bom_no = work_order.bom_no
+ stock_entry.use_multi_level_bom = work_order.use_multi_level_bom
+ stock_entry.fg_completed_qty = pick_list.for_qty
+ if work_order.bom_no:
+ stock_entry.inspection_required = frappe.db.get_value('BOM',
+ work_order.bom_no, 'inspection_required')
+
+ is_wip_warehouse_group = frappe.db.get_value('Warehouse', work_order.wip_warehouse, 'is_group')
+ if not (is_wip_warehouse_group and work_order.skip_transfer):
+ wip_warehouse = work_order.wip_warehouse
+ else:
+ wip_warehouse = None
+ stock_entry.to_warehouse = wip_warehouse
+
+ stock_entry.project = work_order.project
+
+ for location in pick_list.locations:
+ item = frappe._dict()
+ item.item_code = location.item_code
+ item.s_warehouse = location.warehouse
+ item.t_warehouse = wip_warehouse
+ item.qty = location.qty
+ item.transfer_qty = location.stock_qty
+ item.uom = location.uom
+ item.conversion_factor = location.conversion_factor
+ item.stock_uom = location.stock_uom
+
+ stock_entry.append('items', item)
+
+ return stock_entry
+
+def update_stock_entry_based_on_material_request(pick_list, stock_entry):
+ for location in pick_list.locations:
+ item = frappe._dict()
+ item.item_code = location.item_code
+ item.s_warehouse = location.warehouse
+ item.qty = location.qty
+ item.transfer_qty = location.stock_qty
+ item.uom = location.uom
+ item.conversion_factor = location.conversion_factor
+ item.stock_uom = location.stock_uom
+ item.material_request = location.material_request
+ item.material_request_item = location.material_request_item
+
+ stock_entry.append('items', item)
+
+ return stock_entry
\ No newline at end of file
From 05f243590d04a727dfd7d1e096f93bc6f3d092bd Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Mon, 26 Aug 2019 09:29:31 +0530
Subject: [PATCH 326/484] fix: Show option to create pick list or work order
---
.../doctype/work_order/work_order.js | 64 +++++++++++--------
.../doctype/work_order/work_order.py | 8 ++-
2 files changed, 41 insertions(+), 31 deletions(-)
diff --git a/erpnext/manufacturing/doctype/work_order/work_order.js b/erpnext/manufacturing/doctype/work_order/work_order.js
index d345c0bf3f..c1f64ed0da 100644
--- a/erpnext/manufacturing/doctype/work_order/work_order.js
+++ b/erpnext/manufacturing/doctype/work_order/work_order.js
@@ -161,13 +161,6 @@ frappe.ui.form.on("Work Order", {
frm.add_custom_button(__('Create BOM'), () => {
frm.trigger("make_bom");
});
-
- frm.add_custom_button(__('Pick List'), () => {
- frappe.model.open_mapped_doc({
- method: "erpnext.manufacturing.doctype.work_order.work_order.make_pick_list",
- frm
- });
- }, __('Make'));
}
},
@@ -553,31 +546,46 @@ erpnext.work_order = {
var max = (purpose === "Manufacture") ?
flt(frm.doc.material_transferred_for_manufacturing) - flt(frm.doc.produced_qty) :
flt(frm.doc.qty) - flt(frm.doc.material_transferred_for_manufacturing);
- } else {
- var max = flt(frm.doc.qty) - flt(frm.doc.produced_qty);
}
+ max = flt(max, precision('qty'));
- max = flt(max, precision("qty"));
- frappe.prompt({fieldtype:"Float", label: __("Qty for {0}", [purpose]), fieldname:"qty",
- description: __("Max: {0}", [max]), 'default': max }, function(data)
- {
- if(data.qty > max) {
- frappe.msgprint(__("Quantity must not be more than {0}", [max]));
+ frappe.prompt([{
+ fieldtype: 'Float',
+ label: __('Qty for {0}', [purpose]),
+ fieldname: 'qty',
+ description: __('Max: {0}',[max]),
+ default: max
+ }, {
+ fieldtype: 'Select',
+ label: __('Create'),
+ fieldname: 'create',
+ default: 'Stock Entry',
+ options: 'Stock Entry\nPick List'
+ }], function (data) {
+ if (data.qty > max) {
+ frappe.msgprint(__('Quantity must not be more than {0}', [max]));
return;
}
- frappe.call({
- method:"erpnext.manufacturing.doctype.work_order.work_order.make_stock_entry",
- args: {
- "work_order_id": frm.doc.name,
- "purpose": purpose,
- "qty": data.qty
- },
- callback: function(r) {
- var doclist = frappe.model.sync(r.message);
- frappe.set_route("Form", doclist[0].doctype, doclist[0].name);
- }
- });
- }, __("Select Quantity"), __('Create'));
+ if (data.create === 'Stock Entry') {
+ frappe.xcall('erpnext.manufacturing.doctype.work_order.work_order.make_stock_entry', {
+ 'work_order_id': frm.doc.name,
+ 'purpose': purpose,
+ 'qty': data.qty
+ }).then(stock_entry => {
+ frappe.model.sync(stock_entry);
+ frappe.set_route('Form', stock_entry.doctype, stock_entry.name);
+ });
+ } else {
+ frappe.xcall('erpnext.manufacturing.doctype.work_order.work_order.create_pick_list', {
+ 'source_name': frm.doc.name,
+ 'for_qty': data.qty
+ }).then(pick_list => {
+ frappe.model.sync(pick_list);
+ frappe.set_route('Form', pick_list.doctype, pick_list.name);
+ });
+ }
+
+ }, __('Select Quantity'), __('Create'));
},
make_consumption_se: function(frm, backflush_raw_materials_based_on) {
diff --git a/erpnext/manufacturing/doctype/work_order/work_order.py b/erpnext/manufacturing/doctype/work_order/work_order.py
index 804d22ce6b..d3ce1b8533 100644
--- a/erpnext/manufacturing/doctype/work_order/work_order.py
+++ b/erpnext/manufacturing/doctype/work_order/work_order.py
@@ -710,15 +710,15 @@ def get_work_order_operation_data(work_order, operation, workstation):
return d
@frappe.whitelist()
-def create_pick_list(source_name, target_doc=None):
- pick_list = json.loads(target_doc)
+def create_pick_list(source_name, target_doc=None, for_qty=None):
+ pick_list = for_qty or json.loads(target_doc).get('for_qty')
max_finished_goods_qty = frappe.db.get_value('Work Order', source_name, 'qty')
def update_item_quantity(source, target, source_parent):
# qty = source.required_qty - source.transferred_qty
# target.qty = qty
pending_to_issue = flt(source.required_qty) - flt(source.transferred_qty)
- desire_to_transfer = flt(source.required_qty) / max_finished_goods_qty * flt(pick_list.get('for_qty'))
+ desire_to_transfer = flt(source.required_qty) / max_finished_goods_qty * flt(for_qty)
qty = 0
if desire_to_transfer <= pending_to_issue:
@@ -762,4 +762,6 @@ def create_pick_list(source_name, target_doc=None):
# doc.delete_key('items')
# doc.set('items', item_map.values())
+ doc.for_qty = for_qty
+
return doc
\ No newline at end of file
From 2b9e256002a5148ea9d4424bf786c7c48fab5d0c Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Mon, 26 Aug 2019 10:05:01 +0530
Subject: [PATCH 327/484] fix: Rename method name
---
erpnext/manufacturing/doctype/work_order/work_order.js | 4 ----
erpnext/selling/doctype/sales_order/sales_order.js | 6 +++---
erpnext/selling/doctype/sales_order/sales_order.py | 2 +-
erpnext/stock/doctype/pick_list/pick_list.js | 2 +-
erpnext/stock/doctype/pick_list/test_pick_list.py | 2 --
5 files changed, 5 insertions(+), 11 deletions(-)
diff --git a/erpnext/manufacturing/doctype/work_order/work_order.js b/erpnext/manufacturing/doctype/work_order/work_order.js
index c1f64ed0da..ce66c8fd15 100644
--- a/erpnext/manufacturing/doctype/work_order/work_order.js
+++ b/erpnext/manufacturing/doctype/work_order/work_order.js
@@ -264,10 +264,6 @@ frappe.ui.form.on("Work Order", {
});
},
- make_pick_list() {
-
- },
-
show_progress: function(frm) {
var bars = [];
var message = '';
diff --git a/erpnext/selling/doctype/sales_order/sales_order.js b/erpnext/selling/doctype/sales_order/sales_order.js
index 194971026d..6ffc6162d6 100644
--- a/erpnext/selling/doctype/sales_order/sales_order.js
+++ b/erpnext/selling/doctype/sales_order/sales_order.js
@@ -110,7 +110,7 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
let allow_delivery = false;
if (doc.docstatus==1) {
- this.frm.add_custom_button(__('Pick List'), () => this.make_pick_list(), __('Create'));
+ this.frm.add_custom_button(__('Pick List'), () => this.create_pick_list(), __('Create'));
if(this.frm.has_perm("submit")) {
if(doc.status === 'On Hold') {
@@ -235,9 +235,9 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
this.order_type(doc);
},
- make_pick_list() {
+ create_pick_list() {
frappe.model.open_mapped_doc({
- method: "erpnext.selling.doctype.sales_order.sales_order.make_pick_list",
+ method: "erpnext.selling.doctype.sales_order.sales_order.create_pick_list",
frm: this.frm
})
},
diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py
index 426b00484c..a063061107 100755
--- a/erpnext/selling/doctype/sales_order/sales_order.py
+++ b/erpnext/selling/doctype/sales_order/sales_order.py
@@ -1002,7 +1002,7 @@ def make_inter_company_purchase_order(source_name, target_doc=None):
return make_inter_company_transaction("Sales Order", source_name, target_doc)
@frappe.whitelist()
-def make_pick_list(source_name, target_doc=None):
+def create_pick_list(source_name, target_doc=None):
def update_item_quantity(source, target, source_parent):
target.qty = flt(source.qty) - flt(source.delivered_qty)
target.stock_qty = (flt(source.qty) - flt(source.delivered_qty)) * flt(source.conversion_factor)
diff --git a/erpnext/stock/doctype/pick_list/pick_list.js b/erpnext/stock/doctype/pick_list/pick_list.js
index a0082b859c..0a78faeb2b 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.js
+++ b/erpnext/stock/doctype/pick_list/pick_list.js
@@ -118,7 +118,7 @@ frappe.ui.form.on('Pick List', {
return;
}
erpnext.utils.map_current_doc({
- method: 'erpnext.selling.doctype.sales_order.sales_order.make_pick_list',
+ method: 'erpnext.selling.doctype.sales_order.sales_order.create_pick_list',
source_doctype: 'Sales Order',
target: frm,
setters: {
diff --git a/erpnext/stock/doctype/pick_list/test_pick_list.py b/erpnext/stock/doctype/pick_list/test_pick_list.py
index df42ff1256..96b770d1de 100644
--- a/erpnext/stock/doctype/pick_list/test_pick_list.py
+++ b/erpnext/stock/doctype/pick_list/test_pick_list.py
@@ -7,8 +7,6 @@ import frappe
import unittest
# test_dependencies = ['Item', 'Sales Invoice', 'Stock Entry', 'Batch']
-from erpnext.selling.doctype.sales_order.sales_order import make_pick_list
-
class TestPickList(unittest.TestCase):
def test_pick_list_picks_warehouse_for_each_item(self):
pick_list = frappe.get_doc({
From 457da47dba88e8c9c9f464b2a1da0164af87ed67 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Mon, 26 Aug 2019 10:05:35 +0530
Subject: [PATCH 328/484] fix: set for_qty instead of pick_list
---
erpnext/manufacturing/doctype/work_order/work_order.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/manufacturing/doctype/work_order/work_order.py b/erpnext/manufacturing/doctype/work_order/work_order.py
index d3ce1b8533..38e1157abc 100644
--- a/erpnext/manufacturing/doctype/work_order/work_order.py
+++ b/erpnext/manufacturing/doctype/work_order/work_order.py
@@ -711,7 +711,7 @@ def get_work_order_operation_data(work_order, operation, workstation):
@frappe.whitelist()
def create_pick_list(source_name, target_doc=None, for_qty=None):
- pick_list = for_qty or json.loads(target_doc).get('for_qty')
+ for_qty = for_qty or json.loads(target_doc).get('for_qty')
max_finished_goods_qty = frappe.db.get_value('Work Order', source_name, 'qty')
def update_item_quantity(source, target, source_parent):
# qty = source.required_qty - source.transferred_qty
From 00f9930fbf6e656a1036ba7776dd71c64cc4a7c8 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Mon, 26 Aug 2019 10:09:07 +0530
Subject: [PATCH 329/484] style: Remove leftout print statements
---
erpnext/stock/get_item_details.py | 4 ----
1 file changed, 4 deletions(-)
diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py
index 41101f4678..bf5a8180bd 100644
--- a/erpnext/stock/get_item_details.py
+++ b/erpnext/stock/get_item_details.py
@@ -46,14 +46,11 @@ def get_item_details(args, doc=None, overwrite_warehouse=True):
"""
args = process_args(args)
- print('warehouse', args.warehouse, '========')
item = frappe.get_cached_doc("Item", args.item_code)
validate_item_details(args, item)
out = get_basic_details(args, item, overwrite_warehouse)
- print('warehouse2', out.warehouse, '========')
-
get_item_tax_template(args, item, out)
out["item_tax_rate"] = get_item_tax_map(args.company, args.get("item_tax_template") if out.get("item_tax_template") is None \
else out.get("item_tax_template"), as_json=True)
@@ -800,7 +797,6 @@ def get_projected_qty(item_code, warehouse):
@frappe.whitelist()
def get_bin_details(item_code, warehouse):
- print(item_code, warehouse, '---------------------------')
return frappe.db.get_value("Bin", {"item_code": item_code, "warehouse": warehouse},
["projected_qty", "actual_qty", "reserved_qty"], as_dict=True, cache=True) \
or {"projected_qty": 0, "actual_qty": 0, "reserved_qty": 0}
From 5dd1b508026c69c0109ec5f09f4e62c7dcfde725 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Mon, 26 Aug 2019 10:27:25 +0530
Subject: [PATCH 330/484] fix: update show in website on disabling item
(#18831)
---
erpnext/stock/doctype/item/item.py | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py
index 1568729344..518fe74889 100644
--- a/erpnext/stock/doctype/item/item.py
+++ b/erpnext/stock/doctype/item/item.py
@@ -124,6 +124,7 @@ class Item(WebsiteGenerator):
self.update_defaults_from_item_group()
self.validate_auto_reorder_enabled_in_stock_settings()
self.cant_change()
+ self.update_show_in_website()
if not self.get("__islocal"):
self.old_item_group = frappe.db.get_value(self.doctype, self.name, "item_group")
@@ -476,6 +477,10 @@ class Item(WebsiteGenerator):
[self.remove(d) for d in to_remove]
+ def update_show_in_website(self):
+ if self.disabled:
+ self.show_in_website = False
+
def update_template_tables(self):
template = frappe.get_doc("Item", self.variant_of)
From db3bb793e9e4d6dd9b1b536c57afda5693de5689 Mon Sep 17 00:00:00 2001
From: Shivam Mishra
Date: Mon, 26 Aug 2019 11:29:18 +0530
Subject: [PATCH 331/484] feat: added domain info on footer (#18839)
---
erpnext/templates/includes/footer/footer_powered.html | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/erpnext/templates/includes/footer/footer_powered.html b/erpnext/templates/includes/footer/footer_powered.html
index faf5e9278c..8d5523ff97 100644
--- a/erpnext/templates/includes/footer/footer_powered.html
+++ b/erpnext/templates/includes/footer/footer_powered.html
@@ -1 +1,3 @@
-Powered by ERPNext
+{% set domains = frappe.get_doc("Domain Settings").active_domains %}
+
+Powered by ERPNext - {{ domains[0].domain if domains else 'Open Source' }} ERP Software
From 7243e774c27477ffeb30c0c155af7332697eb3df Mon Sep 17 00:00:00 2001
From: Himanshu Warekar
Date: Mon, 26 Aug 2019 12:49:20 +0530
Subject: [PATCH 332/484] fix: add city, state and country
---
erpnext/public/js/templates/contact_list.html | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/erpnext/public/js/templates/contact_list.html b/erpnext/public/js/templates/contact_list.html
index 0a339aa539..0df19bb996 100644
--- a/erpnext/public/js/templates/contact_list.html
+++ b/erpnext/public/js/templates/contact_list.html
@@ -37,7 +37,17 @@
{% endif %}
{% if (contact_list[i].address) { %}
- {%= __("Address ") %}: {%= contact_list[i].address %}
+ {%= __("Address ") %}: {%= contact_list[i].address %}
+ {% if (contact_list[i].city) { %}
+ , {%= contact_list[i].city %}
+ {% endif %}
+ {% if (contact_list[i].state) { %}
+ , {%= contact_list[i].state %}
+ {% endif %}
+ {% if (contact_list[i].country) { %}
+ , {%= contact_list[i].country %}
+ {% endif %}
+
{% endif %}
{% } %}
From 8ac2a2f0c4f1ac3fae0bc23b1e7abdd1558d2126 Mon Sep 17 00:00:00 2001
From: Faris Ansari
Date: Mon, 26 Aug 2019 13:00:17 +0530
Subject: [PATCH 333/484] fix: Set default Parent Item Group
---
erpnext/setup/doctype/item_group/item_group.py | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/erpnext/setup/doctype/item_group/item_group.py b/erpnext/setup/doctype/item_group/item_group.py
index 33ab992568..760b20a476 100644
--- a/erpnext/setup/doctype/item_group/item_group.py
+++ b/erpnext/setup/doctype/item_group/item_group.py
@@ -26,6 +26,10 @@ class ItemGroup(NestedSet, WebsiteGenerator):
def validate(self):
super(ItemGroup, self).validate()
+
+ if not self.parent_item_group:
+ self.parent_item_group = 'All Item Groups'
+
self.make_route()
def on_update(self):
From d6be8989e4d13f45383d919c1d816a8da7c1bc3c Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Mon, 26 Aug 2019 22:11:49 +0530
Subject: [PATCH 334/484] fix: Remove "Material Issue" purpose from pick list
- Because in material issue we already define source warehouse
---
erpnext/stock/doctype/material_request/material_request.js | 1 -
erpnext/stock/doctype/pick_list/pick_list.json | 4 ++--
erpnext/stock/doctype/pick_list/pick_list.py | 5 +++++
3 files changed, 7 insertions(+), 3 deletions(-)
diff --git a/erpnext/stock/doctype/material_request/material_request.js b/erpnext/stock/doctype/material_request/material_request.js
index feaa4132b8..1027dd5fea 100644
--- a/erpnext/stock/doctype/material_request/material_request.js
+++ b/erpnext/stock/doctype/material_request/material_request.js
@@ -67,7 +67,6 @@ frappe.ui.form.on('Material Request', {
}
if (frm.doc.material_request_type === "Material Issue") {
- add_create_pick_list_button();
frm.add_custom_button(__("Issue Material"),
() => frm.events.make_stock_entry(frm), __('Create'));
}
diff --git a/erpnext/stock/doctype/pick_list/pick_list.json b/erpnext/stock/doctype/pick_list/pick_list.json
index dbfd7d1bf2..c7aa4586bb 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.json
+++ b/erpnext/stock/doctype/pick_list/pick_list.json
@@ -98,7 +98,7 @@
"fieldname": "purpose",
"fieldtype": "Select",
"label": "Purpose",
- "options": "Material Transfer for Manufacture\nMaterial Issue\nMaterial Transfer\nDelivery against Sales Order"
+ "options": "Material Transfer for Manufacture\nMaterial Transfer\nDelivery against Sales Order"
},
{
"depends_on": "eval:['Material Transfer', 'Material Issue'].includes(doc.purpose)",
@@ -115,7 +115,7 @@
}
],
"is_submittable": 1,
- "modified": "2019-08-26 06:52:04.532885",
+ "modified": "2019-08-26 16:11:03.184637",
"modified_by": "Administrator",
"module": "Stock",
"name": "Pick List",
diff --git a/erpnext/stock/doctype/pick_list/pick_list.py b/erpnext/stock/doctype/pick_list/pick_list.py
index 16bb9e6dc7..d5bf64309d 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.py
+++ b/erpnext/stock/doctype/pick_list/pick_list.py
@@ -359,9 +359,14 @@ def update_stock_entry_based_on_work_order(pick_list, stock_entry):
def update_stock_entry_based_on_material_request(pick_list, stock_entry):
for location in pick_list.locations:
+ target_warehouse = None
+ if location.material_request_item:
+ target_warehouse = frappe.get_value('Material Request Item',
+ location.material_request_item, 'warehouse')
item = frappe._dict()
item.item_code = location.item_code
item.s_warehouse = location.warehouse
+ item.t_warehouse = target_warehouse
item.qty = location.qty
item.transfer_qty = location.stock_qty
item.uom = location.uom
From 9057239c3c92228ba0b957e47b73cc9e01de7891 Mon Sep 17 00:00:00 2001
From: Himanshu Warekar
Date: Mon, 26 Aug 2019 22:40:54 +0530
Subject: [PATCH 335/484] fix: display address
---
erpnext/public/js/templates/contact_list.html | 12 +-----------
1 file changed, 1 insertion(+), 11 deletions(-)
diff --git a/erpnext/public/js/templates/contact_list.html b/erpnext/public/js/templates/contact_list.html
index 0df19bb996..0a339aa539 100644
--- a/erpnext/public/js/templates/contact_list.html
+++ b/erpnext/public/js/templates/contact_list.html
@@ -37,17 +37,7 @@
{% endif %}
{% if (contact_list[i].address) { %}
- {%= __("Address ") %}: {%= contact_list[i].address %}
- {% if (contact_list[i].city) { %}
- , {%= contact_list[i].city %}
- {% endif %}
- {% if (contact_list[i].state) { %}
- , {%= contact_list[i].state %}
- {% endif %}
- {% if (contact_list[i].country) { %}
- , {%= contact_list[i].country %}
- {% endif %}
-
+ {%= __("Address ") %}: {%= contact_list[i].address %}
{% endif %}
{% } %}
From dc675b1eb0a0db97ed0ee6c1e8856d53bb70c58c Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Tue, 27 Aug 2019 08:06:22 +0530
Subject: [PATCH 336/484] fix: Re-order stock qty field
---
erpnext/stock/doctype/pick_list_item/pick_list_item.json | 4 ++--
.../pick_list_reference_item.json | 8 +++++---
2 files changed, 7 insertions(+), 5 deletions(-)
diff --git a/erpnext/stock/doctype/pick_list_item/pick_list_item.json b/erpnext/stock/doctype/pick_list_item/pick_list_item.json
index fdac9e58cf..809f6613a8 100644
--- a/erpnext/stock/doctype/pick_list_item/pick_list_item.json
+++ b/erpnext/stock/doctype/pick_list_item/pick_list_item.json
@@ -16,8 +16,8 @@
"picked_qty",
"column_break_11",
"uom",
- "stock_uom",
"conversion_factor",
+ "stock_uom",
"serial_no_and_batch_section",
"serial_no",
"column_break_20",
@@ -170,7 +170,7 @@
}
],
"istable": 1,
- "modified": "2019-08-26 06:54:06.783255",
+ "modified": "2019-08-26 22:19:56.872728",
"modified_by": "Administrator",
"module": "Stock",
"name": "Pick List Item",
diff --git a/erpnext/stock/doctype/pick_list_reference_item/pick_list_reference_item.json b/erpnext/stock/doctype/pick_list_reference_item/pick_list_reference_item.json
index b549a08e10..0b3c4dc89f 100644
--- a/erpnext/stock/doctype/pick_list_reference_item/pick_list_reference_item.json
+++ b/erpnext/stock/doctype/pick_list_reference_item/pick_list_reference_item.json
@@ -10,8 +10,8 @@
"stock_qty",
"column_break_5",
"uom",
- "stock_uom",
"conversion_factor",
+ "stock_uom",
"reference_section",
"sales_order",
"sales_order_item",
@@ -33,6 +33,7 @@
{
"fieldname": "stock_qty",
"fieldtype": "Float",
+ "in_list_view": 1,
"label": "Stock Qty"
},
{
@@ -45,7 +46,8 @@
"fieldname": "stock_uom",
"fieldtype": "Link",
"label": "Stock UOM",
- "options": "UOM"
+ "options": "UOM",
+ "read_only": 1
},
{
"fieldname": "item_code",
@@ -96,7 +98,7 @@
}
],
"istable": 1,
- "modified": "2019-08-26 06:54:50.702552",
+ "modified": "2019-08-26 23:02:52.470206",
"modified_by": "Administrator",
"module": "Stock",
"name": "Pick List Reference Item",
From 974ac3e6ade54f84f70010cc624cb73b276f6870 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Tue, 27 Aug 2019 10:17:16 +0530
Subject: [PATCH 337/484] fix: Update item detail for items without reference
---
.../material_request/material_request.py | 1 -
erpnext/stock/doctype/pick_list/pick_list.js | 50 +++++++++++++++++--
erpnext/stock/doctype/pick_list/pick_list.py | 11 +++-
.../pick_list_item/pick_list_item.json | 3 +-
.../pick_list_reference_item.json | 6 +--
5 files changed, 59 insertions(+), 12 deletions(-)
diff --git a/erpnext/stock/doctype/material_request/material_request.py b/erpnext/stock/doctype/material_request/material_request.py
index 7040d83215..9cad3f039f 100644
--- a/erpnext/stock/doctype/material_request/material_request.py
+++ b/erpnext/stock/doctype/material_request/material_request.py
@@ -521,7 +521,6 @@ def create_pick_list(source_name, target_doc=None):
'name': 'material_request_item',
'qty': 'stock_qty'
},
- # 'condition': lambda doc: abs(doc.transferred_qty) < abs(doc.required_qty)
},
}, target_doc)
diff --git a/erpnext/stock/doctype/pick_list/pick_list.js b/erpnext/stock/doctype/pick_list/pick_list.js
index 0a78faeb2b..0d00024a34 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.js
+++ b/erpnext/stock/doctype/pick_list/pick_list.js
@@ -27,7 +27,7 @@ frappe.ui.form.on('Pick List', {
};
});
},
- get_item_locations(frm) {
+ get_item_locations: (frm) => {
frm.call('set_item_locations');
},
refresh: (frm) => {
@@ -84,18 +84,22 @@ frappe.ui.form.on('Pick List', {
source_name: frm.doc.material_request
});
},
+ parent_warehouse: (frm) => {
+ frm.clear_table('locations');
+ frm.refresh_field('locations');
+ },
purpose: (frm) => {
frm.clear_table('items');
frm.clear_table('locations');
frm.trigger('add_get_items_button');
},
- create_delivery_note(frm) {
+ create_delivery_note: (frm) => {
frappe.model.open_mapped_doc({
method: 'erpnext.stock.doctype.pick_list.pick_list.create_delivery_note',
frm: frm
});
},
- create_stock_entry(frm) {
+ create_stock_entry: (frm) => {
frappe.xcall('erpnext.stock.doctype.pick_list.pick_list.create_stock_entry', {
'pick_list': frm.doc,
}).then(stock_entry => {
@@ -103,7 +107,7 @@ frappe.ui.form.on('Pick List', {
frappe.set_route("Form", 'Stock Entry', stock_entry.name);
});
},
- add_get_items_button(frm) {
+ add_get_items_button: (frm) => {
let purpose = frm.doc.purpose;
if (purpose != 'Delivery against Sales Order' || frm.doc.docstatus !== 0) return;
let get_query_filters = {
@@ -130,4 +134,40 @@ frappe.ui.form.on('Pick List', {
});
});
}
-});
\ No newline at end of file
+});
+
+frappe.ui.form.on('Pick List Reference Item', {
+ item_code: (frm, cdt, cdn) => {
+ let row = frappe.get_doc(cdt, cdn);
+ if (row.item_code) {
+ get_item_details(row.item_code).then(data => {
+ frappe.model.set_value(cdt, cdn, 'uom', data.stock_uom);
+ frappe.model.set_value(cdt, cdn, 'stock_uom', data.stock_uom);
+ frappe.model.set_value(cdt, cdn, 'conversion_factor', 1);
+ });
+ }
+ },
+ uom: (frm, cdt, cdn) => {
+ let row = frappe.get_doc(cdt, cdn);
+ if (row.uom) {
+ get_item_details(row.item_code, row.uom).then(data => {
+ frappe.model.set_value(cdt, cdn, 'conversion_factor', data.conversion_factor);
+ });
+ }
+ },
+ qty: (frm, cdt, cdn) => {
+ let row = frappe.get_doc(cdt, cdn);
+ frappe.model.set_value(cdt, cdn, 'stock_qty', row.qty * row.conversion_factor);
+ },
+ conversion_factor: (frm, cdt, cdn) => {
+ let row = frappe.get_doc(cdt, cdn);
+ frappe.model.set_value(cdt, cdn, 'stock_qty', row.qty * row.conversion_factor);
+ }
+});
+
+function get_item_details(item_code, uom=null) {
+ return frappe.xcall('erpnext.stock.doctype.pick_list.pick_list.get_item_details', {
+ item_code,
+ uom
+ });
+}
\ No newline at end of file
diff --git a/erpnext/stock/doctype/pick_list/pick_list.py b/erpnext/stock/doctype/pick_list/pick_list.py
index d5bf64309d..e12bd92c95 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.py
+++ b/erpnext/stock/doctype/pick_list/pick_list.py
@@ -317,8 +317,15 @@ def stock_entry_exists(pick_list_name):
'pick_list': pick_list_name
})
-def get_item_details(item_code):
- pass
+@frappe.whitelist()
+def get_item_details(item_code, uom=None):
+ details = frappe.db.get_value('Item', item_code, ['stock_uom', 'name'], as_dict=1)
+ details.uom = uom or details.stock_uom
+ if uom:
+ details.update(get_conversion_factor(item_code, uom))
+
+ return details
+
def update_stock_entry_based_on_work_order(pick_list, stock_entry):
work_order = frappe.get_doc("Work Order", pick_list.get('work_order'))
diff --git a/erpnext/stock/doctype/pick_list_item/pick_list_item.json b/erpnext/stock/doctype/pick_list_item/pick_list_item.json
index 809f6613a8..947737719e 100644
--- a/erpnext/stock/doctype/pick_list_item/pick_list_item.json
+++ b/erpnext/stock/doctype/pick_list_item/pick_list_item.json
@@ -112,6 +112,7 @@
{
"fieldname": "stock_qty",
"fieldtype": "Float",
+ "in_list_view": 1,
"label": "Qty as per Stock UOM",
"read_only": 1
},
@@ -170,7 +171,7 @@
}
],
"istable": 1,
- "modified": "2019-08-26 22:19:56.872728",
+ "modified": "2019-08-27 08:44:04.173333",
"modified_by": "Administrator",
"module": "Stock",
"name": "Pick List Item",
diff --git a/erpnext/stock/doctype/pick_list_reference_item/pick_list_reference_item.json b/erpnext/stock/doctype/pick_list_reference_item/pick_list_reference_item.json
index 0b3c4dc89f..861e6969d6 100644
--- a/erpnext/stock/doctype/pick_list_reference_item/pick_list_reference_item.json
+++ b/erpnext/stock/doctype/pick_list_reference_item/pick_list_reference_item.json
@@ -33,8 +33,8 @@
{
"fieldname": "stock_qty",
"fieldtype": "Float",
- "in_list_view": 1,
- "label": "Stock Qty"
+ "label": "Stock Qty",
+ "read_only": 1
},
{
"fieldname": "uom",
@@ -98,7 +98,7 @@
}
],
"istable": 1,
- "modified": "2019-08-26 23:02:52.470206",
+ "modified": "2019-08-27 08:40:21.870638",
"modified_by": "Administrator",
"module": "Stock",
"name": "Pick List Reference Item",
From c5e0838890b95c977e6df4521e513dae3b3bb541 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Tue, 27 Aug 2019 12:14:17 +0530
Subject: [PATCH 338/484] fix: Import get_conversion factor method
---
erpnext/stock/doctype/pick_list/pick_list.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/erpnext/stock/doctype/pick_list/pick_list.py b/erpnext/stock/doctype/pick_list/pick_list.py
index e12bd92c95..c7653438c1 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.py
+++ b/erpnext/stock/doctype/pick_list/pick_list.py
@@ -10,6 +10,7 @@ from frappe.model.document import Document
from frappe import _
from frappe.utils import floor, flt, today
from frappe.model.mapper import get_mapped_doc, map_child_doc
+from erpnext.stock.get_item_details import get_conversion_factor
from erpnext.selling.doctype.sales_order.sales_order import make_delivery_note as create_delivery_note_from_sales_order
# TODO: Prioritize SO or WO group warehouse
From cfec328c7490b12ec55a90cfb35edf0f1a360636 Mon Sep 17 00:00:00 2001
From: mbhavesh95863 <41165270+mbhavesh95863@users.noreply.github.com>
Date: Tue, 27 Aug 2019 19:17:19 +0530
Subject: [PATCH 339/484] Same report 2 times in list
---
erpnext/config/selling.py | 6 ------
1 file changed, 6 deletions(-)
diff --git a/erpnext/config/selling.py b/erpnext/config/selling.py
index 844710d47c..928bd5fa32 100644
--- a/erpnext/config/selling.py
+++ b/erpnext/config/selling.py
@@ -304,12 +304,6 @@ def get_data():
"name": "Customers Without Any Sales Transactions",
"doctype": "Customer"
},
- {
- "type": "report",
- "is_query_report": True,
- "name": "Sales Partners Commission",
- "doctype": "Customer"
- },
{
"type": "report",
"is_query_report": True,
From 17d3de18212ae398495a53d6b074b4aa768ad448 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Tue, 27 Aug 2019 22:37:12 +0530
Subject: [PATCH 340/484] fix: process allocation expiry
---
.../leave_ledger_entry/leave_ledger_entry.py | 35 +++++++++----------
1 file changed, 17 insertions(+), 18 deletions(-)
diff --git a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
index c82114e6d5..bfc6d95d17 100644
--- a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
+++ b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
@@ -95,26 +95,25 @@ def process_expired_allocation():
'expire_carry_forwarded_leaves_after_days': (">", 0)
}, fieldname=['name'])
- if leave_type_records:
- leave_type = [record[0] for record in leave_type_records]
+ leave_type = [record[0] for record in leave_type_records]
- expired_allocation = frappe.db.sql_list("""SELECT name
- FROM `tabLeave Ledger Entry`
- WHERE
- `transaction_type`='Leave Allocation'
- AND `is_expired`=1""")
+ expired_allocation = frappe.db.sql_list("""SELECT name
+ FROM `tabLeave Ledger Entry`
+ WHERE
+ `transaction_type`='Leave Allocation'
+ AND `is_expired`=1""")
- expire_allocation = frappe.get_all("Leave Ledger Entry",
- fields=['leaves', 'to_date', 'employee', 'leave_type', 'is_carry_forward', 'transaction_name as name', 'transaction_type'],
- filters={
- 'to_date': ("<", today()),
- 'transaction_type': 'Leave Allocation',
- 'transaction_name': ('not in', expired_allocation)
- },
- or_filters={
- 'is_carry_forward': 0,
- 'leave_type': ('in', leave_type)
- })
+ expire_allocation = frappe.get_all("Leave Ledger Entry",
+ fields=['leaves', 'to_date', 'employee', 'leave_type', 'is_carry_forward', 'transaction_name as name', 'transaction_type'],
+ filters={
+ 'to_date': ("<", today()),
+ 'transaction_type': 'Leave Allocation',
+ 'transaction_name': ('not in', expired_allocation)
+ },
+ or_filters={
+ 'is_carry_forward': 0,
+ 'leave_type': ('in', leave_type)
+ })
if expire_allocation:
create_expiry_ledger_entry(expire_allocation)
From a5b78f3c0d3e8230b410f78eb2d576fcb4159434 Mon Sep 17 00:00:00 2001
From: Himanshu Warekar
Date: Wed, 28 Aug 2019 00:04:05 +0530
Subject: [PATCH 341/484] fix: get address in single line
---
erpnext/public/js/templates/contact_list.html | 2 ++
1 file changed, 2 insertions(+)
diff --git a/erpnext/public/js/templates/contact_list.html b/erpnext/public/js/templates/contact_list.html
index 0a339aa539..8dd220f72d 100644
--- a/erpnext/public/js/templates/contact_list.html
+++ b/erpnext/public/js/templates/contact_list.html
@@ -36,9 +36,11 @@
{% endif %}
{% endif %}
+
{% if (contact_list[i].address) { %}
{%= __("Address ") %}: {%= contact_list[i].address %}
{% endif %}
+
{% } %}
{% if(!contact_list.length) { %}
From 8f32ac0eddb0ded74828043bd3fdf5a39e538e5d Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Wed, 28 Aug 2019 10:16:20 +0530
Subject: [PATCH 342/484] fix: Batch selection logic
---
.../stock/doctype/pick_list/pick_list.json | 4 +-
erpnext/stock/doctype/pick_list/pick_list.py | 44 ++++++++++++-------
2 files changed, 29 insertions(+), 19 deletions(-)
diff --git a/erpnext/stock/doctype/pick_list/pick_list.json b/erpnext/stock/doctype/pick_list/pick_list.json
index c7aa4586bb..b52e18974b 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.json
+++ b/erpnext/stock/doctype/pick_list/pick_list.json
@@ -77,7 +77,7 @@
"options": "Pick List Item"
},
{
- "depends_on": "work_order",
+ "depends_on": "eval:doc.purpose==='Material Transfer for Manufacture'",
"description": "Qty of raw materials will be decided based on the qty of the Finished Goods Item",
"fieldname": "for_qty",
"fieldtype": "Float",
@@ -115,7 +115,7 @@
}
],
"is_submittable": 1,
- "modified": "2019-08-26 16:11:03.184637",
+ "modified": "2019-08-27 21:24:50.609986",
"modified_by": "Administrator",
"module": "Stock",
"name": "Pick List",
diff --git a/erpnext/stock/doctype/pick_list/pick_list.py b/erpnext/stock/doctype/pick_list/pick_list.py
index c7653438c1..11a998518a 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.py
+++ b/erpnext/stock/doctype/pick_list/pick_list.py
@@ -55,13 +55,19 @@ class PickList(Document):
def get_items_with_warehouse_and_quantity(item_doc, from_warehouses, item_location_map):
available_locations = item_location_map.get(item_doc.item_code)
locations = []
+ skip_warehouse = None
+
+ if item_doc.material_request:
+ skip_warehouse = frappe.get_value('Material Request Item', item_doc.material_request_item, 'warehouse')
+
remaining_stock_qty = item_doc.stock_qty
while remaining_stock_qty > 0 and available_locations:
item_location = available_locations.pop(0)
+
stock_qty = remaining_stock_qty if item_location.qty >= remaining_stock_qty else item_location.qty
qty = stock_qty / (item_doc.conversion_factor or 1)
- uom_must_be_whole_number = frappe.db.get_value("UOM", item_doc.uom, "must_be_whole_number")
+ uom_must_be_whole_number = frappe.db.get_value('UOM', item_doc.uom, 'must_be_whole_number')
if uom_must_be_whole_number:
qty = floor(qty)
stock_qty = qty * item_doc.conversion_factor
@@ -131,7 +137,7 @@ def get_item_locations_based_on_serial_nos(item_doc):
return locations
def get_item_locations_based_on_batch_nos(item_doc):
- batch_qty = frappe.db.sql("""
+ batch_locations = frappe.db.sql("""
SELECT
sle.`warehouse`,
sle.`batch_no`,
@@ -141,27 +147,30 @@ def get_item_locations_based_on_batch_nos(item_doc):
WHERE
sle.batch_no = batch.name
and sle.`item_code`=%(item_code)s
- and IFNULL(batch.expiry_date, '2200-01-01') > %(today)s
+ and IFNULL(batch.`expiry_date`, '2200-01-01') > %(today)s
GROUP BY
`warehouse`,
`batch_no`,
`item_code`
HAVING `qty` > 0
- ORDER BY IFNULL(batch.expiry_date, '2200-01-01')
+ ORDER BY IFNULL(batch.`expiry_date`, '2200-01-01'), batch.`creation`
""", {
'item_code': item_doc.item_code,
'today': today()
}, as_dict=1)
locations = []
- required_qty = item_doc.qty
- for d in batch_qty:
- if d.qty > required_qty:
- d.qty = required_qty
- else:
- required_qty -= d.qty
+ required_qty = item_doc.stock_qty
- locations.append(d)
+ for batch_location in batch_locations:
+ if batch_location.qty >= required_qty:
+ # this batch should fulfill the required items
+ batch_location.qty = required_qty
+ required_qty = 0
+ else:
+ required_qty -= batch_location.qty
+
+ locations.append(batch_location)
if required_qty <= 0:
break
@@ -171,7 +180,6 @@ def get_item_locations_based_on_batch_nos(item_doc):
return locations
-
@frappe.whitelist()
def create_delivery_note(source_name, target_doc=None):
pick_list = frappe.get_doc('Pick List', source_name)
@@ -199,7 +207,9 @@ def create_delivery_note(source_name, target_doc=None):
if dn_item:
dn_item.warehouse = location.warehouse
- dn_item.qty = location.qty
+ dn_item.qty = location.picked_qty
+ dn_item.batch_no = location.batch_no
+ dn_item.serial_no = location.serial_no
update_delivery_note_item(sales_order_item, dn_item, delivery_note)
@@ -355,8 +365,8 @@ def update_stock_entry_based_on_work_order(pick_list, stock_entry):
item.item_code = location.item_code
item.s_warehouse = location.warehouse
item.t_warehouse = wip_warehouse
- item.qty = location.qty
- item.transfer_qty = location.stock_qty
+ item.qty = location.picked_qty * location.conversion_factor
+ item.transfer_qty = location.picked_qty
item.uom = location.uom
item.conversion_factor = location.conversion_factor
item.stock_uom = location.stock_uom
@@ -375,8 +385,8 @@ def update_stock_entry_based_on_material_request(pick_list, stock_entry):
item.item_code = location.item_code
item.s_warehouse = location.warehouse
item.t_warehouse = target_warehouse
- item.qty = location.qty
- item.transfer_qty = location.stock_qty
+ item.qty = location.picked_qty * location.conversion_factor
+ item.transfer_qty = location.picked_qty
item.uom = location.uom
item.conversion_factor = location.conversion_factor
item.stock_uom = location.stock_uom
From 0aeccbf4b2ccecd71f43fd8b4d33fa6e300f5e82 Mon Sep 17 00:00:00 2001
From: Shivam Mishra
Date: Wed, 28 Aug 2019 11:39:45 +0530
Subject: [PATCH 343/484] feat: added dashboard fixtures (#18812)
* feat: add dashboard charts fixture
* fix: remove return statement
* feat: added patch for creating default dashboards
* chore: renamed dashboard charts
* feat: add add_dashboard function to install fixtures
* fix: reload doctype issue in patches
* fix (travis): reloaded dashboard chart source
* fix (travis): reloaded dashboard chart source
* fix (travis): reloaded dashboard doctype
* fix (travis): reloaded dashboard chart link doctype
---
erpnext/patches.txt | 5 +
.../patches/v12_0/add_default_dashboards.py | 8 ++
.../setup_wizard/data/dashboard_charts.py | 107 ++++++++++++++++++
.../operations/install_fixtures.py | 10 +-
4 files changed, 129 insertions(+), 1 deletion(-)
create mode 100644 erpnext/patches/v12_0/add_default_dashboards.py
create mode 100644 erpnext/setup/setup_wizard/data/dashboard_charts.py
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index dc6c6daa13..07b8ee6ab4 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -625,5 +625,10 @@ erpnext.patches.v12_0.add_default_buying_selling_terms_in_company
erpnext.patches.v12_0.update_ewaybill_field_position
erpnext.patches.v12_0.create_accounting_dimensions_in_missing_doctypes
erpnext.patches.v11_1.set_status_for_material_request_type_manufacture
+execute:frappe.reload_doc('desk', 'doctype','dashboard_chart_link')
+execute:frappe.reload_doc('desk', 'doctype','dashboard')
+execute:frappe.reload_doc('desk', 'doctype','dashboard_chart_source')
+execute:frappe.reload_doc('desk', 'doctype','dashboard_chart')
+erpnext.patches.v12_0.add_default_dashboards
erpnext.patches.v12_0.remove_bank_remittance_custom_fields
erpnext.patches.v12_0.generate_leave_ledger_entries
diff --git a/erpnext/patches/v12_0/add_default_dashboards.py b/erpnext/patches/v12_0/add_default_dashboards.py
new file mode 100644
index 0000000000..ab92fbaa69
--- /dev/null
+++ b/erpnext/patches/v12_0/add_default_dashboards.py
@@ -0,0 +1,8 @@
+# Copyright (c) 2019, Frappe and Contributors
+# License: GNU General Public License v3. See license.txt
+
+import frappe
+from erpnext.setup.setup_wizard.operations.install_fixtures import add_dashboards
+
+def execute():
+ add_dashboards()
diff --git a/erpnext/setup/setup_wizard/data/dashboard_charts.py b/erpnext/setup/setup_wizard/data/dashboard_charts.py
new file mode 100644
index 0000000000..41cfcb529e
--- /dev/null
+++ b/erpnext/setup/setup_wizard/data/dashboard_charts.py
@@ -0,0 +1,107 @@
+from __future__ import unicode_literals
+from frappe import _
+import frappe
+import json
+
+def get_default_dashboards():
+ company = frappe.get_doc("Company", frappe.defaults.get_defaults().company)
+ income_account = company.default_income_account or get_account("Income Account", company.name)
+ expense_account = company.default_expense_account or get_account("Expense Account", company.name)
+ bank_account = company.default_bank_account or get_account("Bank", company.name)
+
+ return {
+ "Dashboards": [
+ {
+ "doctype": "Dashboard",
+ "dashboard_name": "Accounts",
+ "charts": [
+ { "chart": "Outgoing Bills (Sales Invoice)" },
+ { "chart": "Incoming Bills (Purchase Invoice)" },
+ { "chart": "Bank Balance" },
+ { "chart": "Income" },
+ { "chart": "Expenses" }
+ ]
+ }
+ ],
+ "Charts": [
+ {
+ "doctype": "Dashboard Chart",
+ "time_interval": "Quarterly",
+ "chart_name": "Income",
+ "timespan": "Last Year",
+ "color": None,
+ "filters_json": json.dumps({"company": company.name, "account": income_account}),
+ "source": "Account Balance Timeline",
+ "chart_type": "Custom",
+ "timeseries": 1,
+ "owner": "Administrator",
+ "type": "Line",
+ "width": "Half"
+ },
+ {
+ "doctype": "Dashboard Chart",
+ "time_interval": "Quarterly",
+ "chart_name": "Expenses",
+ "timespan": "Last Year",
+ "color": None,
+ "filters_json": json.dumps({"company": company.name, "account": expense_account}),
+ "source": "Account Balance Timeline",
+ "chart_type": "Custom",
+ "timeseries": 1,
+ "owner": "Administrator",
+ "type": "Line",
+ "width": "Half"
+ },
+ {
+ "doctype": "Dashboard Chart",
+ "time_interval": "Quarterly",
+ "chart_name": "Bank Balance",
+ "timespan": "Last Year",
+ "color": "#ffb868",
+ "filters_json": json.dumps({"company": company.name, "account": bank_account}),
+ "source": "Account Balance Timeline",
+ "chart_type": "Custom",
+ "timeseries": 1,
+ "owner": "Administrator",
+ "type": "Line",
+ "width": "Half"
+ },
+ {
+ "doctype": "Dashboard Chart",
+ "time_interval": "Monthly",
+ "chart_name": "Incoming Bills (Purchase Invoice)",
+ "timespan": "Last Year",
+ "color": "#a83333",
+ "value_based_on": "base_grand_total",
+ "filters_json": json.dumps({}),
+ "chart_type": "Sum",
+ "timeseries": 1,
+ "based_on": "posting_date",
+ "owner": "Administrator",
+ "document_type": "Purchase Invoice",
+ "type": "Bar",
+ "width": "Half"
+ },
+ {
+ "doctype": "Dashboard Chart",
+ "time_interval": "Monthly",
+ "chart_name": "Outgoing Bills (Sales Invoice)",
+ "timespan": "Last Year",
+ "color": "#7b933d",
+ "value_based_on": "base_grand_total",
+ "filters_json": json.dumps({}),
+ "chart_type": "Sum",
+ "timeseries": 1,
+ "based_on": "posting_date",
+ "owner": "Administrator",
+ "document_type": "Sales Invoice",
+ "type": "Bar",
+ "width": "Half"
+ }
+ ]
+ }
+
+def get_account(account_type, company):
+ accounts = frappe.get_list("Account", filters={"account_type": account_type, "company": company})
+ if accounts:
+ return accounts[0].name
\ No newline at end of file
diff --git a/erpnext/setup/setup_wizard/operations/install_fixtures.py b/erpnext/setup/setup_wizard/operations/install_fixtures.py
index 4b734df61d..7123021d1e 100644
--- a/erpnext/setup/setup_wizard/operations/install_fixtures.py
+++ b/erpnext/setup/setup_wizard/operations/install_fixtures.py
@@ -475,13 +475,14 @@ def install_defaults(args=None):
frappe.db.set_value("Company", args.company_name, "default_bank_account", bank_account.name, update_modified=False)
- return doc
except RootNotEditable:
frappe.throw(_("Bank account cannot be named as {0}").format(args.bank_account))
except frappe.DuplicateEntryError:
# bank account same as a CoA entry
pass
+ add_dashboards()
+
# Now, with fixtures out of the way, onto concrete stuff
records = [
@@ -499,6 +500,13 @@ def install_defaults(args=None):
make_records(records)
+def add_dashboards():
+ from erpnext.setup.setup_wizard.data.dashboard_charts import get_default_dashboards
+ dashboard_data = get_default_dashboards()
+
+ make_records(dashboard_data["Charts"])
+ make_records(dashboard_data["Dashboards"])
+
def get_fy_details(fy_start_date, fy_end_date):
start_year = getdate(fy_start_date).year
From be0ae7a4303d65310260ae698e75c9551ac71574 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Wed, 28 Aug 2019 12:40:26 +0530
Subject: [PATCH 344/484] fix: Doctype changes - Check no copy for work order
series field - Add dashboard - Set naming_series for pick list
---
erpnext/config/stock.py | 8 +++++++-
.../doctype/work_order/work_order.json | 3 ++-
erpnext/stock/doctype/pick_list/pick_list.js | 4 ++++
erpnext/stock/doctype/pick_list/pick_list.json | 15 ++++++++++++---
.../doctype/pick_list_item/pick_list_item.json | 4 ++--
5 files changed, 27 insertions(+), 7 deletions(-)
diff --git a/erpnext/config/stock.py b/erpnext/config/stock.py
index 7d66df2360..441a3ab4ec 100644
--- a/erpnext/config/stock.py
+++ b/erpnext/config/stock.py
@@ -30,6 +30,12 @@ def get_data():
"onboard": 1,
"dependencies": ["Item"],
},
+ {
+ "type": "doctype",
+ "name": "Pick List",
+ "onboard": 1,
+ "dependencies": ["Item"],
+ },
{
"type": "doctype",
"name": "Delivery Trip"
@@ -329,5 +335,5 @@ def get_data():
}
]
},
-
+
]
diff --git a/erpnext/manufacturing/doctype/work_order/work_order.json b/erpnext/manufacturing/doctype/work_order/work_order.json
index 63c95e7c21..0d073a2312 100644
--- a/erpnext/manufacturing/doctype/work_order/work_order.json
+++ b/erpnext/manufacturing/doctype/work_order/work_order.json
@@ -72,6 +72,7 @@
"fieldname": "naming_series",
"fieldtype": "Select",
"label": "Series",
+ "no_copy": 1,
"options": "MFG-WO-.YYYY.-",
"print_hide": 1,
"reqd": 1,
@@ -467,7 +468,7 @@
"idx": 1,
"image_field": "image",
"is_submittable": 1,
- "modified": "2019-07-31 00:13:38.218277",
+ "modified": "2019-08-28 12:29:35.315239",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "Work Order",
diff --git a/erpnext/stock/doctype/pick_list/pick_list.js b/erpnext/stock/doctype/pick_list/pick_list.js
index 0d00024a34..163ff8c2f2 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.js
+++ b/erpnext/stock/doctype/pick_list/pick_list.js
@@ -3,6 +3,10 @@
frappe.ui.form.on('Pick List', {
setup: (frm) => {
+ frm.custom_make_buttons = {
+ 'Delivery Note': 'Delivery Note',
+ 'Stock Entry': 'Stock Entry',
+ };
frm.set_query('parent_warehouse', () => {
return {
filters: {
diff --git a/erpnext/stock/doctype/pick_list/pick_list.json b/erpnext/stock/doctype/pick_list/pick_list.json
index b52e18974b..5d33378d69 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.json
+++ b/erpnext/stock/doctype/pick_list/pick_list.json
@@ -1,10 +1,12 @@
{
- "autoname": "PICK.####",
+ "autoname": "naming_series:",
"creation": "2019-07-11 16:03:13.681045",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
+ "naming_series",
+ "company",
"purpose",
"customer",
"work_order",
@@ -12,7 +14,6 @@
"for_qty",
"column_break_4",
"parent_warehouse",
- "company",
"section_break_4",
"items",
"get_item_locations",
@@ -112,10 +113,18 @@
"fieldname": "get_item_locations",
"fieldtype": "Button",
"label": "Get Item Locations"
+ },
+ {
+ "fieldname": "naming_series",
+ "fieldtype": "Select",
+ "label": "Series",
+ "options": "STO-PICK-.YYYY.-",
+ "reqd": 1,
+ "set_only_once": 1
}
],
"is_submittable": 1,
- "modified": "2019-08-27 21:24:50.609986",
+ "modified": "2019-08-28 12:27:22.743705",
"modified_by": "Administrator",
"module": "Stock",
"name": "Pick List",
diff --git a/erpnext/stock/doctype/pick_list_item/pick_list_item.json b/erpnext/stock/doctype/pick_list_item/pick_list_item.json
index 947737719e..4dc3ae4e3a 100644
--- a/erpnext/stock/doctype/pick_list_item/pick_list_item.json
+++ b/erpnext/stock/doctype/pick_list_item/pick_list_item.json
@@ -113,7 +113,7 @@
"fieldname": "stock_qty",
"fieldtype": "Float",
"in_list_view": 1,
- "label": "Qty as per Stock UOM",
+ "label": "Qty (Stock UOM)",
"read_only": 1
},
{
@@ -171,7 +171,7 @@
}
],
"istable": 1,
- "modified": "2019-08-27 08:44:04.173333",
+ "modified": "2019-08-28 12:34:06.224534",
"modified_by": "Administrator",
"module": "Stock",
"name": "Pick List Item",
From 1cf7270049b511fe6a4ce4d73479bc915dbf9d2e Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Wed, 28 Aug 2019 12:40:58 +0530
Subject: [PATCH 345/484] fix: Add picklist dashboard config
---
.../stock/doctype/pick_list/pick_list_dashboard.py | 12 ++++++++++++
1 file changed, 12 insertions(+)
create mode 100644 erpnext/stock/doctype/pick_list/pick_list_dashboard.py
diff --git a/erpnext/stock/doctype/pick_list/pick_list_dashboard.py b/erpnext/stock/doctype/pick_list/pick_list_dashboard.py
new file mode 100644
index 0000000000..6e007df5e6
--- /dev/null
+++ b/erpnext/stock/doctype/pick_list/pick_list_dashboard.py
@@ -0,0 +1,12 @@
+from __future__ import unicode_literals
+from frappe import _
+
+def get_data():
+ return {
+ 'fieldname': 'pick_list',
+ 'transactions': [
+ {
+ 'items': ['Stock Entry', 'Delivery Note']
+ },
+ ]
+ }
\ No newline at end of file
From 9fa5dbd6e4fea97b96059e0e1c37b77194aa1d06 Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Wed, 28 Aug 2019 13:29:03 +0530
Subject: [PATCH 346/484] fix: raised exception in shopify
---
.../doctype/shopify_settings/shopify_settings.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/erpnext/erpnext_integrations/doctype/shopify_settings/shopify_settings.py b/erpnext/erpnext_integrations/doctype/shopify_settings/shopify_settings.py
index 7f4b7bab0a..f5191770b2 100644
--- a/erpnext/erpnext_integrations/doctype/shopify_settings/shopify_settings.py
+++ b/erpnext/erpnext_integrations/doctype/shopify_settings/shopify_settings.py
@@ -58,7 +58,7 @@ class ShopifySettings(Document):
d.raise_for_status()
self.update_webhook_table(method, d.json())
except Exception as e:
- make_shopify_log(status="Warning", message=e.message, exception=False)
+ make_shopify_log(status="Warning", message=e, exception=False)
def unregister_webhooks(self):
session = get_request_session()
@@ -71,7 +71,7 @@ class ShopifySettings(Document):
res.raise_for_status()
deleted_webhooks.append(d)
except Exception as e:
- frappe.log_error(message=frappe.get_traceback(), title=e.message[:140])
+ frappe.log_error(message=frappe.get_traceback(), title=e[:140])
for d in deleted_webhooks:
self.remove(d)
From 1707c3da9598ee51124d0ba93069cf38408446a3 Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Wed, 28 Aug 2019 13:55:26 +0530
Subject: [PATCH 347/484] fix: exception
Co-Authored-By: Himanshu
---
.../doctype/shopify_settings/shopify_settings.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/erpnext_integrations/doctype/shopify_settings/shopify_settings.py b/erpnext/erpnext_integrations/doctype/shopify_settings/shopify_settings.py
index f5191770b2..4943053663 100644
--- a/erpnext/erpnext_integrations/doctype/shopify_settings/shopify_settings.py
+++ b/erpnext/erpnext_integrations/doctype/shopify_settings/shopify_settings.py
@@ -71,7 +71,7 @@ class ShopifySettings(Document):
res.raise_for_status()
deleted_webhooks.append(d)
except Exception as e:
- frappe.log_error(message=frappe.get_traceback(), title=e[:140])
+ frappe.log_error(message=frappe.get_traceback(), title=e)
for d in deleted_webhooks:
self.remove(d)
From d03d8204ab797e2b4cb3a46e4fda64a5e4f91f1e Mon Sep 17 00:00:00 2001
From: Rohit Waghchaure
Date: Wed, 28 Aug 2019 16:56:07 +0530
Subject: [PATCH 348/484] fix: incorrect valuation rate calculated because of
string replacement issue
---
erpnext/stock/stock_ledger.py | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py
index 920fc272f7..f7deac3591 100644
--- a/erpnext/stock/stock_ledger.py
+++ b/erpnext/stock/stock_ledger.py
@@ -227,9 +227,9 @@ class update_entries_after(object):
elif actual_qty < 0:
# In case of delivery/stock issue, get average purchase rate
# of serial nos of current entry
- stock_value_change = -1 * flt(frappe.db.sql("""select sum(purchase_rate)
- from `tabSerial No` where name in (%s)""" % (", ".join(["%s"]*len(serial_no))),
- tuple(serial_no))[0][0])
+ stock_value_change = -1 * flt(frappe.get_all("Serial No",
+ fields=["sum(purchase_rate)"],
+ filters = {'name': ('in', serial_no)}, as_list=1)[0][0])
new_stock_qty = self.qty_after_transaction + actual_qty
From b654dc0e288e3ecfdfbd0831c3ae15cc7036bb90 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Tue, 27 Aug 2019 22:32:33 +0530
Subject: [PATCH 349/484] fix: process allocation expiry
---
.../leave_ledger_entry/leave_ledger_entry.py | 37 +++++++++----------
1 file changed, 18 insertions(+), 19 deletions(-)
diff --git a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
index c82114e6d5..228e226645 100644
--- a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
+++ b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
@@ -95,29 +95,28 @@ def process_expired_allocation():
'expire_carry_forwarded_leaves_after_days': (">", 0)
}, fieldname=['name'])
- if leave_type_records:
- leave_type = [record[0] for record in leave_type_records]
+ leave_type = [record[0] for record in leave_type_records]
- expired_allocation = frappe.db.sql_list("""SELECT name
- FROM `tabLeave Ledger Entry`
- WHERE
- `transaction_type`='Leave Allocation'
- AND `is_expired`=1""")
+ expired_allocation = frappe.db.sql_list("""SELECT name
+ FROM `tabLeave Ledger Entry`
+ WHERE
+ `transaction_type`='Leave Allocation'
+ AND `is_expired`=1""")
- expire_allocation = frappe.get_all("Leave Ledger Entry",
- fields=['leaves', 'to_date', 'employee', 'leave_type', 'is_carry_forward', 'transaction_name as name', 'transaction_type'],
- filters={
- 'to_date': ("<", today()),
- 'transaction_type': 'Leave Allocation',
- 'transaction_name': ('not in', expired_allocation)
- },
- or_filters={
- 'is_carry_forward': 0,
- 'leave_type': ('in', leave_type)
- })
+ expire_allocation = frappe.get_all("Leave Ledger Entry",
+ fields=['leaves', 'to_date', 'employee', 'leave_type', 'is_carry_forward', 'transaction_name as name', 'transaction_type'],
+ filters={
+ 'to_date': ("<", today()),
+ 'transaction_type': 'Leave Allocation',
+ 'transaction_name': ('not in', expired_allocation)
+ },
+ or_filters={
+ 'is_carry_forward': 0,
+ 'leave_type': ('in', leave_type)
+ })
if expire_allocation:
- create_expiry_ledger_entry(expire_allocation)
+ create_expiry_ledger_entry(expire_allocation)
def create_expiry_ledger_entry(allocations):
''' Create ledger entry for expired allocation '''
From f455c92d02554103e91025705c5758c9d5d96a5b Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Wed, 28 Aug 2019 17:44:22 +0530
Subject: [PATCH 350/484] fix: Remove Pick List Reference Item use Item
locations table instead
---
.../doctype/work_order/work_order.py | 33 ++----
.../doctype/sales_order/sales_order.py | 26 +++--
.../material_request/material_request.py | 4 +-
erpnext/stock/doctype/pick_list/pick_list.js | 11 +-
.../stock/doctype/pick_list/pick_list.json | 17 +--
erpnext/stock/doctype/pick_list/pick_list.py | 48 +++-----
.../pick_list_item/pick_list_item.json | 11 +-
.../pick_list_reference_item/__init__.py | 0
.../pick_list_reference_item.js | 8 --
.../pick_list_reference_item.json | 109 ------------------
.../pick_list_reference_item.py | 10 --
11 files changed, 49 insertions(+), 228 deletions(-)
delete mode 100644 erpnext/stock/doctype/pick_list_reference_item/__init__.py
delete mode 100644 erpnext/stock/doctype/pick_list_reference_item/pick_list_reference_item.js
delete mode 100644 erpnext/stock/doctype/pick_list_reference_item/pick_list_reference_item.json
delete mode 100644 erpnext/stock/doctype/pick_list_reference_item/pick_list_reference_item.py
diff --git a/erpnext/manufacturing/doctype/work_order/work_order.py b/erpnext/manufacturing/doctype/work_order/work_order.py
index 38e1157abc..efa901b7f9 100644
--- a/erpnext/manufacturing/doctype/work_order/work_order.py
+++ b/erpnext/manufacturing/doctype/work_order/work_order.py
@@ -735,33 +735,22 @@ def create_pick_list(source_name, target_doc=None, for_qty=None):
else:
target.delete()
- doc = get_mapped_doc("Work Order", source_name, {
- "Work Order": {
- "doctype": "Pick List",
- "validation": {
- "docstatus": ["=", 1]
+ doc = get_mapped_doc('Work Order', source_name, {
+ 'Work Order': {
+ 'doctype': 'Pick List',
+ 'validation': {
+ 'docstatus': ['=', 1]
}
},
- "Work Order Item": {
- "doctype": "Pick List Reference Item",
- "postprocess": update_item_quantity,
- "condition": lambda doc: abs(doc.transferred_qty) < abs(doc.required_qty)
+ 'Work Order Item': {
+ 'doctype': 'Pick List Item',
+ 'postprocess': update_item_quantity,
+ 'condition': lambda doc: abs(doc.transferred_qty) < abs(doc.required_qty)
},
}, target_doc)
- # # aggregate qty for same item
- # item_map = frappe._dict()
- # for item in doc.items:
- # item.idx = None
- # if not item_map.get(item.item_code):
- # item_map[item.item_code] = item
- # else:
- # item_map[item.item_code].qty += item.qty
- # item_map[item.item_code].stock_qty += item.stock_qty
-
- # doc.delete_key('items')
- # doc.set('items', item_map.values())
-
doc.for_qty = for_qty
+ doc.set_item_locations()
+
return doc
\ No newline at end of file
diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py
index e6621b1260..c9aaab4b21 100755
--- a/erpnext/selling/doctype/sales_order/sales_order.py
+++ b/erpnext/selling/doctype/sales_order/sales_order.py
@@ -998,24 +998,26 @@ def create_pick_list(source_name, target_doc=None):
target.qty = flt(source.qty) - flt(source.delivered_qty)
target.stock_qty = (flt(source.qty) - flt(source.delivered_qty)) * flt(source.conversion_factor)
- doc = get_mapped_doc("Sales Order", source_name, {
- "Sales Order": {
- "doctype": "Pick List",
- "validation": {
- "docstatus": ["=", 1]
+ doc = get_mapped_doc('Sales Order', source_name, {
+ 'Sales Order': {
+ 'doctype': 'Pick List',
+ 'validation': {
+ 'docstatus': ['=', 1]
}
},
- "Sales Order Item": {
- "doctype": "Pick List Reference Item",
- "field_map": {
- "parent": "sales_order",
- "name": "sales_order_item"
+ 'Sales Order Item': {
+ 'doctype': 'Pick List Item',
+ 'field_map': {
+ 'parent': 'sales_order',
+ 'name': 'sales_order_item'
},
- "postprocess": update_item_quantity,
- "condition": lambda doc: abs(doc.delivered_qty) < abs(doc.qty) and doc.delivered_by_supplier!=1
+ 'postprocess': update_item_quantity,
+ 'condition': lambda doc: abs(doc.delivered_qty) < abs(doc.qty) and doc.delivered_by_supplier!=1
},
}, target_doc)
doc.purpose = 'Delivery against Sales Order'
+ doc.set_item_locations()
+
return doc
diff --git a/erpnext/stock/doctype/material_request/material_request.py b/erpnext/stock/doctype/material_request/material_request.py
index 9cad3f039f..44e890cc50 100644
--- a/erpnext/stock/doctype/material_request/material_request.py
+++ b/erpnext/stock/doctype/material_request/material_request.py
@@ -516,7 +516,7 @@ def create_pick_list(source_name, target_doc=None):
}
},
'Material Request Item': {
- 'doctype': 'Pick List Reference Item',
+ 'doctype': 'Pick List Item',
'field_map': {
'name': 'material_request_item',
'qty': 'stock_qty'
@@ -524,4 +524,6 @@ def create_pick_list(source_name, target_doc=None):
},
}, target_doc)
+ doc.set_item_locations()
+
return doc
\ No newline at end of file
diff --git a/erpnext/stock/doctype/pick_list/pick_list.js b/erpnext/stock/doctype/pick_list/pick_list.js
index 163ff8c2f2..54a2ca9f0b 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.js
+++ b/erpnext/stock/doctype/pick_list/pick_list.js
@@ -30,6 +30,7 @@ frappe.ui.form.on('Pick List', {
}
};
});
+ // frm.set_df_property('get_item_locations', 'hidden', frm.is_dirty());
},
get_item_locations: (frm) => {
frm.call('set_item_locations');
@@ -69,7 +70,6 @@ frappe.ui.form.on('Pick List', {
frappe.msgprint(__('Quantity must not be more than {0}', [max]));
return;
}
- frm.clear_table('items');
frm.clear_table('locations');
erpnext.utils.map_current_doc({
method: 'erpnext.manufacturing.doctype.work_order.work_order.create_pick_list',
@@ -80,20 +80,13 @@ frappe.ui.form.on('Pick List', {
});
},
material_request: (frm) => {
- frm.clear_table('items');
- frm.clear_table('locations');
erpnext.utils.map_current_doc({
method: 'erpnext.stock.doctype.material_request.material_request.create_pick_list',
target: frm,
source_name: frm.doc.material_request
});
},
- parent_warehouse: (frm) => {
- frm.clear_table('locations');
- frm.refresh_field('locations');
- },
purpose: (frm) => {
- frm.clear_table('items');
frm.clear_table('locations');
frm.trigger('add_get_items_button');
},
@@ -140,7 +133,7 @@ frappe.ui.form.on('Pick List', {
}
});
-frappe.ui.form.on('Pick List Reference Item', {
+frappe.ui.form.on('Pick List Item', {
item_code: (frm, cdt, cdn) => {
let row = frappe.get_doc(cdt, cdn);
if (row.item_code) {
diff --git a/erpnext/stock/doctype/pick_list/pick_list.json b/erpnext/stock/doctype/pick_list/pick_list.json
index 5d33378d69..e635db0540 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.json
+++ b/erpnext/stock/doctype/pick_list/pick_list.json
@@ -14,8 +14,6 @@
"for_qty",
"column_break_4",
"parent_warehouse",
- "section_break_4",
- "items",
"get_item_locations",
"section_break_6",
"locations",
@@ -38,10 +36,6 @@
"fieldname": "section_break_6",
"fieldtype": "Section Break"
},
- {
- "fieldname": "section_break_4",
- "fieldtype": "Section Break"
- },
{
"description": "Items under this warehouse will be suggested",
"fieldname": "parent_warehouse",
@@ -64,13 +58,6 @@
"label": "Work Order",
"options": "Work Order"
},
- {
- "fieldname": "items",
- "fieldtype": "Table",
- "label": "Items To Be Picked",
- "options": "Pick List Reference Item",
- "reqd": 1
- },
{
"fieldname": "locations",
"fieldtype": "Table",
@@ -109,7 +96,6 @@
"options": "Material Request"
},
{
- "depends_on": "eval: doc.items.length && (doc.items.length > 1 || doc.items[0].item_code) && doc.docstatus === 0",
"fieldname": "get_item_locations",
"fieldtype": "Button",
"label": "Get Item Locations"
@@ -124,7 +110,7 @@
}
],
"is_submittable": 1,
- "modified": "2019-08-28 12:27:22.743705",
+ "modified": "2019-08-28 12:49:59.800807",
"modified_by": "Administrator",
"module": "Stock",
"name": "Pick List",
@@ -191,7 +177,6 @@
"write": 1
}
],
- "quick_entry": 1,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
diff --git a/erpnext/stock/doctype/pick_list/pick_list.py b/erpnext/stock/doctype/pick_list/pick_list.py
index 11a998518a..0932c5ad06 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.py
+++ b/erpnext/stock/doctype/pick_list/pick_list.py
@@ -17,7 +17,7 @@ from erpnext.selling.doctype.sales_order.sales_order import make_delivery_note a
class PickList(Document):
def set_item_locations(self):
- items = self.items
+ item_locations = self.locations
self.item_location_map = frappe._dict()
from_warehouses = None
@@ -26,7 +26,7 @@ class PickList(Document):
# Reset
self.delete_key('locations')
- for item_doc in items:
+ for item_doc in item_locations:
item_code = item_doc.item_code
if frappe.get_cached_value('Item', item_code, 'has_serial_no'):
locations = get_item_locations_based_on_serial_nos(item_doc)
@@ -37,20 +37,21 @@ class PickList(Document):
self.item_location_map[item_code] = get_available_items(item_code, from_warehouses)
locations = get_items_with_warehouse_and_quantity(item_doc, from_warehouses, self.item_location_map)
+ # hack
+ del item_doc.idx
+ if len(locations) > 1:
+ del item_doc.name
+
for row in locations:
+ stock_qty = row.get('qty', 0) * item_doc.conversion_factor
row.update({
- 'item_code': item_code,
- 'sales_order': item_doc.sales_order,
- 'sales_order_item': item_doc.sales_order_item,
- 'material_request': item_doc.material_request,
- 'material_request_item': item_doc.material_request_item,
- 'uom': item_doc.uom,
- 'stock_uom': item_doc.stock_uom,
- 'conversion_factor': item_doc.conversion_factor,
- 'stock_qty': row.get("qty", 0) * item_doc.conversion_factor,
- 'picked_qty': row.get("qty", 0) * item_doc.conversion_factor
+ 'stock_qty': stock_qty,
+ 'picked_qty': stock_qty
})
- self.append('locations', row)
+
+ location = item_doc
+ location.update(row)
+ self.append('locations', location)
def get_items_with_warehouse_and_quantity(item_doc, from_warehouses, item_location_map):
available_locations = item_location_map.get(item_doc.item_code)
@@ -242,27 +243,6 @@ def create_stock_entry(pick_list):
return stock_entry.as_dict()
-@frappe.whitelist()
-def create_stock_entry_with_material_request_items(pick_list):
- stock_entry = frappe.new_doc('Stock Entry')
- stock_entry.pick_list = pick_list.get('name')
- stock_entry.purpose = pick_list.get('purpose')
- stock_entry.set_stock_entry_type()
-
- doc = get_mapped_doc("Work Order", source_name, {
- "Work Order": {
- "doctype": "Pick List",
- "validation": {
- "docstatus": ["=", 1]
- }
- },
- "Work Order Item": {
- "doctype": "Pick List Reference Item",
- "postprocess": update_item_quantity,
- "condition": lambda doc: abs(doc.transferred_qty) < abs(doc.required_qty)
- },
- }, target_doc)
-
@frappe.whitelist()
def get_pending_work_orders(doctype, txt, searchfield, start, page_length, filters, as_dict):
return frappe.db.sql("""
diff --git a/erpnext/stock/doctype/pick_list_item/pick_list_item.json b/erpnext/stock/doctype/pick_list_item/pick_list_item.json
index 4dc3ae4e3a..552764dc2f 100644
--- a/erpnext/stock/doctype/pick_list_item/pick_list_item.json
+++ b/erpnext/stock/doctype/pick_list_item/pick_list_item.json
@@ -33,8 +33,7 @@
"fieldname": "qty",
"fieldtype": "Float",
"in_list_view": 1,
- "label": "Qty",
- "read_only": 1
+ "label": "Qty"
},
{
"fieldname": "picked_qty",
@@ -100,8 +99,7 @@
"fieldname": "uom",
"fieldtype": "Link",
"label": "UOM",
- "options": "UOM",
- "read_only": 1
+ "options": "UOM"
},
{
"fieldname": "conversion_factor",
@@ -121,8 +119,7 @@
"fieldtype": "Link",
"in_list_view": 1,
"label": "Item",
- "options": "Item",
- "read_only": 1
+ "options": "Item"
},
{
"fieldname": "quantity_section",
@@ -171,7 +168,7 @@
}
],
"istable": 1,
- "modified": "2019-08-28 12:34:06.224534",
+ "modified": "2019-08-28 15:56:14.507776",
"modified_by": "Administrator",
"module": "Stock",
"name": "Pick List Item",
diff --git a/erpnext/stock/doctype/pick_list_reference_item/__init__.py b/erpnext/stock/doctype/pick_list_reference_item/__init__.py
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/erpnext/stock/doctype/pick_list_reference_item/pick_list_reference_item.js b/erpnext/stock/doctype/pick_list_reference_item/pick_list_reference_item.js
deleted file mode 100644
index 875ce23a28..0000000000
--- a/erpnext/stock/doctype/pick_list_reference_item/pick_list_reference_item.js
+++ /dev/null
@@ -1,8 +0,0 @@
-// Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
-// For license information, please see license.txt
-
-frappe.ui.form.on('Pick List Reference Item', {
- // refresh: function(frm) {
-
- // }
-});
diff --git a/erpnext/stock/doctype/pick_list_reference_item/pick_list_reference_item.json b/erpnext/stock/doctype/pick_list_reference_item/pick_list_reference_item.json
deleted file mode 100644
index 861e6969d6..0000000000
--- a/erpnext/stock/doctype/pick_list_reference_item/pick_list_reference_item.json
+++ /dev/null
@@ -1,109 +0,0 @@
-{
- "creation": "2019-07-24 16:11:07.415562",
- "doctype": "DocType",
- "editable_grid": 1,
- "engine": "InnoDB",
- "field_order": [
- "item_code",
- "quantity_section",
- "qty",
- "stock_qty",
- "column_break_5",
- "uom",
- "conversion_factor",
- "stock_uom",
- "reference_section",
- "sales_order",
- "sales_order_item",
- "material_request",
- "material_request_item"
- ],
- "fields": [
- {
- "fieldname": "qty",
- "fieldtype": "Float",
- "in_list_view": 1,
- "label": "Qty"
- },
- {
- "fieldname": "quantity_section",
- "fieldtype": "Section Break",
- "label": "Quantity"
- },
- {
- "fieldname": "stock_qty",
- "fieldtype": "Float",
- "label": "Stock Qty",
- "read_only": 1
- },
- {
- "fieldname": "uom",
- "fieldtype": "Link",
- "label": "UOM",
- "options": "UOM"
- },
- {
- "fieldname": "stock_uom",
- "fieldtype": "Link",
- "label": "Stock UOM",
- "options": "UOM",
- "read_only": 1
- },
- {
- "fieldname": "item_code",
- "fieldtype": "Link",
- "in_list_view": 1,
- "label": "Item",
- "options": "Item"
- },
- {
- "fieldname": "column_break_5",
- "fieldtype": "Column Break"
- },
- {
- "fieldname": "reference_section",
- "fieldtype": "Section Break",
- "label": "Reference"
- },
- {
- "fieldname": "sales_order",
- "fieldtype": "Link",
- "label": "Sales Order",
- "options": "Sales Order",
- "read_only": 1
- },
- {
- "fieldname": "sales_order_item",
- "fieldtype": "Data",
- "label": "Sales Order Item",
- "read_only": 1
- },
- {
- "fieldname": "conversion_factor",
- "fieldtype": "Float",
- "label": "UOM Conversion Factor"
- },
- {
- "fieldname": "material_request",
- "fieldtype": "Link",
- "label": "Material Request",
- "options": "Material Request",
- "read_only": 1
- },
- {
- "fieldname": "material_request_item",
- "fieldtype": "Data",
- "label": "Material Request Item",
- "read_only": 1
- }
- ],
- "istable": 1,
- "modified": "2019-08-27 08:40:21.870638",
- "modified_by": "Administrator",
- "module": "Stock",
- "name": "Pick List Reference Item",
- "owner": "Administrator",
- "permissions": [],
- "sort_field": "modified",
- "sort_order": "DESC"
-}
\ No newline at end of file
diff --git a/erpnext/stock/doctype/pick_list_reference_item/pick_list_reference_item.py b/erpnext/stock/doctype/pick_list_reference_item/pick_list_reference_item.py
deleted file mode 100644
index 74f0563cdf..0000000000
--- a/erpnext/stock/doctype/pick_list_reference_item/pick_list_reference_item.py
+++ /dev/null
@@ -1,10 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
-# For license information, please see license.txt
-
-from __future__ import unicode_literals
-# import frappe
-from frappe.model.document import Document
-
-class PickListReferenceItem(Document):
- pass
From 354d0af44e138b9bb84c36bbbd51448ccce56af3 Mon Sep 17 00:00:00 2001
From: Rohit Waghchaure
Date: Wed, 28 Aug 2019 17:51:31 +0530
Subject: [PATCH 351/484] fix: added purchase invoice in buying module
---
erpnext/config/buying.py | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/erpnext/config/buying.py b/erpnext/config/buying.py
index f5d8da74c5..6f5ab32b63 100644
--- a/erpnext/config/buying.py
+++ b/erpnext/config/buying.py
@@ -14,6 +14,12 @@ def get_data():
"dependencies": ["Item", "Supplier"],
"description": _("Purchase Orders given to Suppliers."),
},
+ {
+ "type": "doctype",
+ "name": "Purchase Invoice",
+ "onboard": 1,
+ "dependencies": ["Item", "Supplier"]
+ },
{
"type": "doctype",
"name": "Material Request",
From 55a2699f4c497ac8c622fb56da078ac58a9ec4c1 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Thu, 29 Aug 2019 09:14:27 +0530
Subject: [PATCH 352/484] fix: Update dashboard of doctypes that are linked
with pick list
---
.../manufacturing/doctype/work_order/work_order_dashboard.py | 2 +-
erpnext/selling/doctype/sales_order/sales_order.js | 1 +
erpnext/selling/doctype/sales_order/sales_order_dashboard.py | 2 +-
erpnext/stock/doctype/material_request/material_request.js | 1 +
.../doctype/material_request/material_request_dashboard.py | 2 +-
5 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/erpnext/manufacturing/doctype/work_order/work_order_dashboard.py b/erpnext/manufacturing/doctype/work_order/work_order_dashboard.py
index 3fe5282582..0d3c30ea6e 100644
--- a/erpnext/manufacturing/doctype/work_order/work_order_dashboard.py
+++ b/erpnext/manufacturing/doctype/work_order/work_order_dashboard.py
@@ -6,7 +6,7 @@ def get_data():
'fieldname': 'work_order',
'transactions': [
{
- 'items': ['Stock Entry', 'Job Card']
+ 'items': ['Pick List', 'Stock Entry', 'Job Card']
}
]
}
\ No newline at end of file
diff --git a/erpnext/selling/doctype/sales_order/sales_order.js b/erpnext/selling/doctype/sales_order/sales_order.js
index 6ffc6162d6..e86caddb87 100644
--- a/erpnext/selling/doctype/sales_order/sales_order.js
+++ b/erpnext/selling/doctype/sales_order/sales_order.js
@@ -7,6 +7,7 @@ frappe.ui.form.on("Sales Order", {
setup: function(frm) {
frm.custom_make_buttons = {
'Delivery Note': 'Delivery',
+ 'Pick List': 'Pick List',
'Sales Invoice': 'Invoice',
'Material Request': 'Material Request',
'Purchase Order': 'Purchase Order',
diff --git a/erpnext/selling/doctype/sales_order/sales_order_dashboard.py b/erpnext/selling/doctype/sales_order/sales_order_dashboard.py
index aab6db2584..4126bc6a70 100644
--- a/erpnext/selling/doctype/sales_order/sales_order_dashboard.py
+++ b/erpnext/selling/doctype/sales_order/sales_order_dashboard.py
@@ -17,7 +17,7 @@ def get_data():
'transactions': [
{
'label': _('Fulfillment'),
- 'items': ['Sales Invoice', 'Delivery Note']
+ 'items': ['Sales Invoice', 'Pick List', 'Delivery Note']
},
{
'label': _('Purchasing'),
diff --git a/erpnext/stock/doctype/material_request/material_request.js b/erpnext/stock/doctype/material_request/material_request.js
index 1027dd5fea..99195c300d 100644
--- a/erpnext/stock/doctype/material_request/material_request.js
+++ b/erpnext/stock/doctype/material_request/material_request.js
@@ -8,6 +8,7 @@ frappe.ui.form.on('Material Request', {
setup: function(frm) {
frm.custom_make_buttons = {
'Stock Entry': 'Issue Material',
+ 'Pick List': 'Pick List',
'Purchase Order': 'Purchase Order',
'Request for Quotation': 'Request for Quotation',
'Supplier Quotation': 'Supplier Quotation',
diff --git a/erpnext/stock/doctype/material_request/material_request_dashboard.py b/erpnext/stock/doctype/material_request/material_request_dashboard.py
index adfab86cc4..cbd64784c6 100644
--- a/erpnext/stock/doctype/material_request/material_request_dashboard.py
+++ b/erpnext/stock/doctype/material_request/material_request_dashboard.py
@@ -8,7 +8,7 @@ def get_data():
'transactions': [
{
'label': _('Related'),
- 'items': ['Request for Quotation', 'Supplier Quotation', 'Purchase Order', "Stock Entry"]
+ 'items': ['Request for Quotation', 'Supplier Quotation', 'Purchase Order', 'Stock Entry', 'Pick List']
},
{
'label': _('Manufacturing'),
From 66f2bc69a637c6795547f595785162453d916be7 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Thu, 29 Aug 2019 09:23:31 +0530
Subject: [PATCH 353/484] fix: Item mapping of stock entry with no reference
---
erpnext/stock/doctype/pick_list/pick_list.py | 27 ++++++++++++++++----
1 file changed, 22 insertions(+), 5 deletions(-)
diff --git a/erpnext/stock/doctype/pick_list/pick_list.py b/erpnext/stock/doctype/pick_list/pick_list.py
index 0932c5ad06..2f276e2f76 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.py
+++ b/erpnext/stock/doctype/pick_list/pick_list.py
@@ -37,10 +37,8 @@ class PickList(Document):
self.item_location_map[item_code] = get_available_items(item_code, from_warehouses)
locations = get_items_with_warehouse_and_quantity(item_doc, from_warehouses, self.item_location_map)
- # hack
- del item_doc.idx
- if len(locations) > 1:
- del item_doc.name
+ item_doc.idx = None
+ item_doc.name = None
for row in locations:
stock_qty = row.get('qty', 0) * item_doc.conversion_factor
@@ -49,7 +47,7 @@ class PickList(Document):
'picked_qty': stock_qty
})
- location = item_doc
+ location = item_doc.as_dict()
location.update(row)
self.append('locations', location)
@@ -236,6 +234,8 @@ def create_stock_entry(pick_list):
stock_entry = update_stock_entry_based_on_work_order(pick_list, stock_entry)
elif pick_list.get('material_request'):
stock_entry = update_stock_entry_based_on_material_request(pick_list, stock_entry)
+ else:
+ stock_entry = update_stock_entry_items_with_no_reference(pick_list, stock_entry)
stock_entry.set_incoming_rate()
stock_entry.set_actual_qty()
@@ -375,4 +375,21 @@ def update_stock_entry_based_on_material_request(pick_list, stock_entry):
stock_entry.append('items', item)
+ return stock_entry
+
+def update_stock_entry_items_with_no_reference(pick_list, stock_entry):
+ for location in pick_list.locations:
+ item = frappe._dict()
+ item.item_code = location.item_code
+ item.s_warehouse = location.warehouse
+ item.qty = location.picked_qty * location.conversion_factor
+ item.transfer_qty = location.picked_qty
+ item.uom = location.uom
+ item.conversion_factor = location.conversion_factor
+ item.stock_uom = location.stock_uom
+ item.material_request = location.material_request
+ item.material_request_item = location.material_request_item
+
+ stock_entry.append('items', item)
+
return stock_entry
\ No newline at end of file
From ed1ec82d2fb53d7ac81e2a1486050aece83419dc Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Thu, 29 Aug 2019 17:23:09 +0530
Subject: [PATCH 354/484] refactor: Item picking logic
- Fix serial number selection
- Get limited item location based on required qty
- Store total item count to properly track available locations
- Pass missing serial no.
---
erpnext/stock/doctype/pick_list/pick_list.py | 205 ++++++++++---------
1 file changed, 113 insertions(+), 92 deletions(-)
diff --git a/erpnext/stock/doctype/pick_list/pick_list.py b/erpnext/stock/doctype/pick_list/pick_list.py
index 2f276e2f76..21b9cc1054 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.py
+++ b/erpnext/stock/doctype/pick_list/pick_list.py
@@ -8,7 +8,7 @@ import json
from six import iteritems
from frappe.model.document import Document
from frappe import _
-from frappe.utils import floor, flt, today
+from frappe.utils import floor, flt, today, cint
from frappe.model.mapper import get_mapped_doc, map_child_doc
from erpnext.stock.get_item_details import get_conversion_factor
from erpnext.selling.doctype.sales_order.sales_order import make_delivery_note as create_delivery_note_from_sales_order
@@ -17,51 +17,69 @@ from erpnext.selling.doctype.sales_order.sales_order import make_delivery_note a
class PickList(Document):
def set_item_locations(self):
- item_locations = self.locations
+ items = self.aggregate_item_qty()
self.item_location_map = frappe._dict()
from_warehouses = None
if self.parent_warehouse:
from_warehouses = frappe.db.get_descendants('Warehouse', self.parent_warehouse)
- # Reset
+ # reset
self.delete_key('locations')
- for item_doc in item_locations:
+ for item_doc in items:
item_code = item_doc.item_code
- if frappe.get_cached_value('Item', item_code, 'has_serial_no'):
- locations = get_item_locations_based_on_serial_nos(item_doc)
- elif frappe.get_cached_value('Item', item_code, 'has_batch_no'):
- locations = get_item_locations_based_on_batch_nos(item_doc)
- else:
- if item_code not in self.item_location_map:
- self.item_location_map[item_code] = get_available_items(item_code, from_warehouses)
- locations = get_items_with_warehouse_and_quantity(item_doc, from_warehouses, self.item_location_map)
+
+ self.item_location_map.setdefault(item_code,
+ get_available_item_locations(item_code, from_warehouses, self.item_count_map.get(item_code)))
+
+ locations = get_items_with_location_and_quantity(item_doc, self.item_location_map)
item_doc.idx = None
item_doc.name = None
for row in locations:
- stock_qty = row.get('qty', 0) * item_doc.conversion_factor
row.update({
- 'stock_qty': stock_qty,
- 'picked_qty': stock_qty
+ 'picked_qty': row.stock_qty
})
location = item_doc.as_dict()
location.update(row)
self.append('locations', location)
-def get_items_with_warehouse_and_quantity(item_doc, from_warehouses, item_location_map):
+ def aggregate_item_qty(self):
+ locations = self.locations
+ self.item_count_map = {}
+ # aggregate qty for same item
+ item_map = frappe._dict()
+ for item in locations:
+ item_code = item.item_code
+ reference = item.sales_order_item or item.material_request_item
+ key = (item_code, item.uom, reference)
+
+ item.idx = None
+ item.name = None
+
+ if item_map.get(key):
+ item_map[key].qty += item.qty
+ item_map[key].stock_qty += item.stock_qty
+ else:
+ item_map[key] = item
+
+ # maintain count of each item (useful to limit get query)
+ self.item_count_map.setdefault(item_code, 0)
+ self.item_count_map[item_code] += item.stock_qty
+
+ return item_map.values()
+
+
+def get_items_with_location_and_quantity(item_doc, item_location_map):
available_locations = item_location_map.get(item_doc.item_code)
locations = []
- skip_warehouse = None
-
- if item_doc.material_request:
- skip_warehouse = frappe.get_value('Material Request Item', item_doc.material_request_item, 'warehouse')
remaining_stock_qty = item_doc.stock_qty
while remaining_stock_qty > 0 and available_locations:
item_location = available_locations.pop(0)
+ item_location = frappe._dict(item_location)
stock_qty = remaining_stock_qty if item_location.qty >= remaining_stock_qty else item_location.qty
qty = stock_qty / (item_doc.conversion_factor or 1)
@@ -72,54 +90,61 @@ def get_items_with_warehouse_and_quantity(item_doc, from_warehouses, item_locati
stock_qty = qty * item_doc.conversion_factor
if not stock_qty: break
- locations.append({
+ serial_nos = None
+ if item_location.serial_no:
+ serial_nos = '\n'.join(item_location.serial_no[0: cint(stock_qty)])
+
+ locations.append(frappe._dict({
'qty': qty,
- 'warehouse': item_location.warehouse
- })
+ 'stock_qty': stock_qty,
+ 'warehouse': item_location.warehouse,
+ 'serial_no': serial_nos,
+ 'batch_no': item_location.batch_no
+ }))
+
remaining_stock_qty -= stock_qty
qty_diff = item_location.qty - stock_qty
# if extra quantity is available push current warehouse to available locations
- if qty_diff:
+ if qty_diff > 0:
item_location.qty = qty_diff
+ if item_location.serial_no:
+ # set remaining serial numbers
+ item_location.serial_no = item_location.serial_no[-qty_diff:]
available_locations = [item_location] + available_locations
- if remaining_stock_qty:
- frappe.msgprint('{0} {1} of {2} is not available.'
- .format(remaining_stock_qty / item_doc.conversion_factor, item_doc.uom, item_doc.item_code))
-
# update available locations for the item
item_location_map[item_doc.item_code] = available_locations
return locations
-def get_available_items(item_code, from_warehouses):
- # gets all items available in different warehouses
+def get_available_item_locations(item_code, from_warehouses, required_qty):
+ if frappe.get_cached_value('Item', item_code, 'has_serial_no'):
+ return get_available_item_locations_for_serialized_item(item_code, from_warehouses, required_qty)
+ elif frappe.get_cached_value('Item', item_code, 'has_batch_no'):
+ return get_available_item_locations_for_batched_item(item_code, from_warehouses, required_qty)
+ else:
+ return get_available_item_locations_for_other_item(item_code, from_warehouses, required_qty)
+
+def get_available_item_locations_for_serialized_item(item_code, from_warehouses, required_qty):
filters = frappe._dict({
'item_code': item_code,
- 'actual_qty': ['>', 0]
+ 'warehouse': ['!=', '']
})
+
if from_warehouses:
filters.warehouse = ['in', from_warehouses]
- available_items = frappe.get_all('Bin',
- fields=['warehouse', 'actual_qty as qty'],
- filters=filters,
- order_by='creation')
-
- return available_items
-
-def get_item_locations_based_on_serial_nos(item_doc):
serial_nos = frappe.get_all('Serial No',
- fields = ['name', 'warehouse'],
- filters = {
- 'item_code': item_doc.item_code,
- 'warehouse': ['!=', '']
- }, limit=item_doc.stock_qty, order_by='purchase_date', as_list=1)
+ fields=['name', 'warehouse'],
+ filters=filters,
+ limit=required_qty,
+ order_by='purchase_date',
+ as_list=1)
- remaining_stock_qty = flt(item_doc.stock_qty) - len(serial_nos)
+ remaining_stock_qty = required_qty - len(serial_nos)
if remaining_stock_qty:
- frappe.msgprint('{0} {1} of {2} is not available.'
- .format(remaining_stock_qty, item_doc.stock_uom, item_doc.item_code))
+ frappe.msgprint('{0} qty of {1} is not available.'
+ .format(remaining_stock_qty, item_code))
warehouse_serial_nos_map = frappe._dict()
for serial_no, warehouse in serial_nos:
@@ -130,12 +155,12 @@ def get_item_locations_based_on_serial_nos(item_doc):
locations.append({
'qty': len(serial_nos),
'warehouse': warehouse,
- 'serial_no': '\n'.join(serial_nos)
+ 'serial_no': serial_nos
})
return locations
-def get_item_locations_based_on_batch_nos(item_doc):
+def get_available_item_locations_for_batched_item(item_code, from_warehouses, required_qty):
batch_locations = frappe.db.sql("""
SELECT
sle.`warehouse`,
@@ -154,30 +179,36 @@ def get_item_locations_based_on_batch_nos(item_doc):
HAVING `qty` > 0
ORDER BY IFNULL(batch.`expiry_date`, '2200-01-01'), batch.`creation`
""", {
- 'item_code': item_doc.item_code,
+ 'item_code': item_code,
'today': today()
}, as_dict=1)
- locations = []
- required_qty = item_doc.stock_qty
+ total_qty_available = sum(location.get('qty') for location in batch_locations)
- for batch_location in batch_locations:
- if batch_location.qty >= required_qty:
- # this batch should fulfill the required items
- batch_location.qty = required_qty
- required_qty = 0
- else:
- required_qty -= batch_location.qty
+ remaining_qty = required_qty - total_qty_available
- locations.append(batch_location)
+ if remaining_qty > 0:
+ frappe.msgprint('No batches found for {} qty of {}.'.format(remaining_qty, item_code))
- if required_qty <= 0:
- break
+ return batch_locations
- if required_qty:
- frappe.msgprint('No batches found for {} qty of {}.'.format(required_qty, item_doc.item_code))
+def get_available_item_locations_for_other_item(item_code, from_warehouses, required_qty):
+ # gets all items available in different warehouses
+ filters = frappe._dict({
+ 'item_code': item_code,
+ 'actual_qty': ['>', 0]
+ })
- return locations
+ if from_warehouses:
+ filters.warehouse = ['in', from_warehouses]
+
+ item_locations = frappe.get_all('Bin',
+ fields=['warehouse', 'actual_qty as qty'],
+ filters=filters,
+ limit=required_qty,
+ order_by='creation')
+
+ return item_locations
@frappe.whitelist()
def create_delivery_note(source_name, target_doc=None):
@@ -342,14 +373,8 @@ def update_stock_entry_based_on_work_order(pick_list, stock_entry):
for location in pick_list.locations:
item = frappe._dict()
- item.item_code = location.item_code
- item.s_warehouse = location.warehouse
+ update_common_item_properties(item, location)
item.t_warehouse = wip_warehouse
- item.qty = location.picked_qty * location.conversion_factor
- item.transfer_qty = location.picked_qty
- item.uom = location.uom
- item.conversion_factor = location.conversion_factor
- item.stock_uom = location.stock_uom
stock_entry.append('items', item)
@@ -362,17 +387,8 @@ def update_stock_entry_based_on_material_request(pick_list, stock_entry):
target_warehouse = frappe.get_value('Material Request Item',
location.material_request_item, 'warehouse')
item = frappe._dict()
- item.item_code = location.item_code
- item.s_warehouse = location.warehouse
+ update_common_item_properties(item, location)
item.t_warehouse = target_warehouse
- item.qty = location.picked_qty * location.conversion_factor
- item.transfer_qty = location.picked_qty
- item.uom = location.uom
- item.conversion_factor = location.conversion_factor
- item.stock_uom = location.stock_uom
- item.material_request = location.material_request
- item.material_request_item = location.material_request_item
-
stock_entry.append('items', item)
return stock_entry
@@ -380,16 +396,21 @@ def update_stock_entry_based_on_material_request(pick_list, stock_entry):
def update_stock_entry_items_with_no_reference(pick_list, stock_entry):
for location in pick_list.locations:
item = frappe._dict()
- item.item_code = location.item_code
- item.s_warehouse = location.warehouse
- item.qty = location.picked_qty * location.conversion_factor
- item.transfer_qty = location.picked_qty
- item.uom = location.uom
- item.conversion_factor = location.conversion_factor
- item.stock_uom = location.stock_uom
- item.material_request = location.material_request
- item.material_request_item = location.material_request_item
+ update_common_item_properties(item, location)
stock_entry.append('items', item)
- return stock_entry
\ No newline at end of file
+ return stock_entry
+
+def update_common_item_properties(item, location):
+ item.item_code = location.item_code
+ item.s_warehouse = location.warehouse
+ item.qty = location.picked_qty * location.conversion_factor
+ item.transfer_qty = location.picked_qty
+ item.uom = location.uom
+ item.conversion_factor = location.conversion_factor
+ item.stock_uom = location.stock_uom
+ item.material_request = location.material_request
+ item.serial_no = location.serial_no
+ item.batch_no = location.batch_no
+ item.material_request_item = location.material_request_item
\ No newline at end of file
From 36b30911a821424a50d86ae45cf7fffa254112b2 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Thu, 29 Aug 2019 18:06:23 +0530
Subject: [PATCH 355/484] feat: customer credit limit
---
.../selling/doctype/customer/customer.json | 1915 ++---------------
.../doctype/customer_credit_limit/__init__.py | 0
.../customer_credit_limit.json | 46 +
.../customer_credit_limit.py | 10 +
4 files changed, 181 insertions(+), 1790 deletions(-)
create mode 100644 erpnext/selling/doctype/customer_credit_limit/__init__.py
create mode 100644 erpnext/selling/doctype/customer_credit_limit/customer_credit_limit.json
create mode 100644 erpnext/selling/doctype/customer_credit_limit/customer_credit_limit.py
diff --git a/erpnext/selling/doctype/customer/customer.json b/erpnext/selling/doctype/customer/customer.json
index 8c30528960..8b5cca9320 100644
--- a/erpnext/selling/doctype/customer/customer.json
+++ b/erpnext/selling/doctype/customer/customer.json
@@ -1,2036 +1,475 @@
{
- "allow_copy": 0,
"allow_events_in_timeline": 1,
- "allow_guest_to_view": 0,
"allow_import": 1,
"allow_rename": 1,
"autoname": "naming_series:",
- "beta": 0,
"creation": "2013-06-11 14:26:44",
- "custom": 0,
"description": "Buyer of Goods and Services.",
- "docstatus": 0,
"doctype": "DocType",
"document_type": "Setup",
- "editable_grid": 0,
"engine": "InnoDB",
+ "field_order": [
+ "basic_info",
+ "naming_series",
+ "salutation",
+ "customer_name",
+ "gender",
+ "customer_type",
+ "default_bank_account",
+ "lead_name",
+ "image",
+ "column_break0",
+ "account_manager",
+ "customer_group",
+ "territory",
+ "tax_id",
+ "tax_category",
+ "disabled",
+ "is_internal_customer",
+ "represents_company",
+ "allowed_to_transact_section",
+ "companies",
+ "currency_and_price_list",
+ "default_currency",
+ "default_price_list",
+ "column_break_14",
+ "language",
+ "address_contacts",
+ "address_html",
+ "website",
+ "column_break1",
+ "contact_html",
+ "primary_address_and_contact_detail",
+ "customer_primary_contact",
+ "mobile_no",
+ "email_id",
+ "column_break_26",
+ "customer_primary_address",
+ "primary_address",
+ "default_receivable_accounts",
+ "accounts",
+ "credit_limit_section",
+ "payment_terms",
+ "credit_limit",
+ "more_info",
+ "customer_details",
+ "column_break_45",
+ "market_segment",
+ "industry",
+ "is_frozen",
+ "column_break_38",
+ "loyalty_program",
+ "loyalty_program_tier",
+ "sales_team_section_break",
+ "default_sales_partner",
+ "default_commission_rate",
+ "sales_team_section",
+ "sales_team",
+ "customer_pos_id"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "basic_info",
"fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Name and Type",
- "length": 0,
- "no_copy": 0,
"oldfieldtype": "Section Break",
- "options": "fa fa-user",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
+ "options": "fa fa-user"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "",
- "fetch_if_empty": 0,
"fieldname": "naming_series",
"fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Series",
- "length": 0,
"no_copy": 1,
"options": "CUST-.YYYY.-",
- "permlevel": 0,
- "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": 1,
- "translatable": 0,
- "unique": 0
+ "set_only_once": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"depends_on": "eval:doc.customer_type!='Company'",
- "fetch_if_empty": 0,
"fieldname": "salutation",
"fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Salutation",
- "length": 0,
- "no_copy": 0,
- "options": "Salutation",
- "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,
- "translatable": 0,
- "unique": 0
+ "options": "Salutation"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
"bold": 1,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "customer_name",
"fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
"in_global_search": 1,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Full Name",
- "length": 0,
"no_copy": 1,
"oldfieldname": "customer_name",
"oldfieldtype": "Data",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
"reqd": 1,
- "search_index": 1,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "search_index": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"depends_on": "eval:doc.customer_type != 'Company'",
- "fetch_if_empty": 0,
"fieldname": "gender",
"fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Gender",
- "length": 0,
- "no_copy": 0,
- "options": "Gender",
- "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,
- "translatable": 0,
- "unique": 0
+ "options": "Gender"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"default": "Company",
- "fetch_if_empty": 0,
"fieldname": "customer_type",
"fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Type",
- "length": 0,
- "no_copy": 0,
"oldfieldname": "customer_type",
"oldfieldtype": "Select",
"options": "Company\nIndividual",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "reqd": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "default_bank_account",
"fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Default Bank Account",
- "length": 0,
- "no_copy": 0,
- "options": "Bank Account",
- "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,
- "translatable": 0,
- "unique": 0
+ "options": "Bank Account"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "lead_name",
"fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "From Lead",
- "length": 0,
"no_copy": 1,
"oldfieldname": "lead_name",
"oldfieldtype": "Link",
"options": "Lead",
- "permlevel": 0,
"print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 1,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "report_hide": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "image",
"fieldtype": "Attach Image",
"hidden": 1,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Image",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
+ "print_hide": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "column_break0",
"fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0,
"width": "50%"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "account_manager",
"fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Account Manager",
- "length": 0,
- "no_copy": 0,
- "options": "User",
- "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,
- "translatable": 0,
- "unique": 0
+ "options": "User"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "",
- "fetch_if_empty": 0,
"fieldname": "customer_group",
"fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 1,
"label": "Customer Group",
- "length": 0,
- "no_copy": 0,
"oldfieldname": "customer_group",
"oldfieldtype": "Link",
"options": "Customer Group",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
"reqd": 1,
- "search_index": 1,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "search_index": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "",
- "fetch_if_empty": 0,
"fieldname": "territory",
"fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 1,
"label": "Territory",
- "length": 0,
- "no_copy": 0,
"oldfieldname": "territory",
"oldfieldtype": "Link",
"options": "Territory",
- "permlevel": 0,
"print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "reqd": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "tax_id",
"fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Tax ID",
- "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,
- "translatable": 0,
- "unique": 0
+ "label": "Tax ID"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "tax_category",
"fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Tax Category",
- "length": 0,
- "no_copy": 0,
- "options": "Tax Category",
- "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,
- "translatable": 0,
- "unique": 0
+ "options": "Tax Category"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"default": "0",
- "fetch_if_empty": 0,
"fieldname": "disabled",
"fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Disabled",
- "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,
- "translatable": 0,
- "unique": 0
+ "label": "Disabled"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"default": "0",
- "fetch_if_empty": 0,
"fieldname": "is_internal_customer",
"fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Is Internal Customer",
- "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,
- "translatable": 0,
- "unique": 0
+ "label": "Is Internal Customer"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"depends_on": "is_internal_customer",
- "fetch_if_empty": 0,
"fieldname": "represents_company",
"fieldtype": "Link",
- "hidden": 0,
"ignore_user_permissions": 1,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Represents Company",
- "length": 0,
- "no_copy": 0,
"options": "Company",
- "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,
- "translatable": 0,
"unique": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"depends_on": "represents_company",
- "fetch_if_empty": 0,
"fieldname": "allowed_to_transact_section",
"fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Allowed To Transact With",
- "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,
- "translatable": 0,
- "unique": 0
+ "label": "Allowed To Transact With"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"depends_on": "represents_company",
- "fetch_if_empty": 0,
"fieldname": "companies",
"fieldtype": "Table",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Allowed To Transact With",
- "length": 0,
- "no_copy": 0,
- "options": "Allowed To Transact With",
- "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,
- "translatable": 0,
- "unique": 0
+ "options": "Allowed To Transact With"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
"collapsible": 1,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "currency_and_price_list",
"fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Currency and Price List",
- "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,
- "translatable": 0,
- "unique": 0
+ "label": "Currency and Price List"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "default_currency",
"fieldtype": "Link",
- "hidden": 0,
"ignore_user_permissions": 1,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Billing Currency",
- "length": 0,
"no_copy": 1,
- "options": "Currency",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
+ "options": "Currency"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "default_price_list",
"fieldtype": "Link",
- "hidden": 0,
"ignore_user_permissions": 1,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Default Price List",
- "length": 0,
- "no_copy": 0,
- "options": "Price List",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
+ "options": "Price List"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "column_break_14",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 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,
- "translatable": 0,
- "unique": 0
+ "fieldtype": "Column Break"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "language",
"fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Print Language",
- "length": 0,
- "no_copy": 0,
- "options": "Language",
- "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,
- "translatable": 0,
- "unique": 0
+ "options": "Language"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"depends_on": "eval:!doc.__islocal",
- "fetch_if_empty": 0,
"fieldname": "address_contacts",
"fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Address and Contact",
- "length": 0,
- "no_copy": 0,
- "options": "fa fa-map-marker",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
+ "options": "fa fa-map-marker"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "address_html",
"fieldtype": "HTML",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Address HTML",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "read_only": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "website",
"fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Website",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
+ "label": "Website"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "column_break1",
"fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0,
"width": "50%"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "contact_html",
"fieldtype": "HTML",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Contact HTML",
- "length": 0,
- "no_copy": 0,
"oldfieldtype": "HTML",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "read_only": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"description": "Select, to make the customer searchable with these fields",
- "fetch_if_empty": 0,
"fieldname": "primary_address_and_contact_detail",
"fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Primary Address and Contact Detail",
- "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,
- "translatable": 0,
- "unique": 0
+ "label": "Primary Address and Contact Detail"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"description": "Reselect, if the chosen contact is edited after save",
- "fetch_if_empty": 0,
"fieldname": "customer_primary_contact",
"fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Customer Primary Contact",
- "length": 0,
- "no_copy": 0,
- "options": "Contact",
- "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,
- "translatable": 0,
- "unique": 0
+ "options": "Contact"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fetch_from": "customer_primary_contact.mobile_no",
- "fetch_if_empty": 0,
"fieldname": "mobile_no",
"fieldtype": "Read Only",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Mobile No",
- "length": 0,
- "no_copy": 0,
- "options": "",
- "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,
- "translatable": 0,
- "unique": 0
+ "label": "Mobile No"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fetch_from": "customer_primary_contact.email_id",
- "fetch_if_empty": 0,
"fieldname": "email_id",
"fieldtype": "Read Only",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Email Id",
- "length": 0,
- "no_copy": 0,
- "options": "",
- "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,
- "translatable": 0,
- "unique": 0
+ "label": "Email Id"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "column_break_26",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 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,
- "translatable": 0,
- "unique": 0
+ "fieldtype": "Column Break"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"description": "Reselect, if the chosen address is edited after save",
- "fetch_if_empty": 0,
"fieldname": "customer_primary_address",
"fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Customer Primary Address",
- "length": 0,
- "no_copy": 0,
- "options": "Address",
- "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,
- "translatable": 0,
- "unique": 0
+ "options": "Address"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "",
- "fetch_if_empty": 0,
"fieldname": "primary_address",
"fieldtype": "Read Only",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Primary Address",
- "length": 0,
- "no_copy": 0,
- "options": "",
- "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,
- "translatable": 0,
- "unique": 0
+ "label": "Primary Address"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
"collapsible": 1,
- "collapsible_depends_on": "",
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "default_receivable_accounts",
"fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Accounting",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
+ "label": "Accounting"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
"description": "Mention if non-standard receivable account",
- "fetch_if_empty": 0,
"fieldname": "accounts",
"fieldtype": "Table",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Accounts",
- "length": 0,
- "no_copy": 0,
- "options": "Party Account",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
+ "options": "Party Account"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
"collapsible": 1,
- "collapsible_depends_on": "",
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "credit_limit_section",
"fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Credit Limit and Payment Terms",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0,
- "width": ""
+ "label": "Credit Limit and Payment Terms"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "credit_limit",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Credit Limit",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "credit_limit",
- "oldfieldtype": "Currency",
- "options": "",
- "permlevel": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"default": "0",
- "fetch_if_empty": 0,
- "fieldname": "bypass_credit_limit_check_at_sales_order",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Bypass credit limit check at Sales Order",
- "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,
- "translatable": 0,
- "unique": 0
+ "fieldname": "credit_limit",
+ "fieldtype": "Table",
+ "label": "Credit Limit",
+ "options": "Customer Credit Limit"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "column_break_34",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
- "fetch_if_empty": 0,
"fieldname": "payment_terms",
"fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Default Payment Terms Template",
- "length": 0,
- "no_copy": 0,
- "options": "Payment Terms Template",
- "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,
- "translatable": 0,
- "unique": 0
+ "options": "Payment Terms Template"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
"collapsible": 1,
"collapsible_depends_on": "customer_details",
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "more_info",
"fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "More Information",
- "length": 0,
- "no_copy": 0,
"oldfieldtype": "Section Break",
- "options": "fa fa-file-text",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
+ "options": "fa fa-file-text"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"description": "Additional information regarding the customer.",
- "fetch_if_empty": 0,
"fieldname": "customer_details",
"fieldtype": "Text",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Customer Details",
- "length": 0,
- "no_copy": 0,
"oldfieldname": "customer_details",
- "oldfieldtype": "Code",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
+ "oldfieldtype": "Code"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "column_break_45",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 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,
- "translatable": 0,
- "unique": 0
+ "fieldtype": "Column Break"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "market_segment",
"fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Market Segment",
- "length": 0,
- "no_copy": 0,
- "options": "Market Segment",
- "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,
- "translatable": 0,
- "unique": 0
+ "options": "Market Segment"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "industry",
"fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Industry",
- "length": 0,
- "no_copy": 0,
- "options": "Industry Type",
- "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,
- "translatable": 0,
- "unique": 0
+ "options": "Industry Type"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
+ "default": "0",
"fieldname": "is_frozen",
"fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Is Frozen",
- "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,
- "translatable": 0,
- "unique": 0
+ "label": "Is Frozen"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
"collapsible": 1,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "column_break_38",
"fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Loyalty Points",
- "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,
- "translatable": 0,
- "unique": 0
+ "label": "Loyalty Points"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "loyalty_program",
"fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Loyalty Program",
- "length": 0,
"no_copy": 1,
- "options": "Loyalty Program",
- "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,
- "translatable": 0,
- "unique": 0
+ "options": "Loyalty Program"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "loyalty_program_tier",
"fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Loyalty Program Tier",
- "length": 0,
"no_copy": 1,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "read_only": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
"collapsible": 1,
"collapsible_depends_on": "default_sales_partner",
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "sales_team_section_break",
"fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Sales Partner and Commission",
- "length": 0,
- "no_copy": 0,
"oldfieldtype": "Section Break",
- "options": "fa fa-group",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
+ "options": "fa fa-group"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "default_sales_partner",
"fieldtype": "Link",
- "hidden": 0,
"ignore_user_permissions": 1,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Sales Partner",
- "length": 0,
- "no_copy": 0,
"oldfieldname": "default_sales_partner",
"oldfieldtype": "Link",
- "options": "Sales Partner",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
+ "options": "Sales Partner"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "default_commission_rate",
"fieldtype": "Float",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Commission Rate",
- "length": 0,
- "no_copy": 0,
"oldfieldname": "default_commission_rate",
- "oldfieldtype": "Currency",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
+ "oldfieldtype": "Currency"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
"collapsible": 1,
"collapsible_depends_on": "sales_team",
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "sales_team_section",
"fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Sales Team",
- "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,
- "translatable": 0,
- "unique": 0
+ "label": "Sales Team"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "sales_team",
"fieldtype": "Table",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Sales Team Details",
- "length": 0,
- "no_copy": 0,
"oldfieldname": "sales_team",
"oldfieldtype": "Table",
- "options": "Sales Team",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
+ "options": "Sales Team"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "customer_pos_id",
"fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Customer POS id",
- "length": 0,
"no_copy": 1,
- "permlevel": 0,
- "precision": "",
"print_hide": 1,
- "print_hide_if_no_value": 0,
"read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 1,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "report_hide": 1
}
],
- "has_web_view": 0,
- "hide_toolbar": 0,
"icon": "fa fa-user",
"idx": 363,
"image_field": "image",
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "menu_index": 0,
- "modified": "2019-04-12 08:45:39.357491",
+ "modified": "2019-08-28 17:38:09.709688",
"modified_by": "Administrator",
"module": "Selling",
"name": "Customer",
@@ -2038,184 +477,80 @@
"owner": "Administrator",
"permissions": [
{
- "amend": 0,
- "cancel": 0,
"create": 1,
- "delete": 0,
"email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Sales User",
- "set_user_permissions": 0,
"share": 1,
- "submit": 0,
"write": 1
},
{
- "amend": 0,
- "cancel": 0,
- "create": 0,
- "delete": 0,
- "email": 0,
- "export": 0,
- "if_owner": 0,
- "import": 0,
"permlevel": 1,
- "print": 0,
"read": 1,
- "report": 0,
- "role": "Sales User",
- "set_user_permissions": 0,
- "share": 0,
- "submit": 0,
- "write": 0
+ "role": "Sales User"
},
{
- "amend": 0,
- "cancel": 0,
- "create": 0,
- "delete": 0,
"email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
- "role": "Sales Manager",
- "set_user_permissions": 0,
- "share": 0,
- "submit": 0,
- "write": 0
+ "role": "Sales Manager"
},
{
- "amend": 0,
- "cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
- "if_owner": 0,
"import": 1,
- "permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Sales Master Manager",
"set_user_permissions": 1,
"share": 1,
- "submit": 0,
"write": 1
},
{
- "amend": 0,
- "cancel": 0,
- "create": 0,
- "delete": 0,
- "email": 0,
- "export": 0,
- "if_owner": 0,
- "import": 0,
"permlevel": 1,
- "print": 0,
"read": 1,
- "report": 0,
"role": "Sales Master Manager",
- "set_user_permissions": 0,
- "share": 0,
- "submit": 0,
"write": 1
},
{
- "amend": 0,
- "cancel": 0,
- "create": 0,
- "delete": 0,
"email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
- "role": "Stock User",
- "set_user_permissions": 0,
- "share": 0,
- "submit": 0,
- "write": 0
+ "role": "Stock User"
},
{
- "amend": 0,
- "cancel": 0,
- "create": 0,
- "delete": 0,
"email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
- "role": "Stock Manager",
- "set_user_permissions": 0,
- "share": 0,
- "submit": 0,
- "write": 0
+ "role": "Stock Manager"
},
{
- "amend": 0,
- "cancel": 0,
- "create": 0,
- "delete": 0,
"email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
- "role": "Accounts User",
- "set_user_permissions": 0,
- "share": 0,
- "submit": 0,
- "write": 0
+ "role": "Accounts User"
},
{
- "amend": 0,
- "cancel": 0,
- "create": 0,
- "delete": 0,
"email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
- "role": "Accounts Manager",
- "set_user_permissions": 0,
- "share": 0,
- "submit": 0,
- "write": 0
+ "role": "Accounts Manager"
}
],
"quick_entry": 1,
- "read_only": 0,
"search_fields": "customer_name,customer_group,territory, mobile_no,primary_address",
"show_name_in_global_search": 1,
"sort_order": "ASC",
"title_field": "customer_name",
- "track_changes": 1,
- "track_seen": 0,
- "track_views": 0
+ "track_changes": 1
}
\ No newline at end of file
diff --git a/erpnext/selling/doctype/customer_credit_limit/__init__.py b/erpnext/selling/doctype/customer_credit_limit/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/selling/doctype/customer_credit_limit/customer_credit_limit.json b/erpnext/selling/doctype/customer_credit_limit/customer_credit_limit.json
new file mode 100644
index 0000000000..bf99a58cb7
--- /dev/null
+++ b/erpnext/selling/doctype/customer_credit_limit/customer_credit_limit.json
@@ -0,0 +1,46 @@
+{
+ "creation": "2019-08-28 17:29:42.115592",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "credit_limit",
+ "bypass_credit_limit_check",
+ "column_break_2",
+ "company"
+ ],
+ "fields": [
+ {
+ "fieldname": "credit_limit",
+ "fieldtype": "Currency",
+ "label": "Credit Limit"
+ },
+ {
+ "fieldname": "column_break_2",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "label": "Company",
+ "options": "Company"
+ },
+ {
+ "default": "0",
+ "fieldname": "bypass_credit_limit_check",
+ "fieldtype": "Check",
+ "label": "Bypass credit limit_check"
+ }
+ ],
+ "istable": 1,
+ "modified": "2019-08-28 18:19:26.905239",
+ "modified_by": "Administrator",
+ "module": "Selling",
+ "name": "Customer Credit Limit",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/selling/doctype/customer_credit_limit/customer_credit_limit.py b/erpnext/selling/doctype/customer_credit_limit/customer_credit_limit.py
new file mode 100644
index 0000000000..60a4a9a5d2
--- /dev/null
+++ b/erpnext/selling/doctype/customer_credit_limit/customer_credit_limit.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+# import frappe
+from frappe.model.document import Document
+
+class CustomerCreditLimit(Document):
+ pass
From 3e11338ed55898ec4f7728a03fb1d6f1ff5e258b Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Thu, 29 Aug 2019 19:46:49 +0530
Subject: [PATCH 356/484] fix: Validate count of serial numbers
---
erpnext/stock/doctype/pick_list/pick_list.py | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/erpnext/stock/doctype/pick_list/pick_list.py b/erpnext/stock/doctype/pick_list/pick_list.py
index 21b9cc1054..efe6da8e15 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.py
+++ b/erpnext/stock/doctype/pick_list/pick_list.py
@@ -16,6 +16,15 @@ from erpnext.selling.doctype.sales_order.sales_order import make_delivery_note a
# TODO: Prioritize SO or WO group warehouse
class PickList(Document):
+ def before_submit(self):
+ for item in self.locations:
+ if not frappe.get_cached_value('Item', item.item_code, 'has_serial_no'):
+ continue
+ if len(item.serial_no.split('\n')) == item.picked_qty:
+ continue
+ frappe.throw(_('For item {0} at row {1}, count of serial numbers does not match with the picked quantity')
+ .format(frappe.bold(item.item_code), frappe.bold(item.idx)))
+
def set_item_locations(self):
items = self.aggregate_item_qty()
self.item_location_map = frappe._dict()
From 79525327f07aa5c79c07545eb6fcecfcd814c061 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Thu, 29 Aug 2019 19:50:23 +0530
Subject: [PATCH 357/484] feat: bypass credit limit check
---
erpnext/accounts/doctype/sales_invoice/sales_invoice.py | 6 ++++--
erpnext/selling/doctype/sales_order/sales_order.py | 2 +-
erpnext/stock/doctype/delivery_note/delivery_note.py | 6 ++++--
3 files changed, 9 insertions(+), 5 deletions(-)
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index 95c5dd5cd4..4f8d3bdd9a 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -304,8 +304,10 @@ class SalesInvoice(SellingController):
from erpnext.selling.doctype.customer.customer import check_credit_limit
validate_against_credit_limit = False
- bypass_credit_limit_check_at_sales_order = cint(frappe.get_cached_value("Customer", self.customer,
- "bypass_credit_limit_check_at_sales_order"))
+ bypass_credit_limit_check_at_sales_order = frappe.db.get_value("Customer Credit Limit",
+ filters={'parent': self.customer, 'company': self.company},
+ fieldname=["bypass_credit_limit_check"])
+
if bypass_credit_limit_check_at_sales_order:
validate_against_credit_limit = True
diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py
index 4342af5e19..12e7b31a4c 100755
--- a/erpnext/selling/doctype/sales_order/sales_order.py
+++ b/erpnext/selling/doctype/sales_order/sales_order.py
@@ -208,7 +208,7 @@ class SalesOrder(SellingController):
def check_credit_limit(self):
# if bypass credit limit check is set to true (1) at sales order level,
# then we need not to check credit limit and vise versa
- if not cint(frappe.get_cached_value("Customer", self.customer, "bypass_credit_limit_check_at_sales_order")):
+ if not cint(frappe.db.get_value("Customer Credit Limit", {'parent': self.customer, 'company': self.company}, "bypass_credit_limit_check")):
check_credit_limit(self.customer, self.company)
def check_nextdoc_docstatus(self):
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.py b/erpnext/stock/doctype/delivery_note/delivery_note.py
index f79d127984..e29cd1b792 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.py
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.py
@@ -234,8 +234,10 @@ class DeliveryNote(SellingController):
extra_amount = 0
validate_against_credit_limit = False
- bypass_credit_limit_check_at_sales_order = cint(frappe.db.get_value("Customer", self.customer,
- "bypass_credit_limit_check_at_sales_order"))
+ bypass_credit_limit_check_at_sales_order = cint(frappe.db.get_value("Customer Credit Limit",
+ filters={'parent': self.customer, 'company': self.company},
+ fieldname="bypass_credit_limit_check"))
+
if bypass_credit_limit_check_at_sales_order:
validate_against_credit_limit = True
extra_amount = self.base_grand_total
From 5755d2d32f7a17ca7d9df169249d661630e74750 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Thu, 29 Aug 2019 19:51:38 +0530
Subject: [PATCH 358/484] fix: customer credit limit report
---
.../customer_credit_limit.json | 7 ++++---
.../customer_credit_balance.py | 18 ++++++++++++------
2 files changed, 16 insertions(+), 9 deletions(-)
diff --git a/erpnext/selling/doctype/customer_credit_limit/customer_credit_limit.json b/erpnext/selling/doctype/customer_credit_limit/customer_credit_limit.json
index bf99a58cb7..777feea054 100644
--- a/erpnext/selling/doctype/customer_credit_limit/customer_credit_limit.json
+++ b/erpnext/selling/doctype/customer_credit_limit/customer_credit_limit.json
@@ -13,6 +13,7 @@
{
"fieldname": "credit_limit",
"fieldtype": "Currency",
+ "in_list_view": 1,
"label": "Credit Limit"
},
{
@@ -22,6 +23,7 @@
{
"fieldname": "company",
"fieldtype": "Link",
+ "in_list_view": 1,
"label": "Company",
"options": "Company"
},
@@ -33,7 +35,7 @@
}
],
"istable": 1,
- "modified": "2019-08-28 18:19:26.905239",
+ "modified": "2019-08-29 18:27:10.323287",
"modified_by": "Administrator",
"module": "Selling",
"name": "Customer Credit Limit",
@@ -41,6 +43,5 @@
"permissions": [],
"quick_entry": 1,
"sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1
+ "sort_order": "DESC"
}
\ No newline at end of file
diff --git a/erpnext/selling/report/customer_credit_balance/customer_credit_balance.py b/erpnext/selling/report/customer_credit_balance/customer_credit_balance.py
index ee0d72be7b..6b8b8581d2 100644
--- a/erpnext/selling/report/customer_credit_balance/customer_credit_balance.py
+++ b/erpnext/selling/report/customer_credit_balance/customer_credit_balance.py
@@ -29,7 +29,7 @@ def execute(filters=None):
if customer_naming_type == "Naming Series":
row = [d.name, d.customer_name, credit_limit, outstanding_amt, bal,
- d.bypass_credit_limit_check_at_sales_order, d.is_frozen,
+ d.bypass_credit_limit_check, d.is_frozen,
d.disabled]
else:
row = [d.name, credit_limit, outstanding_amt, bal,
@@ -60,9 +60,15 @@ def get_details(filters):
conditions = ""
if filters.get("customer"):
- conditions += " where name = %(customer)s"
-
- return frappe.db.sql("""select name, customer_name,
- bypass_credit_limit_check_at_sales_order, is_frozen, disabled from `tabCustomer` %s
- """ % conditions, filters, as_dict=1)
+ conditions += " AND name = " + filters.get("customer")
+ return frappe.db.sql("""SELECT
+ c.name, c.customer_name,
+ ccl.bypass_credit_limit_check,
+ c.is_frozen, c.disabled
+ FROM `tabCustomer` c, `tabCustomer Credit Limit` ccl
+ WHERE
+ c.name = ccl.parent
+ AND ccl.company = %s
+ {0}
+ """.format(conditions), (filters.get("company")), as_dict=1) #nosec
\ No newline at end of file
From 13c7e183a656cd48e60cb176777b68d684d4b0b9 Mon Sep 17 00:00:00 2001
From: Rohit Waghchaure
Date: Thu, 29 Aug 2019 19:45:19 +0530
Subject: [PATCH 359/484] fix: not able to save sales order
---
erpnext/controllers/selling_controller.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/erpnext/controllers/selling_controller.py b/erpnext/controllers/selling_controller.py
index 52d58dce62..9dbd5be918 100644
--- a/erpnext/controllers/selling_controller.py
+++ b/erpnext/controllers/selling_controller.py
@@ -394,8 +394,8 @@ class SellingController(StockController):
elif self.doctype == "Delivery Note":
e = [d.item_code, d.description, d.warehouse, d.against_sales_order or d.against_sales_invoice, d.batch_no or '']
f = [d.item_code, d.description, d.against_sales_order or d.against_sales_invoice]
- elif self.doctype == "Sales Order":
- e = [d.item_code, d.description, d.warehouse, d.batch_no or '']
+ elif self.doctype in ["Sales Order", "Quotation"]:
+ e = [d.item_code, d.description, d.warehouse, '']
f = [d.item_code, d.description]
if frappe.db.get_value("Item", d.item_code, "is_stock_item") == 1:
From a6ab00162e8694946a9e33fbd8c1820bd817175d Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Thu, 29 Aug 2019 20:17:04 +0530
Subject: [PATCH 360/484] style: Remove commented code
---
erpnext/manufacturing/doctype/work_order/work_order.py | 3 ---
erpnext/stock/doctype/pick_list/pick_list.js | 1 -
2 files changed, 4 deletions(-)
diff --git a/erpnext/manufacturing/doctype/work_order/work_order.py b/erpnext/manufacturing/doctype/work_order/work_order.py
index efa901b7f9..a636b871e2 100644
--- a/erpnext/manufacturing/doctype/work_order/work_order.py
+++ b/erpnext/manufacturing/doctype/work_order/work_order.py
@@ -714,9 +714,6 @@ def create_pick_list(source_name, target_doc=None, for_qty=None):
for_qty = for_qty or json.loads(target_doc).get('for_qty')
max_finished_goods_qty = frappe.db.get_value('Work Order', source_name, 'qty')
def update_item_quantity(source, target, source_parent):
- # qty = source.required_qty - source.transferred_qty
- # target.qty = qty
-
pending_to_issue = flt(source.required_qty) - flt(source.transferred_qty)
desire_to_transfer = flt(source.required_qty) / max_finished_goods_qty * flt(for_qty)
diff --git a/erpnext/stock/doctype/pick_list/pick_list.js b/erpnext/stock/doctype/pick_list/pick_list.js
index 54a2ca9f0b..4b8df0939e 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.js
+++ b/erpnext/stock/doctype/pick_list/pick_list.js
@@ -30,7 +30,6 @@ frappe.ui.form.on('Pick List', {
}
};
});
- // frm.set_df_property('get_item_locations', 'hidden', frm.is_dirty());
},
get_item_locations: (frm) => {
frm.call('set_item_locations');
From c059bc3e368a83022480395eae6c4c4b8228e049 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Thu, 29 Aug 2019 20:51:31 +0530
Subject: [PATCH 361/484] fix: grid view of customer credit limit
---
erpnext/selling/doctype/customer/customer.py | 22 +++++++++++--------
.../customer_credit_limit.json | 11 ++++++----
2 files changed, 20 insertions(+), 13 deletions(-)
diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py
index c946c47c59..5edf06709d 100644
--- a/erpnext/selling/doctype/customer/customer.py
+++ b/erpnext/selling/doctype/customer/customer.py
@@ -167,13 +167,12 @@ class Customer(TransactionBase):
frappe.throw(_("A Customer Group exists with same name please change the Customer name or rename the Customer Group"), frappe.NameError)
def validate_credit_limit_on_change(self):
- if self.get("__islocal") or not self.credit_limit \
- or self.credit_limit == frappe.db.get_value("Customer", self.name, "credit_limit"):
+ if self.get("__islocal") or not self.credit_limit:
return
- for company in frappe.get_all("Company"):
- outstanding_amt = get_customer_outstanding(self.name, company.name)
- if flt(self.credit_limit) < outstanding_amt:
+ for limit in frappe.get_all("Customer Credit Limit", {'parent': self.name}, ["credit_limit", "company"]):
+ outstanding_amt = get_customer_outstanding(self.name, limit.company)
+ if flt(limit.credit_limit) < outstanding_amt:
frappe.throw(_("""New credit limit is less than current outstanding amount for the customer. Credit limit has to be atleast {0}""").format(outstanding_amt))
def on_trash(self):
@@ -322,11 +321,16 @@ def get_credit_limit(customer, company):
credit_limit = None
if customer:
- credit_limit, customer_group = frappe.get_cached_value("Customer",
- customer, ["credit_limit", "customer_group"])
+ credit_record = frappe.db.sql("""SELECT
+ customer_group,
+ credit_limit
+ FROM `tabCustomer`c , `tabCustomer Credit Limit` ccl
+ WHERE
+ c.name = ccl.parent
+ """, as_dict=1)
- if not credit_limit:
- credit_limit = frappe.get_cached_value("Customer Group", customer_group, "credit_limit")
+ if not credit_record.credit_limit:
+ credit_limit = frappe.get_cached_value("Customer Group", credit_record.customer_group, "credit_limit")
if not credit_limit:
credit_limit = frappe.get_cached_value('Company', company, "credit_limit")
diff --git a/erpnext/selling/doctype/customer_credit_limit/customer_credit_limit.json b/erpnext/selling/doctype/customer_credit_limit/customer_credit_limit.json
index 777feea054..e26f798978 100644
--- a/erpnext/selling/doctype/customer_credit_limit/customer_credit_limit.json
+++ b/erpnext/selling/doctype/customer_credit_limit/customer_credit_limit.json
@@ -4,13 +4,14 @@
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
- "credit_limit",
- "bypass_credit_limit_check",
+ "company",
"column_break_2",
- "company"
+ "credit_limit",
+ "bypass_credit_limit_check"
],
"fields": [
{
+ "columns": 4,
"fieldname": "credit_limit",
"fieldtype": "Currency",
"in_list_view": 1,
@@ -21,6 +22,7 @@
"fieldtype": "Column Break"
},
{
+ "columns": 4,
"fieldname": "company",
"fieldtype": "Link",
"in_list_view": 1,
@@ -31,11 +33,12 @@
"default": "0",
"fieldname": "bypass_credit_limit_check",
"fieldtype": "Check",
+ "in_list_view": 1,
"label": "Bypass credit limit_check"
}
],
"istable": 1,
- "modified": "2019-08-29 18:27:10.323287",
+ "modified": "2019-08-29 20:46:36.073953",
"modified_by": "Administrator",
"module": "Selling",
"name": "Customer Credit Limit",
From dcd5be0d07cefc317b35124dd7ea6112645a68d4 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Thu, 29 Aug 2019 20:53:51 +0530
Subject: [PATCH 362/484] patch: move credit limit in customer to child table
---
erpnext/patches.txt | 1 +
...e_credit_limit_to_customer_credit_limit.py | 34 +++++++++++++++++++
2 files changed, 35 insertions(+)
create mode 100644 erpnext/patches/v12_0/move_credit_limit_to_customer_credit_limit.py
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 07b8ee6ab4..2af12698c5 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -632,3 +632,4 @@ execute:frappe.reload_doc('desk', 'doctype','dashboard_chart')
erpnext.patches.v12_0.add_default_dashboards
erpnext.patches.v12_0.remove_bank_remittance_custom_fields
erpnext.patches.v12_0.generate_leave_ledger_entries
+erpnext.patches.v12_0.move_credit_limit_to_customer_credit_limit
\ No newline at end of file
diff --git a/erpnext/patches/v12_0/move_credit_limit_to_customer_credit_limit.py b/erpnext/patches/v12_0/move_credit_limit_to_customer_credit_limit.py
new file mode 100644
index 0000000000..510d79f23d
--- /dev/null
+++ b/erpnext/patches/v12_0/move_credit_limit_to_customer_credit_limit.py
@@ -0,0 +1,34 @@
+# Copyright (c) 2019, Frappe and Contributors
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+import frappe
+
+def execute():
+ ''' Move credit limit and bypass credit limit to the child table of customer credit limit '''
+ frappe.reload_doc("Selling", "doctype", "Customer Credit Limit")
+ frappe.reload_doc("Selling", "doctype", "Customer")
+
+ if frappe.db.a_row_exists("Customer Credit Limit"):
+ return
+
+ move_credit_limit_to_child_table()
+
+def move_credit_limit_to_child_table():
+ ''' maps data from old field to the new field in the child table '''
+
+ credit_limit_data = frappe.db.sql(''' SELECT
+ name, credit_limit,
+ bypass_credit_limit_check_against_sales_order
+ FROM `tabCustomer`''', as_dict=1)
+
+ default_company = frappe.db.get_single_value("Global Defaults", "default_company")
+
+ for customer in credit_limit_data:
+ customer = frappe.get_doc("Customer", customer.name)
+ customer.append("credit_limit", {
+ 'credit_limit': customer.credit_limit,
+ 'bypass_credit_limit_check': customer.bypass_credit_limit_check_against_sales_order,
+ 'company': default_company
+ })
+ customer.save()
\ No newline at end of file
From 9b42682575fa55fdda507670d70db9b3c4d52da9 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Thu, 29 Aug 2019 21:14:26 +0530
Subject: [PATCH 363/484] fix: Check parent warehouse for batch as well
---
erpnext/stock/doctype/pick_list/pick_list.json | 3 ++-
erpnext/stock/doctype/pick_list/pick_list.py | 7 +++++--
erpnext/stock/doctype/pick_list_item/pick_list_item.json | 4 ++--
3 files changed, 9 insertions(+), 5 deletions(-)
diff --git a/erpnext/stock/doctype/pick_list/pick_list.json b/erpnext/stock/doctype/pick_list/pick_list.json
index e635db0540..8d5ef3d12a 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.json
+++ b/erpnext/stock/doctype/pick_list/pick_list.json
@@ -96,6 +96,7 @@
"options": "Material Request"
},
{
+ "depends_on": "eval:doc.docstatus===0",
"fieldname": "get_item_locations",
"fieldtype": "Button",
"label": "Get Item Locations"
@@ -110,7 +111,7 @@
}
],
"is_submittable": 1,
- "modified": "2019-08-28 12:49:59.800807",
+ "modified": "2019-08-29 21:10:11.572387",
"modified_by": "Administrator",
"module": "Stock",
"name": "Pick List",
diff --git a/erpnext/stock/doctype/pick_list/pick_list.py b/erpnext/stock/doctype/pick_list/pick_list.py
index efe6da8e15..128ad2504d 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.py
+++ b/erpnext/stock/doctype/pick_list/pick_list.py
@@ -170,6 +170,7 @@ def get_available_item_locations_for_serialized_item(item_code, from_warehouses,
return locations
def get_available_item_locations_for_batched_item(item_code, from_warehouses, required_qty):
+ warehouse_condition = 'and warehouse in %(warehouses)s' if from_warehouses else ''
batch_locations = frappe.db.sql("""
SELECT
sle.`warehouse`,
@@ -181,15 +182,17 @@ def get_available_item_locations_for_batched_item(item_code, from_warehouses, re
sle.batch_no = batch.name
and sle.`item_code`=%(item_code)s
and IFNULL(batch.`expiry_date`, '2200-01-01') > %(today)s
+ {warehouse_condition}
GROUP BY
`warehouse`,
`batch_no`,
`item_code`
HAVING `qty` > 0
ORDER BY IFNULL(batch.`expiry_date`, '2200-01-01'), batch.`creation`
- """, {
+ """.format(warehouse_condition=warehouse_condition), { #nosec
'item_code': item_code,
- 'today': today()
+ 'today': today(),
+ 'warehouses': from_warehouses
}, as_dict=1)
total_qty_available = sum(location.get('qty') for location in batch_locations)
diff --git a/erpnext/stock/doctype/pick_list_item/pick_list_item.json b/erpnext/stock/doctype/pick_list_item/pick_list_item.json
index 552764dc2f..9ecdecdaa0 100644
--- a/erpnext/stock/doctype/pick_list_item/pick_list_item.json
+++ b/erpnext/stock/doctype/pick_list_item/pick_list_item.json
@@ -111,7 +111,7 @@
"fieldname": "stock_qty",
"fieldtype": "Float",
"in_list_view": 1,
- "label": "Qty (Stock UOM)",
+ "label": "Stock Qty",
"read_only": 1
},
{
@@ -168,7 +168,7 @@
}
],
"istable": 1,
- "modified": "2019-08-28 15:56:14.507776",
+ "modified": "2019-08-29 17:17:17.668199",
"modified_by": "Administrator",
"module": "Stock",
"name": "Pick List Item",
From 9641edc5626e63bda8be72ef6eb2a70a495c02a1 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Thu, 29 Aug 2019 22:23:13 +0530
Subject: [PATCH 364/484] fix: Set item locations before save
---
erpnext/stock/doctype/pick_list/pick_list.py | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/erpnext/stock/doctype/pick_list/pick_list.py b/erpnext/stock/doctype/pick_list/pick_list.py
index 128ad2504d..06bb247d4e 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.py
+++ b/erpnext/stock/doctype/pick_list/pick_list.py
@@ -16,6 +16,9 @@ from erpnext.selling.doctype.sales_order.sales_order import make_delivery_note a
# TODO: Prioritize SO or WO group warehouse
class PickList(Document):
+ def before_save(self):
+ self.set_item_locations()
+
def before_submit(self):
for item in self.locations:
if not frappe.get_cached_value('Item', item.item_code, 'has_serial_no'):
@@ -56,7 +59,7 @@ class PickList(Document):
self.append('locations', location)
def aggregate_item_qty(self):
- locations = self.locations
+ locations = self.get('locations')
self.item_count_map = {}
# aggregate qty for same item
item_map = frappe._dict()
From 88885184dc94d2429a0ab8974b0edc910096c657 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Fri, 30 Aug 2019 09:30:18 +0530
Subject: [PATCH 365/484] fix: Show separate button for pick list creation in
work order
---
.../doctype/work_order/work_order.js | 150 ++++++++++--------
1 file changed, 84 insertions(+), 66 deletions(-)
diff --git a/erpnext/manufacturing/doctype/work_order/work_order.js b/erpnext/manufacturing/doctype/work_order/work_order.js
index ce66c8fd15..ce7b4f9425 100644
--- a/erpnext/manufacturing/doctype/work_order/work_order.js
+++ b/erpnext/manufacturing/doctype/work_order/work_order.js
@@ -4,16 +4,17 @@
frappe.ui.form.on("Work Order", {
setup: function(frm) {
frm.custom_make_buttons = {
- 'Stock Entry': 'Make Stock Entry',
- }
+ 'Stock Entry': 'Start',
+ 'Pick List': 'Create Pick List',
+ };
// Set query for warehouses
- frm.set_query("wip_warehouse", function(doc) {
+ frm.set_query("wip_warehouse", function() {
return {
filters: {
'company': frm.doc.company,
}
- }
+ };
});
frm.set_query("source_warehouse", function() {
@@ -21,7 +22,7 @@ frappe.ui.form.on("Work Order", {
filters: {
'company': frm.doc.company,
}
- }
+ };
});
frm.set_query("source_warehouse", "required_items", function() {
@@ -29,7 +30,7 @@ frappe.ui.form.on("Work Order", {
filters: {
'company': frm.doc.company,
}
- }
+ };
});
frm.set_query("sales_order", function() {
@@ -37,7 +38,7 @@ frappe.ui.form.on("Work Order", {
filters: {
"status": ["not in", ["Closed", "On Hold"]]
}
- }
+ };
});
frm.set_query("fg_warehouse", function() {
@@ -46,7 +47,7 @@ frappe.ui.form.on("Work Order", {
'company': frm.doc.company,
'is_group': 0
}
- }
+ };
});
frm.set_query("scrap_warehouse", function() {
@@ -55,17 +56,19 @@ frappe.ui.form.on("Work Order", {
'company': frm.doc.company,
'is_group': 0
}
- }
+ };
});
// Set query for BOM
frm.set_query("bom_no", function() {
if (frm.doc.production_item) {
- return{
+ return {
query: "erpnext.controllers.queries.bom",
filters: {item: cstr(frm.doc.production_item)}
- }
- } else msgprint(__("Please enter Production Item first"));
+ };
+ } else {
+ frappe.msgprint(__("Please enter Production Item first"));
+ }
});
// Set query for FG Item
@@ -76,7 +79,7 @@ frappe.ui.form.on("Work Order", {
['is_stock_item', '=',1],
['default_bom', '!=', '']
]
- }
+ };
});
// Set query for FG Item
@@ -85,12 +88,12 @@ frappe.ui.form.on("Work Order", {
filters:[
['Project', 'status', 'not in', 'Completed, Cancelled']
]
- }
+ };
});
// formatter for work order operation
frm.set_indicator_formatter('operation',
- function(doc) { return (frm.doc.qty==doc.completed_qty) ? "green" : "orange" });
+ function(doc) { return (frm.doc.qty==doc.completed_qty) ? "green" : "orange"; });
},
onload: function(frm) {
@@ -133,7 +136,7 @@ frappe.ui.form.on("Work Order", {
if(not_completed && not_completed.length) {
frm.add_custom_button(__('Create Job Card'), () => {
- frm.trigger("make_job_card")
+ frm.trigger("make_job_card");
}).addClass('btn-primary');
}
}
@@ -151,7 +154,7 @@ frappe.ui.form.on("Work Order", {
condition: (d) => {
if (d.allow_alternative_item) {return true;}
}
- })
+ });
});
}
}
@@ -285,13 +288,13 @@ frappe.ui.form.on("Work Order", {
if(!frm.doc.skip_transfer){
var pending_complete = frm.doc.material_transferred_for_manufacturing - frm.doc.produced_qty;
if(pending_complete) {
- var title = __('{0} items in progress', [pending_complete]);
var width = ((pending_complete / frm.doc.qty * 100) - added_min);
+ title = __('{0} items in progress', [pending_complete]);
bars.push({
'title': title,
'width': (width > 100 ? "99.5" : width) + '%',
'progress_class': 'progress-bar-warning'
- })
+ });
message = message + '. ' + title;
}
}
@@ -377,7 +380,7 @@ frappe.ui.form.on("Work Order", {
filters: [
["Sales Order","name", "in", r.message]
]
- }
+ };
});
}
});
@@ -401,10 +404,10 @@ frappe.ui.form.on("Work Order Item", {
frappe.model.set_value(row.doctype, row.name,
"available_qty_at_source_warehouse", r.message);
}
- })
+ });
}
}
-})
+});
frappe.ui.form.on("Work Order Operation", {
workstation: function(frm, cdt, cdn) {
@@ -421,7 +424,7 @@ frappe.ui.form.on("Work Order Operation", {
erpnext.work_order.calculate_cost(frm.doc);
erpnext.work_order.calculate_total_cost(frm);
}
- })
+ });
}
},
time_in_mins: function(frm, cdt, cdn) {
@@ -447,10 +450,13 @@ erpnext.work_order = {
const show_start_btn = (frm.doc.skip_transfer
|| frm.doc.transfer_material_against == 'Job Card') ? 0 : 1;
- if (show_start_btn){
+ if (show_start_btn) {
if ((flt(doc.material_transferred_for_manufacturing) < flt(doc.qty))
&& frm.doc.status != 'Stopped') {
frm.has_start_btn = true;
+ frm.add_custom_button(__('Create Pick List'), function() {
+ erpnext.work_order.create_pick_list(frm);
+ });
var start_btn = frm.add_custom_button(__('Start'), function() {
erpnext.work_order.make_se(frm, 'Material Transfer for Manufacture');
});
@@ -519,8 +525,8 @@ erpnext.work_order = {
calculate_total_cost: function(frm) {
var variable_cost = frm.doc.actual_operating_cost ?
- flt(frm.doc.actual_operating_cost) : flt(frm.doc.planned_operating_cost)
- frm.set_value("total_operating_cost", (flt(frm.doc.additional_operating_cost) + variable_cost))
+ flt(frm.doc.actual_operating_cost) : flt(frm.doc.planned_operating_cost);
+ frm.set_value("total_operating_cost", (flt(frm.doc.additional_operating_cost) + variable_cost));
},
set_default_warehouse: function(frm) {
@@ -528,60 +534,72 @@ erpnext.work_order = {
frappe.call({
method: "erpnext.manufacturing.doctype.work_order.work_order.get_default_warehouse",
callback: function(r) {
- if(!r.exe) {
+ if (!r.exe) {
frm.set_value("wip_warehouse", r.message.wip_warehouse);
- frm.set_value("fg_warehouse", r.message.fg_warehouse)
+ frm.set_value("fg_warehouse", r.message.fg_warehouse);
}
}
});
}
},
- make_se: function(frm, purpose) {
- if(!frm.doc.skip_transfer){
- var max = (purpose === "Manufacture") ?
- flt(frm.doc.material_transferred_for_manufacturing) - flt(frm.doc.produced_qty) :
- flt(frm.doc.qty) - flt(frm.doc.material_transferred_for_manufacturing);
+ get_max_transferable_qty: (frm, purpose) => {
+ let max = 0;
+ if (frm.doc.skip_transfer) return max;
+ if (purpose === 'Manufacture') {
+ max = flt(frm.doc.material_transferred_for_manufacturing) - flt(frm.doc.produced_qty);
+ } else {
+ max = flt(frm.doc.qty) - flt(frm.doc.material_transferred_for_manufacturing);
}
- max = flt(max, precision('qty'));
+ return flt(max, precision('qty'));
+ },
- frappe.prompt([{
- fieldtype: 'Float',
- label: __('Qty for {0}', [purpose]),
- fieldname: 'qty',
- description: __('Max: {0}',[max]),
- default: max
- }, {
- fieldtype: 'Select',
- label: __('Create'),
- fieldname: 'create',
- default: 'Stock Entry',
- options: 'Stock Entry\nPick List'
- }], function (data) {
- if (data.qty > max) {
- frappe.msgprint(__('Quantity must not be more than {0}', [max]));
- return;
- }
- if (data.create === 'Stock Entry') {
- frappe.xcall('erpnext.manufacturing.doctype.work_order.work_order.make_stock_entry', {
+ show_prompt_for_qty_input: function(frm, purpose) {
+ let max = this.get_max_transferable_qty(frm, purpose);
+ return new Promise((resolve, reject) => {
+ frappe.prompt({
+ fieldtype: 'Float',
+ label: __('Qty for {0}', [purpose]),
+ fieldname: 'qty',
+ description: __('Max: {0}', [max]),
+ default: max
+ }, data => {
+ if (data.qty > max) {
+ frappe.msgprint(__('Quantity must not be more than {0}', [max]));
+ reject();
+ }
+ data.purpose = purpose;
+ resolve(data);
+ }, __('Select Quantity'), __('Create'));
+ });
+ },
+
+ make_se: function(frm, purpose) {
+ this.show_prompt_for_qty_input(frm, purpose)
+ .then(data => {
+ return frappe.xcall('erpnext.manufacturing.doctype.work_order.work_order.make_stock_entry', {
'work_order_id': frm.doc.name,
'purpose': purpose,
'qty': data.qty
- }).then(stock_entry => {
- frappe.model.sync(stock_entry);
- frappe.set_route('Form', stock_entry.doctype, stock_entry.name);
});
- } else {
- frappe.xcall('erpnext.manufacturing.doctype.work_order.work_order.create_pick_list', {
+ }).then(stock_entry => {
+ frappe.model.sync(stock_entry);
+ frappe.set_route('Form', stock_entry.doctype, stock_entry.name);
+ });
+
+ },
+
+ create_pick_list: function(frm, purpose='Material Transfer for Manufacture') {
+ this.show_prompt_for_qty_input(frm, purpose)
+ .then(data => {
+ return frappe.xcall('erpnext.manufacturing.doctype.work_order.work_order.create_pick_list', {
'source_name': frm.doc.name,
'for_qty': data.qty
- }).then(pick_list => {
- frappe.model.sync(pick_list);
- frappe.set_route('Form', pick_list.doctype, pick_list.name);
});
- }
-
- }, __('Select Quantity'), __('Create'));
+ }).then(pick_list => {
+ frappe.model.sync(pick_list);
+ frappe.set_route('Form', pick_list.doctype, pick_list.name);
+ });
},
make_consumption_se: function(frm, backflush_raw_materials_based_on) {
@@ -621,6 +639,6 @@ erpnext.work_order = {
frm.reload_doc();
}
}
- })
+ });
}
-}
+};
From effe53d4ae9a46d4a15f50d34f8aae863bf4dc5d Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Fri, 30 Aug 2019 09:52:08 +0530
Subject: [PATCH 366/484] fix: Set default value for qty
---
erpnext/stock/doctype/pick_list_item/pick_list_item.json | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/erpnext/stock/doctype/pick_list_item/pick_list_item.json b/erpnext/stock/doctype/pick_list_item/pick_list_item.json
index 9ecdecdaa0..c7a35df51f 100644
--- a/erpnext/stock/doctype/pick_list_item/pick_list_item.json
+++ b/erpnext/stock/doctype/pick_list_item/pick_list_item.json
@@ -30,6 +30,7 @@
],
"fields": [
{
+ "default": "1",
"fieldname": "qty",
"fieldtype": "Float",
"in_list_view": 1,
@@ -168,7 +169,7 @@
}
],
"istable": 1,
- "modified": "2019-08-29 17:17:17.668199",
+ "modified": "2019-08-29 21:28:39.539007",
"modified_by": "Administrator",
"module": "Stock",
"name": "Pick List Item",
From 5e84ce55ae954ef4e634129cc5cd9bbe61c13eda Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Fri, 30 Aug 2019 10:01:49 +0530
Subject: [PATCH 367/484] fix: Add is_stock_item filter for item in locations
table
---
erpnext/stock/doctype/pick_list/pick_list.js | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/erpnext/stock/doctype/pick_list/pick_list.js b/erpnext/stock/doctype/pick_list/pick_list.js
index 4b8df0939e..badb3e7574 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.js
+++ b/erpnext/stock/doctype/pick_list/pick_list.js
@@ -30,6 +30,13 @@ frappe.ui.form.on('Pick List', {
}
};
});
+ frm.set_query('item_code', 'locations', () => {
+ return {
+ filters: {
+ is_stock_item: 1
+ }
+ };
+ });
},
get_item_locations: (frm) => {
frm.call('set_item_locations');
From 0df38891a16bd5cdba083253e70c8be2ab4d7d1d Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Fri, 30 Aug 2019 15:59:35 +0530
Subject: [PATCH 368/484] fix: Update pick list print format
---
erpnext/stock/print_format/pick_list/pick_list.json | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/erpnext/stock/print_format/pick_list/pick_list.json b/erpnext/stock/print_format/pick_list/pick_list.json
index 56c819fc0c..0e88d24c5a 100644
--- a/erpnext/stock/print_format/pick_list/pick_list.json
+++ b/erpnext/stock/print_format/pick_list/pick_list.json
@@ -7,10 +7,10 @@
"docstatus": 0,
"doctype": "Print Format",
"font": "Default",
- "format_data": "[{\"fieldname\": \"print_heading_template\", \"fieldtype\": \"Custom HTML\", \"options\": \"\\t\\t\\t\\t
Pick List{{ doc.name }} \\t\\t\\t\\t \"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"company\", \"label\": \"Company\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"parent_warehouse\", \"label\": \"Parent Warehouse\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"visible_columns\": [{\"print_hide\": 0, \"fieldname\": \"item\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"item_name\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"description\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"warehouse\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"qty\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"serial_no\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"batch_no\", \"print_width\": \"\"}], \"print_hide\": 0, \"fieldname\": \"item_locations\", \"label\": \"Item Locations\"}]",
+ "format_data": "[{\"fieldname\": \"print_heading_template\", \"fieldtype\": \"Custom HTML\", \"options\": \"\\t\\t\\t\\t
Pick List{{ doc.name }} \\t\\t\\t\\t \"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"company\", \"label\": \"Company\"}, {\"print_hide\": 0, \"fieldname\": \"customer\", \"label\": \"Customer\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"purpose\", \"label\": \"Purpose\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"visible_columns\": [{\"print_hide\": 0, \"fieldname\": \"item_name\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"warehouse\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"qty\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"stock_qty\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"serial_no\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"batch_no\", \"print_width\": \"\"}], \"print_hide\": 0, \"fieldname\": \"locations\", \"label\": \"Item Locations\"}]",
"idx": 0,
"line_breaks": 1,
- "modified": "2019-08-02 07:58:35.504361",
+ "modified": "2019-08-30 15:58:27.807219",
"modified_by": "Administrator",
"module": "Stock",
"name": "Pick List",
From b3e5d11e1d10f4e6ea738c149d0161016b5df06a Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Fri, 30 Aug 2019 18:18:48 +0530
Subject: [PATCH 369/484] fix: multiple fixes
---
erpnext/patches.txt | 2 +-
...e_credit_limit_to_customer_credit_limit.py | 15 +++++++------
.../selling/doctype/customer/customer.json | 19 ++++++++--------
erpnext/selling/doctype/customer/customer.py | 22 ++++++++++++++-----
.../selling/doctype/customer/test_customer.py | 8 +++----
...es_order_with_bypass_credit_limit_check.js | 5 +++--
...order_without_bypass_credit_limit_check.js | 6 +++--
7 files changed, 46 insertions(+), 31 deletions(-)
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 2af12698c5..0c909bfa1b 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -632,4 +632,4 @@ execute:frappe.reload_doc('desk', 'doctype','dashboard_chart')
erpnext.patches.v12_0.add_default_dashboards
erpnext.patches.v12_0.remove_bank_remittance_custom_fields
erpnext.patches.v12_0.generate_leave_ledger_entries
-erpnext.patches.v12_0.move_credit_limit_to_customer_credit_limit
\ No newline at end of file
+erpnext.patches.v12_0.move_credit_limit_to_customer_credit_limit #
\ No newline at end of file
diff --git a/erpnext/patches/v12_0/move_credit_limit_to_customer_credit_limit.py b/erpnext/patches/v12_0/move_credit_limit_to_customer_credit_limit.py
index 510d79f23d..3cfabe48ad 100644
--- a/erpnext/patches/v12_0/move_credit_limit_to_customer_credit_limit.py
+++ b/erpnext/patches/v12_0/move_credit_limit_to_customer_credit_limit.py
@@ -19,16 +19,17 @@ def move_credit_limit_to_child_table():
credit_limit_data = frappe.db.sql(''' SELECT
name, credit_limit,
- bypass_credit_limit_check_against_sales_order
+ bypass_credit_limit_check_at_sales_order
FROM `tabCustomer`''', as_dict=1)
- default_company = frappe.db.get_single_value("Global Defaults", "default_company")
+ companies = frappe.get_all("Company", 'name')
for customer in credit_limit_data:
customer = frappe.get_doc("Customer", customer.name)
- customer.append("credit_limit", {
- 'credit_limit': customer.credit_limit,
- 'bypass_credit_limit_check': customer.bypass_credit_limit_check_against_sales_order,
- 'company': default_company
- })
+ for company in companies:
+ customer.append("credit_limit_reference", {
+ 'credit_limit': customer.credit_limit,
+ 'bypass_credit_limit_check': customer.bypass_credit_limit_check_at_sales_order,
+ 'company': company.name
+ })
customer.save()
\ No newline at end of file
diff --git a/erpnext/selling/doctype/customer/customer.json b/erpnext/selling/doctype/customer/customer.json
index 8b5cca9320..b83e284697 100644
--- a/erpnext/selling/doctype/customer/customer.json
+++ b/erpnext/selling/doctype/customer/customer.json
@@ -50,7 +50,7 @@
"accounts",
"credit_limit_section",
"payment_terms",
- "credit_limit",
+ "credit_limit_reference",
"more_info",
"customer_details",
"column_break_45",
@@ -344,13 +344,6 @@
"fieldtype": "Section Break",
"label": "Credit Limit and Payment Terms"
},
- {
- "default": "0",
- "fieldname": "credit_limit",
- "fieldtype": "Table",
- "label": "Credit Limit",
- "options": "Customer Credit Limit"
- },
{
"fieldname": "payment_terms",
"fieldtype": "Link",
@@ -464,12 +457,19 @@
"print_hide": 1,
"read_only": 1,
"report_hide": 1
+ },
+ {
+ "default": "0",
+ "fieldname": "credit_limit_reference",
+ "fieldtype": "Table",
+ "label": "Credit Limit",
+ "options": "Customer Credit Limit"
}
],
"icon": "fa fa-user",
"idx": 363,
"image_field": "image",
- "modified": "2019-08-28 17:38:09.709688",
+ "modified": "2019-08-30 18:03:13.332934",
"modified_by": "Administrator",
"module": "Selling",
"name": "Customer",
@@ -550,6 +550,7 @@
"quick_entry": 1,
"search_fields": "customer_name,customer_group,territory, mobile_no,primary_address",
"show_name_in_global_search": 1,
+ "sort_field": "modified",
"sort_order": "ASC",
"title_field": "customer_name",
"track_changes": 1
diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py
index 5edf06709d..3e9a824dae 100644
--- a/erpnext/selling/doctype/customer/customer.py
+++ b/erpnext/selling/doctype/customer/customer.py
@@ -167,11 +167,17 @@ class Customer(TransactionBase):
frappe.throw(_("A Customer Group exists with same name please change the Customer name or rename the Customer Group"), frappe.NameError)
def validate_credit_limit_on_change(self):
- if self.get("__islocal") or not self.credit_limit:
+ if self.get("__islocal") or not self.credit_limit_reference:
return
+ company_record = [c.company for c in self.credit_limit_reference]
+
for limit in frappe.get_all("Customer Credit Limit", {'parent': self.name}, ["credit_limit", "company"]):
outstanding_amt = get_customer_outstanding(self.name, limit.company)
+ company_record.append(limit.company)
+ if company_record.count(limit.company) >2:
+ frappe.throw(_("Credit limit is already defined for the Company {0}").format(limit.company, self.name))
+
if flt(limit.credit_limit) < outstanding_amt:
frappe.throw(_("""New credit limit is less than current outstanding amount for the customer. Credit limit has to be atleast {0}""").format(outstanding_amt))
@@ -322,14 +328,18 @@ def get_credit_limit(customer, company):
if customer:
credit_record = frappe.db.sql("""SELECT
- customer_group,
- credit_limit
+ c.customer_group,
+ ccl.credit_limit
FROM `tabCustomer`c , `tabCustomer Credit Limit` ccl
WHERE
- c.name = ccl.parent
- """, as_dict=1)
+ c.name = %s
+ AND c.name = ccl.parent
+ AND ccl.company = %s
+ """, (customer, company), as_dict=1)
- if not credit_record.credit_limit:
+ credit_limit = credit_record.credit_limit
+
+ if not credit_limit:
credit_limit = frappe.get_cached_value("Customer Group", credit_record.customer_group, "credit_limit")
if not credit_limit:
diff --git a/erpnext/selling/doctype/customer/test_customer.py b/erpnext/selling/doctype/customer/test_customer.py
index f261ef37fb..8ea4964047 100644
--- a/erpnext/selling/doctype/customer/test_customer.py
+++ b/erpnext/selling/doctype/customer/test_customer.py
@@ -25,7 +25,7 @@ class TestCustomer(unittest.TestCase):
make_test_records('Item')
def tearDown(self):
- frappe.db.set_value("Customer", '_Test Customer', 'credit_limit', 0.0)
+ frappe.db.set_value("Customer", {'parent': '_Test Customer', 'company': '_Test Company'}, 'credit_limit', 0.0)
def test_party_details(self):
from erpnext.accounts.party import get_party_details
@@ -226,7 +226,7 @@ class TestCustomer(unittest.TestCase):
make_sales_order(qty=item_qty)
if credit_limit == 0.0:
- frappe.db.set_value("Customer", '_Test Customer', 'credit_limit', outstanding_amt - 50.0)
+ frappe.db.set_value("Customer", {'parent': '_Test Customer', 'company': '_Test Company'}, 'credit_limit', outstanding_amt - 50.0)
# Sales Order
so = make_sales_order(do_not_submit=True)
@@ -241,7 +241,7 @@ class TestCustomer(unittest.TestCase):
self.assertRaises(frappe.ValidationError, si.submit)
if credit_limit > outstanding_amt:
- frappe.db.set_value("Customer", '_Test Customer', 'credit_limit', credit_limit)
+ frappe.db.set_value("Customer", {'parent': '_Test Customer', 'company': '_Test Company'}, 'credit_limit', credit_limit)
# Makes Sales invoice from Sales Order
so.save(ignore_permissions=True)
@@ -252,7 +252,7 @@ class TestCustomer(unittest.TestCase):
def test_customer_credit_limit_on_change(self):
outstanding_amt = self.get_customer_outstanding_amount()
customer = frappe.get_doc("Customer", '_Test Customer')
- customer.credit_limit = flt(outstanding_amt - 100)
+ customer.credit_limit_reference['credit_limit'] = flt(outstanding_amt - 100)
self.assertRaises(frappe.ValidationError, customer.save)
def test_customer_payment_terms(self):
diff --git a/erpnext/selling/doctype/sales_order/tests/test_sales_order_with_bypass_credit_limit_check.js b/erpnext/selling/doctype/sales_order/tests/test_sales_order_with_bypass_credit_limit_check.js
index dbd58c19c5..1f73f91f61 100644
--- a/erpnext/selling/doctype/sales_order/tests/test_sales_order_with_bypass_credit_limit_check.js
+++ b/erpnext/selling/doctype/sales_order/tests/test_sales_order_with_bypass_credit_limit_check.js
@@ -10,8 +10,9 @@ QUnit.test("test_sales_order_with_bypass_credit_limit_check", function(assert) {
() => frappe.quick_entry.dialog.$wrapper.find('.edit-full').click(),
() => frappe.timeout(1),
() => cur_frm.set_value("customer_name", "Test Customer 10"),
- () => cur_frm.set_value("credit_limit", 100.00),
- () => cur_frm.set_value("bypass_credit_limit_check_at_sales_order", 1),
+ () => cur_frm.add_child('credit_limit_reference', {
+ 'credit_limit': 1000,
+ 'bypass_credit_limit_check': 1}),
// save form
() => cur_frm.save(),
() => frappe.timeout(1),
diff --git a/erpnext/selling/doctype/sales_order/tests/test_sales_order_without_bypass_credit_limit_check.js b/erpnext/selling/doctype/sales_order/tests/test_sales_order_without_bypass_credit_limit_check.js
index 4e81fb065f..34560b6900 100644
--- a/erpnext/selling/doctype/sales_order/tests/test_sales_order_without_bypass_credit_limit_check.js
+++ b/erpnext/selling/doctype/sales_order/tests/test_sales_order_without_bypass_credit_limit_check.js
@@ -10,8 +10,10 @@ QUnit.test("test_sales_order_without_bypass_credit_limit_check", function(assert
() => frappe.quick_entry.dialog.$wrapper.find('.edit-full').click(),
() => frappe.timeout(1),
() => cur_frm.set_value("customer_name", "Test Customer 11"),
- () => cur_frm.set_value("credit_limit", 100.00),
- () => cur_frm.set_value("bypass_credit_limit_check_at_sales_order", 0),
+ () => cur_frm.add_child('credit_limit_reference', {
+ 'credit_limit': 1000,
+ 'company': '_Test Company',
+ 'bypass_credit_limit_check': 1}),
// save form
() => cur_frm.save(),
() => frappe.timeout(1),
From 0eed0a9abe372fa844c641aa386a5a4efbfb2da6 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Fri, 30 Aug 2019 19:12:16 +0530
Subject: [PATCH 370/484] test: Temporarily comment out tests
---
.../stock/doctype/pick_list/test_pick_list.py | 159 +++++++++---------
1 file changed, 80 insertions(+), 79 deletions(-)
diff --git a/erpnext/stock/doctype/pick_list/test_pick_list.py b/erpnext/stock/doctype/pick_list/test_pick_list.py
index 96b770d1de..940d40e6c0 100644
--- a/erpnext/stock/doctype/pick_list/test_pick_list.py
+++ b/erpnext/stock/doctype/pick_list/test_pick_list.py
@@ -3,97 +3,98 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
+# import frappe
import unittest
# test_dependencies = ['Item', 'Sales Invoice', 'Stock Entry', 'Batch']
class TestPickList(unittest.TestCase):
def test_pick_list_picks_warehouse_for_each_item(self):
- pick_list = frappe.get_doc({
- 'doctype': 'Pick List',
- 'company': '_Test Company',
- 'customer': '_Test Customer',
- 'items_based_on': 'Sales Order',
- 'items': [{
- 'item_code': '_Test Item Home Desktop 100',
- 'qty': 5,
- 'stock_qty': 5,
- 'conversion_factor': 1,
- 'sales_order': '_T-Sales Order-1',
- 'sales_item': '_T-Sales Order-1_item',
- }]
- })
- pick_list.set_item_locations()
-
- self.assertEqual(pick_list.locations[0].item_code, '_Test Item Home Desktop 100')
- self.assertEqual(pick_list.locations[0].warehouse, '_Test Warehouse - _TC')
- self.assertEqual(pick_list.locations[0].qty, 5)
-
- def test_pick_list_skips_out_of_stock_item(self):
- pick_list = frappe.get_doc({
- 'doctype': 'Pick List',
- 'company': '_Test Company',
- 'customer': '_Test Customer',
- 'items_based_on': 'Sales Order',
- 'items': [{
- 'item_code': '_Test Item Warehouse Group Wise Reorder',
- 'qty': 1000,
- 'stock_qty': 1000,
- 'conversion_factor': 1,
- 'sales_order': '_T-Sales Order-1',
- 'sales_item': '_T-Sales Order-1_item',
- }]
- })
-
- pick_list.set_item_locations()
-
- self.assertEqual(pick_list.locations[0].item_code, '_Test Item Warehouse Group Wise Reorder')
- self.assertEqual(pick_list.locations[0].warehouse, '_Test Warehouse Group-C1 - _TC')
- self.assertEqual(pick_list.locations[0].qty, 30)
-
-
- def test_pick_list_skips_items_in_expired_batch(self):
pass
+# pick_list = frappe.get_doc({
+# 'doctype': 'Pick List',
+# 'company': '_Test Company',
+# 'customer': '_Test Customer',
+# 'items_based_on': 'Sales Order',
+# 'items': [{
+# 'item_code': '_Test Item Home Desktop 100',
+# 'qty': 5,
+# 'stock_qty': 5,
+# 'conversion_factor': 1,
+# 'sales_order': '_T-Sales Order-1',
+# 'sales_item': '_T-Sales Order-1_item',
+# }]
+# })
+# pick_list.set_item_locations()
- def test_pick_list_shows_serial_no_for_serialized_item(self):
+# self.assertEqual(pick_list.locations[0].item_code, '_Test Item Home Desktop 100')
+# self.assertEqual(pick_list.locations[0].warehouse, '_Test Warehouse - _TC')
+# self.assertEqual(pick_list.locations[0].qty, 5)
- stock_reconciliation = frappe.get_doc({
- 'doctype': 'Stock Reconciliation',
- 'company': '_Test Company',
- 'items': [{
- 'item_code': '_Test Serialized Item',
- 'warehouse': '_Test Warehouse - _TC',
- 'qty': 5,
- 'serial_no': '123450\n123451\n123452\n123453\n123454'
- }]
- })
+ # def test_pick_list_skips_out_of_stock_item(self):
+ # pick_list = frappe.get_doc({
+ # 'doctype': 'Pick List',
+ # 'company': '_Test Company',
+ # 'customer': '_Test Customer',
+ # 'items_based_on': 'Sales Order',
+ # 'items': [{
+ # 'item_code': '_Test Item Warehouse Group Wise Reorder',
+ # 'qty': 1000,
+ # 'stock_qty': 1000,
+ # 'conversion_factor': 1,
+ # 'sales_order': '_T-Sales Order-1',
+ # 'sales_item': '_T-Sales Order-1_item',
+ # }]
+ # })
- stock_reconciliation.submit()
+ # pick_list.set_item_locations()
- pick_list = frappe.get_doc({
- 'doctype': 'Pick List',
- 'company': '_Test Company',
- 'customer': '_Test Customer',
- 'items_based_on': 'Sales Order',
- 'items': [{
- 'item_code': '_Test Serialized Item',
- 'qty': 1000,
- 'stock_qty': 1000,
- 'conversion_factor': 1,
- 'sales_order': '_T-Sales Order-1',
- 'sales_item': '_T-Sales Order-1_item',
- }]
- })
-
- pick_list.set_item_locations()
- self.assertEqual(pick_list.locations[0].item_code, '_Test Serialized Item')
- self.assertEqual(pick_list.locations[0].warehouse, '_Test Warehouse - _TC')
- self.assertEqual(pick_list.locations[0].qty, 5)
- self.assertEqual(pick_list.locations[0].serial_no, '123450\n123451\n123452\n123453\n123454')
+ # self.assertEqual(pick_list.locations[0].item_code, '_Test Item Warehouse Group Wise Reorder')
+ # self.assertEqual(pick_list.locations[0].warehouse, '_Test Warehouse Group-C1 - _TC')
+ # self.assertEqual(pick_list.locations[0].qty, 30)
- def test_pick_list_for_multiple_reference_doctypes(self):
- pass
+ # def test_pick_list_skips_items_in_expired_batch(self):
+ # pass
+
+ # def test_pick_list_shows_serial_no_for_serialized_item(self):
+
+ # stock_reconciliation = frappe.get_doc({
+ # 'doctype': 'Stock Reconciliation',
+ # 'company': '_Test Company',
+ # 'items': [{
+ # 'item_code': '_Test Serialized Item',
+ # 'warehouse': '_Test Warehouse - _TC',
+ # 'qty': 5,
+ # 'serial_no': '123450\n123451\n123452\n123453\n123454'
+ # }]
+ # })
+
+ # stock_reconciliation.submit()
+
+ # pick_list = frappe.get_doc({
+ # 'doctype': 'Pick List',
+ # 'company': '_Test Company',
+ # 'customer': '_Test Customer',
+ # 'items_based_on': 'Sales Order',
+ # 'items': [{
+ # 'item_code': '_Test Serialized Item',
+ # 'qty': 1000,
+ # 'stock_qty': 1000,
+ # 'conversion_factor': 1,
+ # 'sales_order': '_T-Sales Order-1',
+ # 'sales_item': '_T-Sales Order-1_item',
+ # }]
+ # })
+
+ # pick_list.set_item_locations()
+ # self.assertEqual(pick_list.locations[0].item_code, '_Test Serialized Item')
+ # self.assertEqual(pick_list.locations[0].warehouse, '_Test Warehouse - _TC')
+ # self.assertEqual(pick_list.locations[0].qty, 5)
+ # self.assertEqual(pick_list.locations[0].serial_no, '123450\n123451\n123452\n123453\n123454')
+
+
+ # def test_pick_list_for_multiple_reference_doctypes(self):
+ # pass
## records required
From 744b92d2339369af43ea5be9cf4fbc3844b911fe Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Fri, 30 Aug 2019 19:39:28 +0530
Subject: [PATCH 371/484] fix: Commonify item not available alert - Reorganise
code - UX fixes
---
erpnext/stock/doctype/pick_list/pick_list.js | 6 ++-
erpnext/stock/doctype/pick_list/pick_list.py | 50 ++++++++++----------
2 files changed, 30 insertions(+), 26 deletions(-)
diff --git a/erpnext/stock/doctype/pick_list/pick_list.js b/erpnext/stock/doctype/pick_list/pick_list.js
index badb3e7574..7c1e39a7a8 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.js
+++ b/erpnext/stock/doctype/pick_list/pick_list.js
@@ -39,7 +39,11 @@ frappe.ui.form.on('Pick List', {
});
},
get_item_locations: (frm) => {
- frm.call('set_item_locations');
+ if (!frm.doc.locations || !frm.doc.locations.length) {
+ frappe.msgprint(__('First add items in the Item Locations table'));
+ } else {
+ frm.call('set_item_locations');
+ }
},
refresh: (frm) => {
frm.trigger('add_get_items_button');
diff --git a/erpnext/stock/doctype/pick_list/pick_list.py b/erpnext/stock/doctype/pick_list/pick_list.py
index 06bb247d4e..51f41a9632 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.py
+++ b/erpnext/stock/doctype/pick_list/pick_list.py
@@ -130,12 +130,24 @@ def get_items_with_location_and_quantity(item_doc, item_location_map):
return locations
def get_available_item_locations(item_code, from_warehouses, required_qty):
+ locations = []
if frappe.get_cached_value('Item', item_code, 'has_serial_no'):
- return get_available_item_locations_for_serialized_item(item_code, from_warehouses, required_qty)
+ locations = get_available_item_locations_for_serialized_item(item_code, from_warehouses, required_qty)
elif frappe.get_cached_value('Item', item_code, 'has_batch_no'):
- return get_available_item_locations_for_batched_item(item_code, from_warehouses, required_qty)
+ locations = get_available_item_locations_for_batched_item(item_code, from_warehouses, required_qty)
else:
- return get_available_item_locations_for_other_item(item_code, from_warehouses, required_qty)
+ locations = get_available_item_locations_for_other_item(item_code, from_warehouses, required_qty)
+
+ total_qty_available = sum(location.get('qty') for location in locations)
+
+ remaining_qty = required_qty - total_qty_available
+
+ if remaining_qty > 0:
+ frappe.msgprint(_('{0} units of {1} is not available.')
+ .format(remaining_qty, frappe.get_desk_link('Item', item_code)))
+
+ return locations
+
def get_available_item_locations_for_serialized_item(item_code, from_warehouses, required_qty):
filters = frappe._dict({
@@ -153,11 +165,6 @@ def get_available_item_locations_for_serialized_item(item_code, from_warehouses,
order_by='purchase_date',
as_list=1)
- remaining_stock_qty = required_qty - len(serial_nos)
- if remaining_stock_qty:
- frappe.msgprint('{0} qty of {1} is not available.'
- .format(remaining_stock_qty, item_code))
-
warehouse_serial_nos_map = frappe._dict()
for serial_no, warehouse in serial_nos:
warehouse_serial_nos_map.setdefault(warehouse, []).append(serial_no)
@@ -198,13 +205,6 @@ def get_available_item_locations_for_batched_item(item_code, from_warehouses, re
'warehouses': from_warehouses
}, as_dict=1)
- total_qty_available = sum(location.get('qty') for location in batch_locations)
-
- remaining_qty = required_qty - total_qty_available
-
- if remaining_qty > 0:
- frappe.msgprint('No batches found for {} qty of {}.'.format(remaining_qty, item_code))
-
return batch_locations
def get_available_item_locations_for_other_item(item_code, from_warehouses, required_qty):
@@ -225,6 +225,7 @@ def get_available_item_locations_for_other_item(item_code, from_warehouses, requ
return item_locations
+
@frappe.whitelist()
def create_delivery_note(source_name, target_doc=None):
pick_list = frappe.get_doc('Pick List', source_name)
@@ -323,6 +324,15 @@ def target_document_exists(pick_list_name, purpose):
return stock_entry_exists(pick_list_name)
+@frappe.whitelist()
+def get_item_details(item_code, uom=None):
+ details = frappe.db.get_value('Item', item_code, ['stock_uom', 'name'], as_dict=1)
+ details.uom = uom or details.stock_uom
+ if uom:
+ details.update(get_conversion_factor(item_code, uom))
+
+ return details
+
def update_delivery_note_item(source, target, delivery_note):
cost_center = frappe.db.get_value('Project', delivery_note.project, 'cost_center')
@@ -354,16 +364,6 @@ def stock_entry_exists(pick_list_name):
'pick_list': pick_list_name
})
-@frappe.whitelist()
-def get_item_details(item_code, uom=None):
- details = frappe.db.get_value('Item', item_code, ['stock_uom', 'name'], as_dict=1)
- details.uom = uom or details.stock_uom
- if uom:
- details.update(get_conversion_factor(item_code, uom))
-
- return details
-
-
def update_stock_entry_based_on_work_order(pick_list, stock_entry):
work_order = frappe.get_doc("Work Order", pick_list.get('work_order'))
From bcfec77e2c514ed2d3c78ae2d348e7e93f657410 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Fri, 30 Aug 2019 19:44:37 +0530
Subject: [PATCH 372/484] style: Use single quotes
---
erpnext/stock/doctype/pick_list/pick_list.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/stock/doctype/pick_list/pick_list.js b/erpnext/stock/doctype/pick_list/pick_list.js
index 7c1e39a7a8..3f66743f07 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.js
+++ b/erpnext/stock/doctype/pick_list/pick_list.js
@@ -86,7 +86,7 @@ frappe.ui.form.on('Pick List', {
target: frm,
source_name: frm.doc.work_order
});
- }, __("Select Quantity"), __('Get Items'));
+ }, __('Select Quantity'), __('Get Items'));
});
},
material_request: (frm) => {
From 89433b4bea0bc9dd86696356f7fb58f13a513798 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Fri, 30 Aug 2019 22:57:51 +0530
Subject: [PATCH 373/484] fix: get credit limit
---
.../v12_0/move_credit_limit_to_customer_credit_limit.py | 4 ++--
erpnext/selling/doctype/customer/customer.py | 9 +++++----
2 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/erpnext/patches/v12_0/move_credit_limit_to_customer_credit_limit.py b/erpnext/patches/v12_0/move_credit_limit_to_customer_credit_limit.py
index 3cfabe48ad..344dd82958 100644
--- a/erpnext/patches/v12_0/move_credit_limit_to_customer_credit_limit.py
+++ b/erpnext/patches/v12_0/move_credit_limit_to_customer_credit_limit.py
@@ -18,8 +18,8 @@ def move_credit_limit_to_child_table():
''' maps data from old field to the new field in the child table '''
credit_limit_data = frappe.db.sql(''' SELECT
- name, credit_limit,
- bypass_credit_limit_check_at_sales_order
+ name, credit_limit,
+ bypass_credit_limit_check_at_sales_order
FROM `tabCustomer`''', as_dict=1)
companies = frappe.get_all("Company", 'name')
diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py
index 3e9a824dae..940aa34e78 100644
--- a/erpnext/selling/doctype/customer/customer.py
+++ b/erpnext/selling/doctype/customer/customer.py
@@ -335,12 +335,13 @@ def get_credit_limit(customer, company):
c.name = %s
AND c.name = ccl.parent
AND ccl.company = %s
- """, (customer, company), as_dict=1)
+ """, (customer, company))
- credit_limit = credit_record.credit_limit
+ if credit_record:
+ customer_group, credit_limit = credit_record[0]
- if not credit_limit:
- credit_limit = frappe.get_cached_value("Customer Group", credit_record.customer_group, "credit_limit")
+ if not credit_limit and customer_group:
+ credit_limit = frappe.get_cached_value("Customer Group", customer_group, "credit_limit")
if not credit_limit:
credit_limit = frappe.get_cached_value('Company', company, "credit_limit")
From f856b3b5595e8ccdadb4d2041d6ee762e0acfe47 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Sat, 31 Aug 2019 01:40:58 +0530
Subject: [PATCH 374/484] fix: fetch customer group of the customer
---
erpnext/selling/doctype/customer/customer.py | 16 +++-------------
1 file changed, 3 insertions(+), 13 deletions(-)
diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py
index 940aa34e78..0ecb41e98c 100644
--- a/erpnext/selling/doctype/customer/customer.py
+++ b/erpnext/selling/doctype/customer/customer.py
@@ -327,20 +327,10 @@ def get_credit_limit(customer, company):
credit_limit = None
if customer:
- credit_record = frappe.db.sql("""SELECT
- c.customer_group,
- ccl.credit_limit
- FROM `tabCustomer`c , `tabCustomer Credit Limit` ccl
- WHERE
- c.name = %s
- AND c.name = ccl.parent
- AND ccl.company = %s
- """, (customer, company))
+ credit_limit = frappe.db.get_value("Customer Credit Limit", {'parent': customer, 'company': company}, 'credit_limit')
- if credit_record:
- customer_group, credit_limit = credit_record[0]
-
- if not credit_limit and customer_group:
+ if not credit_limit:
+ customer_group = frappe.db.get_value("Customer", customer, 'credit_group')
credit_limit = frappe.get_cached_value("Customer Group", customer_group, "credit_limit")
if not credit_limit:
From e3bb247868e749dde3e601f6879c550a3611740d Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Sat, 31 Aug 2019 13:16:14 +0530
Subject: [PATCH 375/484] fix: check column in credit limit
---
.../v12_0/move_credit_limit_to_customer_credit_limit.py | 9 ++++++---
erpnext/selling/doctype/customer/customer.py | 2 +-
2 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/erpnext/patches/v12_0/move_credit_limit_to_customer_credit_limit.py b/erpnext/patches/v12_0/move_credit_limit_to_customer_credit_limit.py
index 344dd82958..58ad337b34 100644
--- a/erpnext/patches/v12_0/move_credit_limit_to_customer_credit_limit.py
+++ b/erpnext/patches/v12_0/move_credit_limit_to_customer_credit_limit.py
@@ -17,10 +17,13 @@ def execute():
def move_credit_limit_to_child_table():
''' maps data from old field to the new field in the child table '''
+ if not frappe.db.has_column('Customer', 'bypass_credit_limit_check_at_sales_order'):
+ fields = ", bypass_credit_limit_check_at_sales_order"
+
credit_limit_data = frappe.db.sql(''' SELECT
- name, credit_limit,
- bypass_credit_limit_check_at_sales_order
- FROM `tabCustomer`''', as_dict=1)
+ name, credit_limit
+ {0}
+ FROM `tabCustomer`'''.format(fields), as_dict=1) #nosec
companies = frappe.get_all("Company", 'name')
diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py
index 0ecb41e98c..3d5fee9423 100644
--- a/erpnext/selling/doctype/customer/customer.py
+++ b/erpnext/selling/doctype/customer/customer.py
@@ -330,7 +330,7 @@ def get_credit_limit(customer, company):
credit_limit = frappe.db.get_value("Customer Credit Limit", {'parent': customer, 'company': company}, 'credit_limit')
if not credit_limit:
- customer_group = frappe.db.get_value("Customer", customer, 'credit_group')
+ customer_group = frappe.db.get_value("Customer", customer, 'customer_group')
credit_limit = frappe.get_cached_value("Customer Group", customer_group, "credit_limit")
if not credit_limit:
From dbc69da409d31bcefc8b15001fcda2260cbdd2a9 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Sat, 31 Aug 2019 14:28:02 +0530
Subject: [PATCH 376/484] fix: minor fixes
---
.../v12_0/move_credit_limit_to_customer_credit_limit.py | 3 ++-
erpnext/selling/doctype/customer/test_customer.py | 2 +-
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/erpnext/patches/v12_0/move_credit_limit_to_customer_credit_limit.py b/erpnext/patches/v12_0/move_credit_limit_to_customer_credit_limit.py
index 58ad337b34..0b3da20986 100644
--- a/erpnext/patches/v12_0/move_credit_limit_to_customer_credit_limit.py
+++ b/erpnext/patches/v12_0/move_credit_limit_to_customer_credit_limit.py
@@ -17,7 +17,8 @@ def execute():
def move_credit_limit_to_child_table():
''' maps data from old field to the new field in the child table '''
- if not frappe.db.has_column('Customer', 'bypass_credit_limit_check_at_sales_order'):
+ fields=""
+ if frappe.db.has_column('Customer', 'bypass_credit_limit_check_at_sales_order'):
fields = ", bypass_credit_limit_check_at_sales_order"
credit_limit_data = frappe.db.sql(''' SELECT
diff --git a/erpnext/selling/doctype/customer/test_customer.py b/erpnext/selling/doctype/customer/test_customer.py
index 8ea4964047..1ef2aabead 100644
--- a/erpnext/selling/doctype/customer/test_customer.py
+++ b/erpnext/selling/doctype/customer/test_customer.py
@@ -25,7 +25,7 @@ class TestCustomer(unittest.TestCase):
make_test_records('Item')
def tearDown(self):
- frappe.db.set_value("Customer", {'parent': '_Test Customer', 'company': '_Test Company'}, 'credit_limit', 0.0)
+ frappe.db.set_value("Customer Credit Limit", {'parent': '_Test Customer', 'company': '_Test Company'}, 'credit_limit', 0.0)
def test_party_details(self):
from erpnext.accounts.party import get_party_details
From 42d0da8f5a740f2fe3762c8411dbbc56a30e66db Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Sat, 31 Aug 2019 14:28:10 +0530
Subject: [PATCH 377/484] Revert "fix: process allocation expiry"
This reverts commit b654dc0e288e3ecfdfbd0831c3ae15cc7036bb90.
---
.../leave_ledger_entry/leave_ledger_entry.py | 37 ++++++++++---------
1 file changed, 19 insertions(+), 18 deletions(-)
diff --git a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
index 228e226645..c82114e6d5 100644
--- a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
+++ b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
@@ -95,28 +95,29 @@ def process_expired_allocation():
'expire_carry_forwarded_leaves_after_days': (">", 0)
}, fieldname=['name'])
- leave_type = [record[0] for record in leave_type_records]
+ if leave_type_records:
+ leave_type = [record[0] for record in leave_type_records]
- expired_allocation = frappe.db.sql_list("""SELECT name
- FROM `tabLeave Ledger Entry`
- WHERE
- `transaction_type`='Leave Allocation'
- AND `is_expired`=1""")
+ expired_allocation = frappe.db.sql_list("""SELECT name
+ FROM `tabLeave Ledger Entry`
+ WHERE
+ `transaction_type`='Leave Allocation'
+ AND `is_expired`=1""")
- expire_allocation = frappe.get_all("Leave Ledger Entry",
- fields=['leaves', 'to_date', 'employee', 'leave_type', 'is_carry_forward', 'transaction_name as name', 'transaction_type'],
- filters={
- 'to_date': ("<", today()),
- 'transaction_type': 'Leave Allocation',
- 'transaction_name': ('not in', expired_allocation)
- },
- or_filters={
- 'is_carry_forward': 0,
- 'leave_type': ('in', leave_type)
- })
+ expire_allocation = frappe.get_all("Leave Ledger Entry",
+ fields=['leaves', 'to_date', 'employee', 'leave_type', 'is_carry_forward', 'transaction_name as name', 'transaction_type'],
+ filters={
+ 'to_date': ("<", today()),
+ 'transaction_type': 'Leave Allocation',
+ 'transaction_name': ('not in', expired_allocation)
+ },
+ or_filters={
+ 'is_carry_forward': 0,
+ 'leave_type': ('in', leave_type)
+ })
if expire_allocation:
- create_expiry_ledger_entry(expire_allocation)
+ create_expiry_ledger_entry(expire_allocation)
def create_expiry_ledger_entry(allocations):
''' Create ledger entry for expired allocation '''
From bb3cec15567b6ed8e48de7e3927f31945c590f90 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Sat, 31 Aug 2019 14:32:07 +0530
Subject: [PATCH 378/484] test: fetch data from customer credit limit
---
erpnext/selling/doctype/customer/test_customer.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/erpnext/selling/doctype/customer/test_customer.py b/erpnext/selling/doctype/customer/test_customer.py
index 1ef2aabead..e5771b2359 100644
--- a/erpnext/selling/doctype/customer/test_customer.py
+++ b/erpnext/selling/doctype/customer/test_customer.py
@@ -226,7 +226,7 @@ class TestCustomer(unittest.TestCase):
make_sales_order(qty=item_qty)
if credit_limit == 0.0:
- frappe.db.set_value("Customer", {'parent': '_Test Customer', 'company': '_Test Company'}, 'credit_limit', outstanding_amt - 50.0)
+ frappe.db.set_value("Customer Credit Limit", {'parent': '_Test Customer', 'company': '_Test Company'}, 'credit_limit', outstanding_amt - 50.0)
# Sales Order
so = make_sales_order(do_not_submit=True)
@@ -252,7 +252,7 @@ class TestCustomer(unittest.TestCase):
def test_customer_credit_limit_on_change(self):
outstanding_amt = self.get_customer_outstanding_amount()
customer = frappe.get_doc("Customer", '_Test Customer')
- customer.credit_limit_reference['credit_limit'] = flt(outstanding_amt - 100)
+ customer.credit_limit_reference[0].credit_limit = flt(outstanding_amt - 100)
self.assertRaises(frappe.ValidationError, customer.save)
def test_customer_payment_terms(self):
From ca58fde552506acd38477886b63738f2a980b67b Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Sat, 31 Aug 2019 16:58:51 +0530
Subject: [PATCH 379/484] test: Enable basic tests
---
.../stock/doctype/pick_list/test_pick_list.py | 216 +++++++++++-------
1 file changed, 133 insertions(+), 83 deletions(-)
diff --git a/erpnext/stock/doctype/pick_list/test_pick_list.py b/erpnext/stock/doctype/pick_list/test_pick_list.py
index 940d40e6c0..d32e345047 100644
--- a/erpnext/stock/doctype/pick_list/test_pick_list.py
+++ b/erpnext/stock/doctype/pick_list/test_pick_list.py
@@ -3,108 +3,158 @@
# See license.txt
from __future__ import unicode_literals
-# import frappe
+import frappe
import unittest
-# test_dependencies = ['Item', 'Sales Invoice', 'Stock Entry', 'Batch']
+test_dependencies = ['Item', 'Sales Invoice', 'Stock Entry', 'Batch']
+
+from erpnext.stock.doctype.stock_reconciliation.stock_reconciliation \
+ import EmptyStockReconciliationItemsError
class TestPickList(unittest.TestCase):
+
def test_pick_list_picks_warehouse_for_each_item(self):
- pass
-# pick_list = frappe.get_doc({
-# 'doctype': 'Pick List',
-# 'company': '_Test Company',
-# 'customer': '_Test Customer',
-# 'items_based_on': 'Sales Order',
-# 'items': [{
-# 'item_code': '_Test Item Home Desktop 100',
-# 'qty': 5,
-# 'stock_qty': 5,
-# 'conversion_factor': 1,
-# 'sales_order': '_T-Sales Order-1',
-# 'sales_item': '_T-Sales Order-1_item',
-# }]
-# })
-# pick_list.set_item_locations()
+ try:
+ frappe.get_doc({
+ 'doctype': 'Stock Reconciliation',
+ 'company': '_Test Company',
+ 'purpose': 'Opening Stock',
+ 'expense_account': 'Temporary Opening - _TC',
+ 'items': [{
+ 'item_code': '_Test Item Home Desktop 100',
+ 'warehouse': '_Test Warehouse - _TC',
+ 'valuation_rate': 100,
+ 'qty': 5
+ }]
+ }).submit()
+ except EmptyStockReconciliationItemsError:
+ pass
-# self.assertEqual(pick_list.locations[0].item_code, '_Test Item Home Desktop 100')
-# self.assertEqual(pick_list.locations[0].warehouse, '_Test Warehouse - _TC')
-# self.assertEqual(pick_list.locations[0].qty, 5)
+ pick_list = frappe.get_doc({
+ 'doctype': 'Pick List',
+ 'company': '_Test Company',
+ 'customer': '_Test Customer',
+ 'items_based_on': 'Sales Order',
+ 'locations': [{
+ 'item_code': '_Test Item Home Desktop 100',
+ 'qty': 5,
+ 'stock_qty': 5,
+ 'conversion_factor': 1,
+ 'sales_order': '_T-Sales Order-1',
+ 'sales_item': '_T-Sales Order-1_item',
+ }]
+ })
+ pick_list.set_item_locations()
- # def test_pick_list_skips_out_of_stock_item(self):
- # pick_list = frappe.get_doc({
- # 'doctype': 'Pick List',
- # 'company': '_Test Company',
- # 'customer': '_Test Customer',
- # 'items_based_on': 'Sales Order',
- # 'items': [{
- # 'item_code': '_Test Item Warehouse Group Wise Reorder',
- # 'qty': 1000,
- # 'stock_qty': 1000,
- # 'conversion_factor': 1,
- # 'sales_order': '_T-Sales Order-1',
- # 'sales_item': '_T-Sales Order-1_item',
- # }]
- # })
+ self.assertEqual(pick_list.locations[0].item_code, '_Test Item Home Desktop 100')
+ self.assertEqual(pick_list.locations[0].warehouse, '_Test Warehouse - _TC')
+ self.assertEqual(pick_list.locations[0].qty, 5)
- # pick_list.set_item_locations()
+ def test_pick_list_splits_row_according_to_warhouse_availability(self):
+ try:
+ frappe.get_doc({
+ 'doctype': 'Stock Reconciliation',
+ 'company': '_Test Company',
+ 'purpose': 'Opening Stock',
+ 'expense_account': 'Temporary Opening - _TC',
+ 'items': [{
+ 'item_code': '_Test Item Warehouse Group Wise Reorder',
+ 'warehouse': '_Test Warehouse Group-C1 - _TC',
+ 'valuation_rate': 100,
+ 'qty': 5
+ }]
+ }).submit()
+ except EmptyStockReconciliationItemsError:
+ pass
- # self.assertEqual(pick_list.locations[0].item_code, '_Test Item Warehouse Group Wise Reorder')
- # self.assertEqual(pick_list.locations[0].warehouse, '_Test Warehouse Group-C1 - _TC')
- # self.assertEqual(pick_list.locations[0].qty, 30)
+ try:
+ frappe.get_doc({
+ 'doctype': 'Stock Reconciliation',
+ 'company': '_Test Company',
+ 'purpose': 'Opening Stock',
+ 'expense_account': 'Temporary Opening - _TC',
+ 'items': [{
+ 'item_code': '_Test Item Warehouse Group Wise Reorder',
+ 'warehouse': '_Test Warehouse 2 - _TC',
+ 'valuation_rate': 400,
+ 'qty': 10
+ }]
+ }).submit()
+ except EmptyStockReconciliationItemsError:
+ pass
+ pick_list = frappe.get_doc({
+ 'doctype': 'Pick List',
+ 'company': '_Test Company',
+ 'customer': '_Test Customer',
+ 'items_based_on': 'Sales Order',
+ 'locations': [{
+ 'item_code': '_Test Item Warehouse Group Wise Reorder',
+ 'qty': 1000,
+ 'stock_qty': 1000,
+ 'conversion_factor': 1,
+ 'sales_order': '_T-Sales Order-1',
+ 'sales_item': '_T-Sales Order-1_item',
+ }]
+ })
- # def test_pick_list_skips_items_in_expired_batch(self):
- # pass
+ pick_list.set_item_locations()
- # def test_pick_list_shows_serial_no_for_serialized_item(self):
+ self.assertEqual(pick_list.locations[0].item_code, '_Test Item Warehouse Group Wise Reorder')
+ self.assertEqual(pick_list.locations[0].warehouse, '_Test Warehouse Group-C1 - _TC')
+ self.assertEqual(pick_list.locations[0].qty, 5)
- # stock_reconciliation = frappe.get_doc({
- # 'doctype': 'Stock Reconciliation',
- # 'company': '_Test Company',
- # 'items': [{
- # 'item_code': '_Test Serialized Item',
- # 'warehouse': '_Test Warehouse - _TC',
- # 'qty': 5,
- # 'serial_no': '123450\n123451\n123452\n123453\n123454'
- # }]
- # })
+ self.assertEqual(pick_list.locations[1].item_code, '_Test Item Warehouse Group Wise Reorder')
+ self.assertEqual(pick_list.locations[1].warehouse, '_Test Warehouse 2 - _TC')
+ self.assertEqual(pick_list.locations[1].qty, 10)
- # stock_reconciliation.submit()
+ def test_pick_list_shows_serial_no_for_serialized_item(self):
- # pick_list = frappe.get_doc({
- # 'doctype': 'Pick List',
- # 'company': '_Test Company',
- # 'customer': '_Test Customer',
- # 'items_based_on': 'Sales Order',
- # 'items': [{
- # 'item_code': '_Test Serialized Item',
- # 'qty': 1000,
- # 'stock_qty': 1000,
- # 'conversion_factor': 1,
- # 'sales_order': '_T-Sales Order-1',
- # 'sales_item': '_T-Sales Order-1_item',
- # }]
- # })
+ stock_reconciliation = frappe.get_doc({
+ 'doctype': 'Stock Reconciliation',
+ 'company': '_Test Company',
+ 'items': [{
+ 'item_code': '_Test Serialized Item',
+ 'warehouse': '_Test Warehouse - _TC',
+ 'valuation_rate': 100,
+ 'qty': 5,
+ 'serial_no': '123450\n123451\n123452\n123453\n123454'
+ }]
+ })
- # pick_list.set_item_locations()
- # self.assertEqual(pick_list.locations[0].item_code, '_Test Serialized Item')
- # self.assertEqual(pick_list.locations[0].warehouse, '_Test Warehouse - _TC')
- # self.assertEqual(pick_list.locations[0].qty, 5)
- # self.assertEqual(pick_list.locations[0].serial_no, '123450\n123451\n123452\n123453\n123454')
+ stock_reconciliation.submit()
+ pick_list = frappe.get_doc({
+ 'doctype': 'Pick List',
+ 'company': '_Test Company',
+ 'customer': '_Test Customer',
+ 'items_based_on': 'Sales Order',
+ 'locations': [{
+ 'item_code': '_Test Serialized Item',
+ 'qty': 1000,
+ 'stock_qty': 1000,
+ 'conversion_factor': 1,
+ 'sales_order': '_T-Sales Order-1',
+ 'sales_item': '_T-Sales Order-1_item',
+ }]
+ })
+
+ pick_list.set_item_locations()
+ self.assertEqual(pick_list.locations[0].item_code, '_Test Serialized Item')
+ self.assertEqual(pick_list.locations[0].warehouse, '_Test Warehouse - _TC')
+ self.assertEqual(pick_list.locations[0].qty, 5)
+ self.assertEqual(pick_list.locations[0].serial_no, '123450\n123451\n123452\n123453\n123454')
# def test_pick_list_for_multiple_reference_doctypes(self):
# pass
+ # def test_pick_list_skips_items_in_expired_batch(self):
+ # pass
-## records required
+ # def test_pick_list_from_sales_order(self):
+ # pass
-'''
-batch no
-items
-sales invoice
-stock entries
- bin
- stock ledger entry
-warehouses
-'''
\ No newline at end of file
+ # def test_pick_list_from_work_order(self):
+ # pass
+
+ # def test_pick_list_from_material_request(self):
+ # pass
\ No newline at end of file
From 736b5e07cc59596a19dd9a5ac697ac4f6f1dfe10 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Sat, 31 Aug 2019 18:33:23 +0530
Subject: [PATCH 380/484] fix: Maintain the order of Item List
---
erpnext/stock/doctype/pick_list/pick_list.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/erpnext/stock/doctype/pick_list/pick_list.py b/erpnext/stock/doctype/pick_list/pick_list.py
index 51f41a9632..c4d8c41ebb 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.py
+++ b/erpnext/stock/doctype/pick_list/pick_list.py
@@ -8,6 +8,7 @@ import json
from six import iteritems
from frappe.model.document import Document
from frappe import _
+from collections import OrderedDict
from frappe.utils import floor, flt, today, cint
from frappe.model.mapper import get_mapped_doc, map_child_doc
from erpnext.stock.get_item_details import get_conversion_factor
@@ -62,7 +63,7 @@ class PickList(Document):
locations = self.get('locations')
self.item_count_map = {}
# aggregate qty for same item
- item_map = frappe._dict()
+ item_map = OrderedDict()
for item in locations:
item_code = item.item_code
reference = item.sales_order_item or item.material_request_item
From 72bea0dff4d7552c20ee200a8d0ce248880589a8 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Sat, 31 Aug 2019 18:34:25 +0530
Subject: [PATCH 381/484] test: Add test to check creation of pick list from
multiple sales order
---
.../stock/doctype/pick_list/test_pick_list.py | 70 +++++++++++++++++--
1 file changed, 65 insertions(+), 5 deletions(-)
diff --git a/erpnext/stock/doctype/pick_list/test_pick_list.py b/erpnext/stock/doctype/pick_list/test_pick_list.py
index d32e345047..6b4f73b140 100644
--- a/erpnext/stock/doctype/pick_list/test_pick_list.py
+++ b/erpnext/stock/doctype/pick_list/test_pick_list.py
@@ -40,7 +40,7 @@ class TestPickList(unittest.TestCase):
'stock_qty': 5,
'conversion_factor': 1,
'sales_order': '_T-Sales Order-1',
- 'sales_item': '_T-Sales Order-1_item',
+ 'sales_order_item': '_T-Sales Order-1_item',
}]
})
pick_list.set_item_locations()
@@ -93,7 +93,7 @@ class TestPickList(unittest.TestCase):
'stock_qty': 1000,
'conversion_factor': 1,
'sales_order': '_T-Sales Order-1',
- 'sales_item': '_T-Sales Order-1_item',
+ 'sales_order_item': '_T-Sales Order-1_item',
}]
})
@@ -134,7 +134,7 @@ class TestPickList(unittest.TestCase):
'stock_qty': 1000,
'conversion_factor': 1,
'sales_order': '_T-Sales Order-1',
- 'sales_item': '_T-Sales Order-1_item',
+ 'sales_order_item': '_T-Sales Order-1_item',
}]
})
@@ -144,8 +144,68 @@ class TestPickList(unittest.TestCase):
self.assertEqual(pick_list.locations[0].qty, 5)
self.assertEqual(pick_list.locations[0].serial_no, '123450\n123451\n123452\n123453\n123454')
- # def test_pick_list_for_multiple_reference_doctypes(self):
- # pass
+ def test_pick_list_for_items_from_multiple_sales_orders(self):
+ try:
+ frappe.get_doc({
+ 'doctype': 'Stock Reconciliation',
+ 'company': '_Test Company',
+ 'purpose': 'Opening Stock',
+ 'expense_account': 'Temporary Opening - _TC',
+ 'items': [{
+ 'item_code': '_Test Item Home Desktop 100',
+ 'warehouse': '_Test Warehouse - _TC',
+ 'valuation_rate': 100,
+ 'qty': 10
+ }]
+ }).submit()
+ except EmptyStockReconciliationItemsError:
+ pass
+
+ sales_order = frappe.get_doc({
+ 'doctype': "Sales Order",
+ 'customer': '_Test Customer',
+ 'company': '_Test Company',
+ 'items': [{
+ 'item_code': '_Test Item Home Desktop 100',
+ 'qty': 10,
+ 'delivery_date': frappe.utils.today()
+ }],
+ })
+ sales_order.submit()
+
+ pick_list = frappe.get_doc({
+ 'doctype': 'Pick List',
+ 'company': '_Test Company',
+ 'customer': '_Test Customer',
+ 'items_based_on': 'Sales Order',
+ 'locations': [{
+ 'item_code': '_Test Item Home Desktop 100',
+ 'qty': 5,
+ 'stock_qty': 5,
+ 'conversion_factor': 1,
+ 'sales_order': '_T-Sales Order-1',
+ 'sales_order_item': '_T-Sales Order-1_item',
+ }, {
+ 'item_code': '_Test Item Home Desktop 100',
+ 'qty': 5,
+ 'stock_qty': 5,
+ 'conversion_factor': 1,
+ 'sales_order': sales_order.name,
+ 'sales_order_item': sales_order.items[0].name,
+ }]
+ })
+ pick_list.set_item_locations()
+
+ self.assertEqual(pick_list.locations[0].item_code, '_Test Item Home Desktop 100')
+ self.assertEqual(pick_list.locations[0].warehouse, '_Test Warehouse - _TC')
+ self.assertEqual(pick_list.locations[0].qty, 5)
+ self.assertEqual(pick_list.locations[0].sales_order_item, '_T-Sales Order-1_item')
+
+ self.assertEqual(pick_list.locations[1].item_code, '_Test Item Home Desktop 100')
+ self.assertEqual(pick_list.locations[1].warehouse, '_Test Warehouse - _TC')
+ self.assertEqual(pick_list.locations[1].qty, 5)
+ self.assertEqual(pick_list.locations[1].sales_order_item, sales_order.items[0].name)
+
# def test_pick_list_skips_items_in_expired_batch(self):
# pass
From 86720deeae65adc00a25ce3ba514559bfb60f080 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Sun, 1 Sep 2019 10:15:23 +0530
Subject: [PATCH 382/484] fix: bypass credit limit check
---
erpnext/patches.txt | 2 +-
.../v12_0/move_credit_limit_to_customer_credit_limit.py | 8 ++++----
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 0c909bfa1b..2af12698c5 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -632,4 +632,4 @@ execute:frappe.reload_doc('desk', 'doctype','dashboard_chart')
erpnext.patches.v12_0.add_default_dashboards
erpnext.patches.v12_0.remove_bank_remittance_custom_fields
erpnext.patches.v12_0.generate_leave_ledger_entries
-erpnext.patches.v12_0.move_credit_limit_to_customer_credit_limit #
\ No newline at end of file
+erpnext.patches.v12_0.move_credit_limit_to_customer_credit_limit
\ No newline at end of file
diff --git a/erpnext/patches/v12_0/move_credit_limit_to_customer_credit_limit.py b/erpnext/patches/v12_0/move_credit_limit_to_customer_credit_limit.py
index 0b3da20986..6f59b46ee7 100644
--- a/erpnext/patches/v12_0/move_credit_limit_to_customer_credit_limit.py
+++ b/erpnext/patches/v12_0/move_credit_limit_to_customer_credit_limit.py
@@ -21,19 +21,19 @@ def move_credit_limit_to_child_table():
if frappe.db.has_column('Customer', 'bypass_credit_limit_check_at_sales_order'):
fields = ", bypass_credit_limit_check_at_sales_order"
- credit_limit_data = frappe.db.sql(''' SELECT
+ credit_limit_record = frappe.db.sql(''' SELECT
name, credit_limit
{0}
FROM `tabCustomer`'''.format(fields), as_dict=1) #nosec
companies = frappe.get_all("Company", 'name')
- for customer in credit_limit_data:
+ for record in credit_limit_record:
customer = frappe.get_doc("Customer", customer.name)
for company in companies:
customer.append("credit_limit_reference", {
- 'credit_limit': customer.credit_limit,
- 'bypass_credit_limit_check': customer.bypass_credit_limit_check_at_sales_order,
+ 'credit_limit': record.credit_limit,
+ 'bypass_credit_limit_check': record.bypass_credit_limit_check_at_sales_order,
'company': company.name
})
customer.save()
\ No newline at end of file
From fd85b1689d38a746387044597ce9fbf2f0571a90 Mon Sep 17 00:00:00 2001
From: Himanshu Warekar
Date: Mon, 2 Sep 2019 12:10:15 +0530
Subject: [PATCH 383/484] fix: review fixes
---
erpnext/communication/doctype/call_log/call_log.py | 2 +-
erpnext/crm/doctype/opportunity/test_opportunity.py | 6 +++---
erpnext/public/js/templates/contact_list.html | 6 +++---
3 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/erpnext/communication/doctype/call_log/call_log.py b/erpnext/communication/doctype/call_log/call_log.py
index 411f56c5ec..35c31a0bf8 100644
--- a/erpnext/communication/doctype/call_log/call_log.py
+++ b/erpnext/communication/doctype/call_log/call_log.py
@@ -75,7 +75,7 @@ def set_caller_information(doc, state):
# Contact now has all the nos saved in child table
if doc.doctype == 'Contact':
- numbers = [nos.phone for nos in doc.phone_nos]
+ numbers = [d.phone for d in doc.phone_nos]
for number in numbers:
number = strip_number(number)
diff --git a/erpnext/crm/doctype/opportunity/test_opportunity.py b/erpnext/crm/doctype/opportunity/test_opportunity.py
index 8927d93027..8f61edf00e 100644
--- a/erpnext/crm/doctype/opportunity/test_opportunity.py
+++ b/erpnext/crm/doctype/opportunity/test_opportunity.py
@@ -45,7 +45,7 @@ class TestOpportunity(unittest.TestCase):
# create new customer and create new contact against 'new.opportunity@example.com'
customer = make_customer(opp_doc.party_name).insert(ignore_permissions=True)
- d = frappe.get_doc({
+ contact = frappe.get_doc({
"doctype": "Contact",
"first_name": "_Test Opportunity Customer",
"links": [{
@@ -53,8 +53,8 @@ class TestOpportunity(unittest.TestCase):
"link_name": customer.name
}]
})
- d.add_email(new_lead_email_id)
- d.insert(ignore_permissions=True)
+ contact.add_email(new_lead_email_id)
+ contact.insert(ignore_permissions=True)
opp_doc = frappe.get_doc(args).insert(ignore_permissions=True)
self.assertTrue(opp_doc.party_name)
diff --git a/erpnext/public/js/templates/contact_list.html b/erpnext/public/js/templates/contact_list.html
index 8dd220f72d..da7b059fcd 100644
--- a/erpnext/public/js/templates/contact_list.html
+++ b/erpnext/public/js/templates/contact_list.html
@@ -21,7 +21,7 @@
{% endif %}
{% if(contact_list[i].phone_nos) { %}
{% for(var j=0, k=contact_list[i].phone_nos.length; j
+ {%= __("Phone") %}: {%= contact_list[i].phone_nos[j].phone %}
{% } %}
{% endif %}
@@ -31,14 +31,14 @@
{% endif %}
{% if(contact_list[i].email_ids) { %}
{% for(var j=0, k=contact_list[i].email_ids.length; j
+ {%= __("Email") %}: {%= contact_list[i].email_ids[j].email_id %}
{% } %}
{% endif %}
{% endif %}
{% if (contact_list[i].address) { %}
- {%= __("Address ") %}: {%= contact_list[i].address %}
+ {%= __("Address") %}: {%= contact_list[i].address %}
{% endif %}
From 26dfd5b3140d827c24a8f5ec061112809a243f21 Mon Sep 17 00:00:00 2001
From: Himanshu Warekar
Date: Mon, 2 Sep 2019 12:21:41 +0530
Subject: [PATCH 384/484] fix: translation strings
---
erpnext/public/js/templates/contact_list.html | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/erpnext/public/js/templates/contact_list.html b/erpnext/public/js/templates/contact_list.html
index da7b059fcd..50fbfd9f12 100644
--- a/erpnext/public/js/templates/contact_list.html
+++ b/erpnext/public/js/templates/contact_list.html
@@ -17,7 +17,7 @@
{% if (contact_list[i].phones || contact_list[i].email_ids) { %}
{% if(contact_list[i].phone) { %}
- {%= __("Phone ") %}: {%= contact_list[i].phone %} ({%= __("Primary") %})
+ {%= __("Phone") %}: {%= contact_list[i].phone %} ({%= __("Primary") %})
{% endif %}
{% if(contact_list[i].phone_nos) { %}
{% for(var j=0, k=contact_list[i].phone_nos.length; j
{% if(contact_list[i].email_id) { %}
- {%= __("Email ") %}: {%= contact_list[i].email_id %} ({%= __("Primary") %})
+ {%= __("Email") %}: {%= contact_list[i].email_id %} ({%= __("Primary") %})
{% endif %}
{% if(contact_list[i].email_ids) { %}
{% for(var j=0, k=contact_list[i].email_ids.length; j
Date: Mon, 2 Sep 2019 13:20:27 +0530
Subject: [PATCH 385/484] fix: fix query for contacts
---
erpnext/accounts/doctype/sales_invoice/pos.py | 4 ++--
erpnext/selling/doctype/sms_center/sms_center.py | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/erpnext/accounts/doctype/sales_invoice/pos.py b/erpnext/accounts/doctype/sales_invoice/pos.py
index e290b235a9..7e23793700 100755
--- a/erpnext/accounts/doctype/sales_invoice/pos.py
+++ b/erpnext/accounts/doctype/sales_invoice/pos.py
@@ -227,8 +227,8 @@ def get_contacts(customers):
customers = [frappe._dict({'name': customers})]
for data in customers:
- contact = frappe.db.sql(""" select email_id, phone, mobile_no from `tabContact`
- where is_primary_contact =1 and name in
+ contact = frappe.db.sql(""" select email_id, phone from `tabContact`
+ where is_primary_contact=1 and name in
(select parent from `tabDynamic Link` where link_doctype = 'Customer' and link_name = %s
and parenttype = 'Contact')""", data.name, as_dict=1)
if contact:
diff --git a/erpnext/selling/doctype/sms_center/sms_center.py b/erpnext/selling/doctype/sms_center/sms_center.py
index bb6ba1ffce..289b045e1c 100644
--- a/erpnext/selling/doctype/sms_center/sms_center.py
+++ b/erpnext/selling/doctype/sms_center/sms_center.py
@@ -31,7 +31,7 @@ class SMSCenter(Document):
self.sales_partner.replace("'", "\'") or " and ifnull(dl.link_name, '') != ''"
if self.send_to in ['All Contact', 'All Customer Contact', 'All Supplier Contact', 'All Sales Partner Contact']:
rec = frappe.db.sql("""select CONCAT(ifnull(c.first_name,''), ' ', ifnull(c.last_name,'')),
- c.mobile_no from `tabContact` c, `tabDynamic Link` dl where ifnull(c.mobile_no,'')!='' and
+ c.phone from `tabContact` c, `tabDynamic Link` dl where ifnull(c.phone,'')!='' and
c.docstatus != 2 and dl.parent = c.name%s""" % where_clause)
elif self.send_to == 'All Lead (Open)':
From 711d1acffd969e18859421e80c1677c6ab3b549f Mon Sep 17 00:00:00 2001
From: Himanshu Warekar
Date: Mon, 2 Sep 2019 13:31:10 +0530
Subject: [PATCH 386/484] fix: remove references of mobile_no
---
erpnext/accounts/page/pos/pos.js | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/erpnext/accounts/page/pos/pos.js b/erpnext/accounts/page/pos/pos.js
index b5a02d0e49..0e7301204a 100755
--- a/erpnext/accounts/page/pos/pos.js
+++ b/erpnext/accounts/page/pos/pos.js
@@ -816,7 +816,6 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
contact = me.contacts[data.name];
if(reg.test(data.name.toLowerCase())
|| reg.test(data.customer_name.toLowerCase())
- || (contact && reg.test(contact["mobile_no"]))
|| (contact && reg.test(contact["phone"]))
|| (data.customer_group && reg.test(data.customer_group.toLowerCase()))){
return data;
@@ -834,7 +833,6 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
if(contact && !c['phone']) {
c["phone"] = contact["phone"];
c["email_id"] = contact["email_id"];
- c["mobile_no"] = contact["mobile_no"];
}
me.customers_mapper.push({
@@ -844,10 +842,9 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
customer_group: c.customer_group,
territory: c.territory,
phone: contact ? contact["phone"] : '',
- mobile_no: contact ? contact["mobile_no"] : '',
email_id: contact ? contact["email_id"] : '',
searchtext: ['customer_name', 'customer_group', 'name', 'value',
- 'label', 'email_id', 'phone', 'mobile_no']
+ 'label', 'email_id', 'phone']
.map(key => c[key]).join(' ')
.toLowerCase()
});
From 402d82b4c54ad643832f1216384a220fe296766a Mon Sep 17 00:00:00 2001
From: deepeshgarg007
Date: Mon, 2 Sep 2019 14:37:18 +0530
Subject: [PATCH 387/484] fix: Remove delete_doc from tests
---
.../accounts/doctype/budget/test_budget.py | 52 +++++++++----------
.../loyalty_program/test_loyalty_program.py | 3 --
.../sales_invoice/test_sales_invoice.py | 1 -
.../test_tax_withholding_category.py | 3 --
erpnext/assets/doctype/asset/test_asset.py | 2 -
.../expense_claim/test_expense_claim.py | 1 -
.../test_stock_reconciliation.py | 4 --
7 files changed, 25 insertions(+), 41 deletions(-)
diff --git a/erpnext/accounts/doctype/budget/test_budget.py b/erpnext/accounts/doctype/budget/test_budget.py
index b126b1fb0a..33aefd67d1 100644
--- a/erpnext/accounts/doctype/budget/test_budget.py
+++ b/erpnext/accounts/doctype/budget/test_budget.py
@@ -11,32 +11,32 @@ from erpnext.buying.doctype.purchase_order.test_purchase_order import create_pur
from erpnext.accounts.doctype.budget.budget import get_actual_expense, BudgetError
from erpnext.accounts.doctype.journal_entry.test_journal_entry import make_journal_entry
-class TestBudget(unittest.TestCase):
+class TestBudget(unittest.TestCase):
def test_monthly_budget_crossed_ignore(self):
set_total_expense_zero("2013-02-28", "Cost Center")
budget = make_budget(budget_against="Cost Center")
-
+
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
"_Test Bank - _TC", 40000, "_Test Cost Center - _TC", posting_date="2013-02-28", submit=True)
self.assertTrue(frappe.db.get_value("GL Entry",
{"voucher_type": "Journal Entry", "voucher_no": jv.name}))
-
+
budget.cancel()
def test_monthly_budget_crossed_stop1(self):
set_total_expense_zero("2013-02-28", "Cost Center")
budget = make_budget(budget_against="Cost Center")
-
+
frappe.db.set_value("Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop")
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
"_Test Bank - _TC", 40000, "_Test Cost Center - _TC", posting_date="2013-02-28")
self.assertRaises(BudgetError, jv.submit)
-
+
budget.load_from_db()
budget.cancel()
@@ -46,7 +46,7 @@ class TestBudget(unittest.TestCase):
budget = make_budget(budget_against="Cost Center")
frappe.db.set_value("Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop")
-
+
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
"_Test Bank - _TC", 40000, "_Test Cost Center - _TC", posting_date="2013-03-02")
@@ -117,14 +117,14 @@ class TestBudget(unittest.TestCase):
set_total_expense_zero("2013-02-28", "Project")
budget = make_budget(budget_against="Project")
-
+
frappe.db.set_value("Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop")
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
"_Test Bank - _TC", 40000, "_Test Cost Center - _TC", project="_Test Project", posting_date="2013-02-28")
self.assertRaises(BudgetError, jv.submit)
-
+
budget.load_from_db()
budget.cancel()
@@ -132,31 +132,31 @@ class TestBudget(unittest.TestCase):
set_total_expense_zero("2013-02-28", "Cost Center")
budget = make_budget(budget_against="Cost Center")
-
+
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
"_Test Bank - _TC", 150000, "_Test Cost Center - _TC", posting_date="2013-03-28")
self.assertRaises(BudgetError, jv.submit)
-
+
budget.cancel()
def test_yearly_budget_crossed_stop2(self):
set_total_expense_zero("2013-02-28", "Project")
budget = make_budget(budget_against="Project")
-
+
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
"_Test Bank - _TC", 150000, "_Test Cost Center - _TC", project="_Test Project", posting_date="2013-03-28")
self.assertRaises(BudgetError, jv.submit)
-
+
budget.cancel()
def test_monthly_budget_on_cancellation1(self):
set_total_expense_zero("2013-02-28", "Cost Center")
budget = make_budget(budget_against="Cost Center")
-
+
jv1 = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
"_Test Bank - _TC", 20000, "_Test Cost Center - _TC", posting_date="2013-02-28", submit=True)
@@ -170,9 +170,9 @@ class TestBudget(unittest.TestCase):
{"voucher_type": "Journal Entry", "voucher_no": jv2.name}))
frappe.db.set_value("Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop")
-
+
self.assertRaises(BudgetError, jv1.cancel)
-
+
budget.load_from_db()
budget.cancel()
@@ -180,7 +180,7 @@ class TestBudget(unittest.TestCase):
set_total_expense_zero("2013-02-28", "Project")
budget = make_budget(budget_against="Project")
-
+
jv1 = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
"_Test Bank - _TC", 20000, "_Test Cost Center - _TC", posting_date="2013-02-28", submit=True, project="_Test Project")
@@ -194,16 +194,16 @@ class TestBudget(unittest.TestCase):
{"voucher_type": "Journal Entry", "voucher_no": jv2.name}))
frappe.db.set_value("Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop")
-
+
self.assertRaises(BudgetError, jv1.cancel)
-
+
budget.load_from_db()
budget.cancel()
def test_monthly_budget_against_group_cost_center(self):
set_total_expense_zero("2013-02-28", "Cost Center")
set_total_expense_zero("2013-02-28", "Cost Center", "_Test Cost Center 2 - _TC")
-
+
budget = make_budget(budget_against="Cost Center", cost_center="_Test Company - _TC")
frappe.db.set_value("Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop")
@@ -211,7 +211,7 @@ class TestBudget(unittest.TestCase):
"_Test Bank - _TC", 40000, "_Test Cost Center 2 - _TC", posting_date="2013-02-28")
self.assertRaises(BudgetError, jv.submit)
-
+
budget.load_from_db()
budget.cancel()
@@ -239,8 +239,6 @@ class TestBudget(unittest.TestCase):
budget.cancel()
jv.cancel()
- frappe.delete_doc('Journal Entry', jv.name)
- frappe.delete_doc('Cost Center', cost_center)
def set_total_expense_zero(posting_date, budget_against_field=None, budget_against_CC=None):
if budget_against_field == "Project":
@@ -256,7 +254,7 @@ def set_total_expense_zero(posting_date, budget_against_field=None, budget_again
"budget_against_field": budget_against_field,
"budget_against": budget_against
}))
-
+
if existing_expense:
if budget_against_field == "Cost Center":
make_journal_entry("_Test Account Cost for Goods Sold - _TC",
@@ -281,13 +279,13 @@ def make_budget(**args):
frappe.db.sql("delete from `tabBudget Account` where parent = %(name)s", d)
budget = frappe.new_doc("Budget")
-
+
if budget_against == "Project":
budget.project = "_Test Project"
else:
budget.cost_center =cost_center or "_Test Cost Center - _TC"
-
-
+
+
budget.fiscal_year = "_Test Fiscal Year 2013"
budget.monthly_distribution = "_Test Distribution"
budget.company = "_Test Company"
@@ -299,7 +297,7 @@ def make_budget(**args):
"account": "_Test Account Cost for Goods Sold - _TC",
"budget_amount": 100000
})
-
+
if args.applicable_on_material_request:
budget.applicable_on_material_request = 1
budget.action_if_annual_budget_exceeded_on_mr = args.action_if_annual_budget_exceeded_on_mr or 'Warn'
diff --git a/erpnext/accounts/doctype/loyalty_program/test_loyalty_program.py b/erpnext/accounts/doctype/loyalty_program/test_loyalty_program.py
index 56a0d2f39c..4a7406e0cb 100644
--- a/erpnext/accounts/doctype/loyalty_program/test_loyalty_program.py
+++ b/erpnext/accounts/doctype/loyalty_program/test_loyalty_program.py
@@ -49,7 +49,6 @@ class TestLoyaltyProgram(unittest.TestCase):
# cancel and delete
for d in [si_redeem, si_original]:
d.cancel()
- frappe.delete_doc('Sales Invoice', d.name)
def test_loyalty_points_earned_multiple_tier(self):
frappe.db.set_value("Customer", "Test Loyalty Customer", "loyalty_program", "Test Multiple Loyalty")
@@ -91,7 +90,6 @@ class TestLoyaltyProgram(unittest.TestCase):
# cancel and delete
for d in [si_redeem, si_original]:
d.cancel()
- frappe.delete_doc('Sales Invoice', d.name)
def test_cancel_sales_invoice(self):
''' cancelling the sales invoice should cancel the earned points'''
@@ -143,7 +141,6 @@ class TestLoyaltyProgram(unittest.TestCase):
d.cancel()
except frappe.TimestampMismatchError:
frappe.get_doc('Sales Invoice', d.name).cancel()
- frappe.delete_doc('Sales Invoice', d.name)
def test_loyalty_points_for_dashboard(self):
doc = frappe.get_doc('Customer', 'Test Loyalty Customer')
diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
index dff55947df..4f253b69f7 100644
--- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
@@ -818,7 +818,6 @@ class TestSalesInvoice(unittest.TestCase):
self.assertEqual(expected_gl_entries[i][2], gle.credit)
si.cancel()
- frappe.delete_doc('Sales Invoice', si.name)
gle = frappe.db.sql("""select * from `tabGL Entry`
where voucher_type='Sales Invoice' and voucher_no=%s""", si.name)
diff --git a/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py b/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py
index 638e57ed2b..b1468999fc 100644
--- a/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py
+++ b/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py
@@ -48,7 +48,6 @@ class TestTaxWithholdingCategory(unittest.TestCase):
#delete invoices to avoid clashing
for d in invoices:
d.cancel()
- frappe.delete_doc("Purchase Invoice", d.name)
def test_single_threshold_tds(self):
invoices = []
@@ -83,7 +82,6 @@ class TestTaxWithholdingCategory(unittest.TestCase):
# delete invoices to avoid clashing
for d in invoices:
d.cancel()
- frappe.delete_doc("Purchase Invoice", d.name)
def test_single_threshold_tds_with_previous_vouchers(self):
invoices = []
@@ -102,7 +100,6 @@ class TestTaxWithholdingCategory(unittest.TestCase):
# delete invoices to avoid clashing
for d in invoices:
d.cancel()
- frappe.delete_doc("Purchase Invoice", d.name)
def create_purchase_invoice(**args):
# return sales invoice doc object
diff --git a/erpnext/assets/doctype/asset/test_asset.py b/erpnext/assets/doctype/asset/test_asset.py
index 481ee7d9f4..c09b94fa8e 100644
--- a/erpnext/assets/doctype/asset/test_asset.py
+++ b/erpnext/assets/doctype/asset/test_asset.py
@@ -456,8 +456,6 @@ class TestAsset(unittest.TestCase):
self.assertEqual(gle, expected_gle)
si.cancel()
- frappe.delete_doc("Sales Invoice", si.name)
-
self.assertEqual(frappe.db.get_value("Asset", asset.name, "status"), "Partially Depreciated")
def test_asset_expected_value_after_useful_life(self):
diff --git a/erpnext/hr/doctype/expense_claim/test_expense_claim.py b/erpnext/hr/doctype/expense_claim/test_expense_claim.py
index 6618a4f7c5..b559dfd81d 100644
--- a/erpnext/hr/doctype/expense_claim/test_expense_claim.py
+++ b/erpnext/hr/doctype/expense_claim/test_expense_claim.py
@@ -45,7 +45,6 @@ class TestExpenseClaim(unittest.TestCase):
self.assertEqual(frappe.db.get_value("Project", "_Test Project 1", "total_expense_claim"), 700)
expense_claim2.cancel()
- frappe.delete_doc("Expense Claim", expense_claim2.name)
self.assertEqual(frappe.db.get_value("Task", task_name, "total_expense_claim"), 200)
self.assertEqual(frappe.db.get_value("Project", "_Test Project 1", "total_expense_claim"), 200)
diff --git a/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py
index ededc4d8b4..cd05929743 100644
--- a/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py
+++ b/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py
@@ -152,7 +152,6 @@ class TestStockReconciliation(unittest.TestCase):
for d in to_delete_records:
stock_doc = frappe.get_doc("Stock Reconciliation", d)
stock_doc.cancel()
- frappe.delete_doc("Stock Reconciliation", stock_doc.name)
for d in serial_nos + serial_nos1:
if frappe.db.exists("Serial No", d):
@@ -203,9 +202,6 @@ class TestStockReconciliation(unittest.TestCase):
stock_doc = frappe.get_doc("Stock Reconciliation", d)
stock_doc.cancel()
- frappe.delete_doc("Batch", sr.items[0].batch_no)
- for d in to_delete_records:
- frappe.delete_doc("Stock Reconciliation", d)
def insert_existing_sle():
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
From 063144c514ac4e42112935592380bd15466d6d7a Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Mon, 2 Sep 2019 15:53:28 +0530
Subject: [PATCH 388/484] fix: Check in_patch before adding 'All Item Group'
---
erpnext/setup/doctype/item_group/item_group.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/setup/doctype/item_group/item_group.py b/erpnext/setup/doctype/item_group/item_group.py
index 760b20a476..bb357d8bf8 100644
--- a/erpnext/setup/doctype/item_group/item_group.py
+++ b/erpnext/setup/doctype/item_group/item_group.py
@@ -27,7 +27,7 @@ class ItemGroup(NestedSet, WebsiteGenerator):
def validate(self):
super(ItemGroup, self).validate()
- if not self.parent_item_group:
+ if not self.parent_item_group and not frappe.flags.in_test:
self.parent_item_group = 'All Item Groups'
self.make_route()
From fffdb6f575a034403d230c3611ad4afdaa45853b Mon Sep 17 00:00:00 2001
From: Himanshu
Date: Mon, 2 Sep 2019 15:57:45 +0530
Subject: [PATCH 389/484] feat(Contacts): Multiple Emails in a Contact (#18675)
* feat: render multiple addresses
* feat: move to newer contacts structure
* fix: iterate over valid variable
* fix: use primary label instead of bold letters
* fix: call popup get contact name from number
* fix: make contact structure call popup compatible
* fix: query
* fix: add city, state and country
* fix: display address
* fix: get address in single line
* fix: review fixes
* fix: translation strings
* fix: fix query for contacts
* fix: remove references of mobile_no
---
erpnext/accounts/doctype/sales_invoice/pos.py | 4 +--
erpnext/accounts/page/pos/pos.js | 5 +--
.../doctype/call_log/call_log.py | 4 +++
.../doctype/opportunity/test_opportunity.py | 7 ++--
.../exotel_settings/exotel_settings.py | 1 -
erpnext/hub_node/legacy.py | 5 +--
erpnext/public/js/templates/contact_list.html | 35 +++++++++++++------
erpnext/selling/doctype/customer/customer.py | 7 ++--
.../selling/doctype/sms_center/sms_center.py | 2 +-
9 files changed, 43 insertions(+), 27 deletions(-)
diff --git a/erpnext/accounts/doctype/sales_invoice/pos.py b/erpnext/accounts/doctype/sales_invoice/pos.py
index e290b235a9..7e23793700 100755
--- a/erpnext/accounts/doctype/sales_invoice/pos.py
+++ b/erpnext/accounts/doctype/sales_invoice/pos.py
@@ -227,8 +227,8 @@ def get_contacts(customers):
customers = [frappe._dict({'name': customers})]
for data in customers:
- contact = frappe.db.sql(""" select email_id, phone, mobile_no from `tabContact`
- where is_primary_contact =1 and name in
+ contact = frappe.db.sql(""" select email_id, phone from `tabContact`
+ where is_primary_contact=1 and name in
(select parent from `tabDynamic Link` where link_doctype = 'Customer' and link_name = %s
and parenttype = 'Contact')""", data.name, as_dict=1)
if contact:
diff --git a/erpnext/accounts/page/pos/pos.js b/erpnext/accounts/page/pos/pos.js
index b5a02d0e49..0e7301204a 100755
--- a/erpnext/accounts/page/pos/pos.js
+++ b/erpnext/accounts/page/pos/pos.js
@@ -816,7 +816,6 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
contact = me.contacts[data.name];
if(reg.test(data.name.toLowerCase())
|| reg.test(data.customer_name.toLowerCase())
- || (contact && reg.test(contact["mobile_no"]))
|| (contact && reg.test(contact["phone"]))
|| (data.customer_group && reg.test(data.customer_group.toLowerCase()))){
return data;
@@ -834,7 +833,6 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
if(contact && !c['phone']) {
c["phone"] = contact["phone"];
c["email_id"] = contact["email_id"];
- c["mobile_no"] = contact["mobile_no"];
}
me.customers_mapper.push({
@@ -844,10 +842,9 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
customer_group: c.customer_group,
territory: c.territory,
phone: contact ? contact["phone"] : '',
- mobile_no: contact ? contact["mobile_no"] : '',
email_id: contact ? contact["email_id"] : '',
searchtext: ['customer_name', 'customer_group', 'name', 'value',
- 'label', 'email_id', 'phone', 'mobile_no']
+ 'label', 'email_id', 'phone']
.map(key => c[key]).join(' ')
.toLowerCase()
});
diff --git a/erpnext/communication/doctype/call_log/call_log.py b/erpnext/communication/doctype/call_log/call_log.py
index 2343632719..35c31a0bf8 100644
--- a/erpnext/communication/doctype/call_log/call_log.py
+++ b/erpnext/communication/doctype/call_log/call_log.py
@@ -73,6 +73,10 @@ def set_caller_information(doc, state):
# contact_name or lead_name
display_name_field = '{}_name'.format(fieldname)
+ # Contact now has all the nos saved in child table
+ if doc.doctype == 'Contact':
+ numbers = [d.phone for d in doc.phone_nos]
+
for number in numbers:
number = strip_number(number)
if not number: continue
diff --git a/erpnext/crm/doctype/opportunity/test_opportunity.py b/erpnext/crm/doctype/opportunity/test_opportunity.py
index 1a9f66ad9a..8f61edf00e 100644
--- a/erpnext/crm/doctype/opportunity/test_opportunity.py
+++ b/erpnext/crm/doctype/opportunity/test_opportunity.py
@@ -45,15 +45,16 @@ class TestOpportunity(unittest.TestCase):
# create new customer and create new contact against 'new.opportunity@example.com'
customer = make_customer(opp_doc.party_name).insert(ignore_permissions=True)
- frappe.get_doc({
+ contact = frappe.get_doc({
"doctype": "Contact",
- "email_id": new_lead_email_id,
"first_name": "_Test Opportunity Customer",
"links": [{
"link_doctype": "Customer",
"link_name": customer.name
}]
- }).insert(ignore_permissions=True)
+ })
+ contact.add_email(new_lead_email_id)
+ contact.insert(ignore_permissions=True)
opp_doc = frappe.get_doc(args).insert(ignore_permissions=True)
self.assertTrue(opp_doc.party_name)
diff --git a/erpnext/erpnext_integrations/doctype/exotel_settings/exotel_settings.py b/erpnext/erpnext_integrations/doctype/exotel_settings/exotel_settings.py
index 77de84ce5c..6a846efad7 100644
--- a/erpnext/erpnext_integrations/doctype/exotel_settings/exotel_settings.py
+++ b/erpnext/erpnext_integrations/doctype/exotel_settings/exotel_settings.py
@@ -3,7 +3,6 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-# import frappe
from frappe.model.document import Document
import requests
import frappe
diff --git a/erpnext/hub_node/legacy.py b/erpnext/hub_node/legacy.py
index 95ada76a6a..85eb1b2bb0 100644
--- a/erpnext/hub_node/legacy.py
+++ b/erpnext/hub_node/legacy.py
@@ -68,12 +68,13 @@ def make_contact(supplier):
contact = frappe.get_doc({
'doctype': 'Contact',
'first_name': supplier.supplier_name,
- 'email_id': supplier.supplier_email,
'is_primary_contact': 1,
'links': [
{'link_doctype': 'Supplier', 'link_name': supplier.supplier_name}
]
- }).insert()
+ })
+ contact.add_email(supplier.supplier_email)
+ contact.insert()
else:
contact = frappe.get_doc('Contact', contact_name)
diff --git a/erpnext/public/js/templates/contact_list.html b/erpnext/public/js/templates/contact_list.html
index 893b4e0ec2..50fbfd9f12 100644
--- a/erpnext/public/js/templates/contact_list.html
+++ b/erpnext/public/js/templates/contact_list.html
@@ -14,20 +14,33 @@
style="margin-top:-3px; margin-right: -5px;">
{%= __("Edit") %}
- {% if (contact_list[i].phone || contact_list[i].mobile_no ||
- contact_list[i].email_id) { %}
+ {% if (contact_list[i].phones || contact_list[i].email_ids) { %}
- {% if(contact_list[i].phone) { %}
- {%= __("Phone") %}: {%= contact_list[i].phone %}
- {% } %}
- {% if(contact_list[i].mobile_no) { %}
- {%= __("Mobile No.") %}: {%= contact_list[i].mobile_no %}
- {% } %}
- {% if(contact_list[i].email_id) { %}
- {%= __("Email Address") %}: {%= contact_list[i].email_id %}
- {% } %}
+ {% if(contact_list[i].phone) { %}
+ {%= __("Phone") %}: {%= contact_list[i].phone %} ({%= __("Primary") %})
+ {% endif %}
+ {% if(contact_list[i].phone_nos) { %}
+ {% for(var j=0, k=contact_list[i].phone_nos.length; j
+ {% } %}
+ {% endif %}
+
+
+ {% if(contact_list[i].email_id) { %}
+ {%= __("Email") %}: {%= contact_list[i].email_id %} ({%= __("Primary") %})
+ {% endif %}
+ {% if(contact_list[i].email_ids) { %}
+ {% for(var j=0, k=contact_list[i].email_ids.length; j
+ {% } %}
+ {% endif %}
{% endif %}
+
+ {% if (contact_list[i].address) { %}
+ {%= __("Address") %}: {%= contact_list[i].address %}
+ {% endif %}
+
{% } %}
{% if(!contact_list.length) { %}
diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py
index c946c47c59..d0b4ba0e65 100644
--- a/erpnext/selling/doctype/customer/customer.py
+++ b/erpnext/selling/doctype/customer/customer.py
@@ -337,14 +337,15 @@ def make_contact(args, is_primary_contact=1):
contact = frappe.get_doc({
'doctype': 'Contact',
'first_name': args.get('name'),
- 'mobile_no': args.get('mobile_no'),
- 'email_id': args.get('email_id'),
'is_primary_contact': is_primary_contact,
'links': [{
'link_doctype': args.get('doctype'),
'link_name': args.get('name')
}]
- }).insert()
+ })
+ contact.add_email(args.get('email_id'))
+ contact.add_phone(args.get('mobile_no'))
+ contact.insert()
return contact
diff --git a/erpnext/selling/doctype/sms_center/sms_center.py b/erpnext/selling/doctype/sms_center/sms_center.py
index bb6ba1ffce..289b045e1c 100644
--- a/erpnext/selling/doctype/sms_center/sms_center.py
+++ b/erpnext/selling/doctype/sms_center/sms_center.py
@@ -31,7 +31,7 @@ class SMSCenter(Document):
self.sales_partner.replace("'", "\'") or " and ifnull(dl.link_name, '') != ''"
if self.send_to in ['All Contact', 'All Customer Contact', 'All Supplier Contact', 'All Sales Partner Contact']:
rec = frappe.db.sql("""select CONCAT(ifnull(c.first_name,''), ' ', ifnull(c.last_name,'')),
- c.mobile_no from `tabContact` c, `tabDynamic Link` dl where ifnull(c.mobile_no,'')!='' and
+ c.phone from `tabContact` c, `tabDynamic Link` dl where ifnull(c.phone,'')!='' and
c.docstatus != 2 and dl.parent = c.name%s""" % where_clause)
elif self.send_to == 'All Lead (Open)':
From e7c7a0e6487ce659428e5f1aefbc8c8af13a0b16 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Mon, 2 Sep 2019 15:59:44 +0530
Subject: [PATCH 390/484] fix: loan application (#18882)
* fix: loan application
* Update loan_application.py
---
erpnext/hr/doctype/loan_application/loan_application.py | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/erpnext/hr/doctype/loan_application/loan_application.py b/erpnext/hr/doctype/loan_application/loan_application.py
index 28d9c43f8e..582bf48bf0 100644
--- a/erpnext/hr/doctype/loan_application/loan_application.py
+++ b/erpnext/hr/doctype/loan_application/loan_application.py
@@ -30,7 +30,7 @@ class LoanApplication(Document):
monthly_interest_rate = flt(self.rate_of_interest) / (12 *100)
if monthly_interest_rate:
min_repayment_amount = self.loan_amount*monthly_interest_rate
- if self.repayment_amount - min_repayment_amount <= 0:
+ if (self.repayment_amount - min_repayment_amount) <= 0:
frappe.throw(_("Repayment Amount must be greater than " \
+ str(flt(min_repayment_amount, 2))))
self.repayment_periods = math.ceil((math.log(self.repayment_amount) -
@@ -58,10 +58,13 @@ def make_loan(source_name, target_doc = None):
doclist = get_mapped_doc("Loan Application", source_name, {
"Loan Application": {
"doctype": "Loan",
+ "field_map": {
+ "repayment_amount": "monthly_repayment_amount"
+ },
"validation": {
"docstatus": ["=", 1]
}
}
}, target_doc)
- return doclist
\ No newline at end of file
+ return doclist
From 8666ecc26f8bdba6346dddab782c44e7198ccfb3 Mon Sep 17 00:00:00 2001
From: deepeshgarg007
Date: Mon, 2 Sep 2019 17:41:12 +0530
Subject: [PATCH 391/484] fix: Purchase receipt test
---
.../stock/doctype/purchase_receipt/test_purchase_receipt.py | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
index d124ae4747..ab9311b480 100644
--- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
@@ -329,6 +329,11 @@ class TestPurchaseReceipt(unittest.TestCase):
location = frappe.db.get_value('Serial No', serial_nos[0].name, 'location')
self.assertEquals(location, "Test Location")
+ frappe.db.set_value("Asset", asset, "purchase_receipt", "")
+ frappe.db.set_value("Purchase Receipt Item", pr.items[0].name, "asset", "")
+
+ pr.load_from_db()
+
pr.cancel()
serial_nos = frappe.get_all('Serial No', {'asset': asset}, 'name') or []
self.assertEquals(len(serial_nos), 0)
From cf901da25d2e17657c1ad21823eb6a6e900b653e Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Mon, 2 Sep 2019 23:18:36 +0530
Subject: [PATCH 392/484] test: create customer credit limit on change
---
.../v12_0/move_credit_limit_to_customer_credit_limit.py | 2 +-
erpnext/selling/doctype/customer/test_customer.py | 5 ++++-
2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/erpnext/patches/v12_0/move_credit_limit_to_customer_credit_limit.py b/erpnext/patches/v12_0/move_credit_limit_to_customer_credit_limit.py
index 6f59b46ee7..ca01c604dd 100644
--- a/erpnext/patches/v12_0/move_credit_limit_to_customer_credit_limit.py
+++ b/erpnext/patches/v12_0/move_credit_limit_to_customer_credit_limit.py
@@ -29,7 +29,7 @@ def move_credit_limit_to_child_table():
companies = frappe.get_all("Company", 'name')
for record in credit_limit_record:
- customer = frappe.get_doc("Customer", customer.name)
+ customer = frappe.get_doc("Customer", record.name)
for company in companies:
customer.append("credit_limit_reference", {
'credit_limit': record.credit_limit,
diff --git a/erpnext/selling/doctype/customer/test_customer.py b/erpnext/selling/doctype/customer/test_customer.py
index e5771b2359..35d1b2cf1c 100644
--- a/erpnext/selling/doctype/customer/test_customer.py
+++ b/erpnext/selling/doctype/customer/test_customer.py
@@ -252,7 +252,10 @@ class TestCustomer(unittest.TestCase):
def test_customer_credit_limit_on_change(self):
outstanding_amt = self.get_customer_outstanding_amount()
customer = frappe.get_doc("Customer", '_Test Customer')
- customer.credit_limit_reference[0].credit_limit = flt(outstanding_amt - 100)
+ customer.append('credit_limit_reference', {'credit_limit': flt(outstanding_amt - 100), 'company': '_Test Company'})
+
+ ''' define new credit limit for same company '''
+ customer.append('credit_limit_reference', {'credit_limit': flt(outstanding_amt - 100), 'company': '_Test Company'})
self.assertRaises(frappe.ValidationError, customer.save)
def test_customer_payment_terms(self):
From 7fa3f3fe98d6fc355cd51595116e0cad32e555ed Mon Sep 17 00:00:00 2001
From: Rohan
Date: Tue, 3 Sep 2019 14:16:12 +0530
Subject: [PATCH 393/484] fix: include start and end date for contract status
(#18866)
---
erpnext/crm/doctype/contract/contract.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/crm/doctype/contract/contract.py b/erpnext/crm/doctype/contract/contract.py
index 64cc97b503..18444cc7e6 100644
--- a/erpnext/crm/doctype/contract/contract.py
+++ b/erpnext/crm/doctype/contract/contract.py
@@ -88,7 +88,7 @@ def get_status(start_date, end_date):
end_date = getdate(end_date)
now_date = getdate(nowdate())
- return "Active" if start_date < now_date < end_date else "Inactive"
+ return "Active" if start_date <= now_date <= end_date else "Inactive"
def update_status_for_contracts():
From c174e4d01a1a6c6d2bd1d2353502d95ffccd5a37 Mon Sep 17 00:00:00 2001
From: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com>
Date: Tue, 3 Sep 2019 14:17:41 +0530
Subject: [PATCH 394/484] fix: Default message from Payment Gateway Account not
fetching (#18848)
---
.../accounts/doctype/payment_request/payment_request.js | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/erpnext/accounts/doctype/payment_request/payment_request.js b/erpnext/accounts/doctype/payment_request/payment_request.js
index a455e74940..e2510f675f 100644
--- a/erpnext/accounts/doctype/payment_request/payment_request.js
+++ b/erpnext/accounts/doctype/payment_request/payment_request.js
@@ -1,7 +1,6 @@
-cur_frm.add_fetch("payment_gateway", "payment_account", "payment_account")
-cur_frm.add_fetch("payment_gateway", "payment_gateway", "payment_gateway")
-cur_frm.add_fetch("payment_gateway", "message", "message")
-cur_frm.add_fetch("payment_gateway", "payment_url_message", "payment_url_message")
+cur_frm.add_fetch("payment_gateway_account", "payment_account", "payment_account")
+cur_frm.add_fetch("payment_gateway_account", "payment_gateway", "payment_gateway")
+cur_frm.add_fetch("payment_gateway_account", "message", "message")
frappe.ui.form.on("Payment Request", "onload", function(frm, dt, dn){
if (frm.doc.reference_doctype) {
From cb44f3a7c345ac42ba1631c7ebe41f26e5474973 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Tue, 3 Sep 2019 14:18:15 +0530
Subject: [PATCH 395/484] fix(purchase-invoice): add rounded total property
setter for purchase invoice (#18841)
---
erpnext/setup/doctype/global_defaults/global_defaults.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/setup/doctype/global_defaults/global_defaults.py b/erpnext/setup/doctype/global_defaults/global_defaults.py
index a39e246c68..fa7bc504b6 100644
--- a/erpnext/setup/doctype/global_defaults/global_defaults.py
+++ b/erpnext/setup/doctype/global_defaults/global_defaults.py
@@ -58,7 +58,7 @@ class GlobalDefaults(Document):
# Make property setters to hide rounded total fields
for doctype in ("Quotation", "Sales Order", "Sales Invoice", "Delivery Note",
- "Supplier Quotation", "Purchase Order"):
+ "Supplier Quotation", "Purchase Order", "Purchase Invoice"):
make_property_setter(doctype, "base_rounded_total", "hidden", self.disable_rounded_total, "Check")
make_property_setter(doctype, "base_rounded_total", "print_hide", 1, "Check")
From 1ab75db0acce6a4071dab999a39da0f851502e30 Mon Sep 17 00:00:00 2001
From: Nabin Hait
Date: Tue, 3 Sep 2019 16:07:46 +0530
Subject: [PATCH 396/484] refactor: Accounts Receivable / Payable report
(#18906)
---
.../accounts_receivable.html | 28 +-
.../accounts_receivable.js | 13 +-
.../accounts_receivable.py | 1228 ++++++++---------
.../test_accounts_receivable.py | 35 +-
.../accounts_receivable_summary.py | 345 ++---
erpnext/selling/doctype/customer/customer.py | 4 +-
6 files changed, 748 insertions(+), 905 deletions(-)
diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.html b/erpnext/accounts/report/accounts_receivable/accounts_receivable.html
index 192b6d7be3..d00bcf643e 100644
--- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.html
+++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.html
@@ -40,7 +40,7 @@
-{% if(filters.show_pdc_in_print) { %}
+{% if(filters.show_future_payments) { %}
{% var balance_row = data.slice(-1).pop();
var range1 = report.columns[11].label;
var range2 = report.columns[12].label;
@@ -122,22 +122,22 @@
{%= __("Date") %}
{%= __("Age (Days)") %}
- {% if(report.report_name === "Accounts Receivable" && filters.show_sales_person_in_print) { %}
+ {% if(report.report_name === "Accounts Receivable" && filters.show_sales_person) { %}
{%= __("Reference") %}
{%= __("Sales Person") %}
{% } else { %}
{%= __("Reference") %}
{% } %}
- {% if(!filters.show_pdc_in_print) { %}
+ {% if(!filters.show_future_payments) { %}
{%= (filters.customer || filters.supplier) ? __("Remarks"): __("Party") %}
{% } %}
{%= __("Invoiced Amount") %}
- {% if(!filters.show_pdc_in_print) { %}
+ {% if(!filters.show_future_payments) { %}
{%= __("Paid Amount") %}
{%= report.report_name === "Accounts Receivable" ? __('Credit Note') : __('Debit Note') %}
{% } %}
{%= __("Outstanding Amount") %}
- {% if(filters.show_pdc_in_print) { %}
+ {% if(filters.show_future_payments) { %}
{% if(report.report_name === "Accounts Receivable") { %}
{%= __("Customer LPO No.") %}
{% } %}
@@ -162,18 +162,18 @@
{%= frappe.datetime.str_to_user(data[i]["posting_date"]) %}
{%= data[i][__("Age (Days)")] %}
- {% if(!filters.show_pdc_in_print) { %}
+ {% if(!filters.show_future_payments) { %}
{%= data[i]["voucher_type"] %}
{% } %}
{%= data[i]["voucher_no"] %}
- {% if(report.report_name === "Accounts Receivable" && filters.show_sales_person_in_print) { %}
+ {% if(report.report_name === "Accounts Receivable" && filters.show_sales_person) { %}
{%= data[i]["sales_person"] %}
{% } %}
- {% if(!filters.show_pdc_in_print) { %}
+ {% if(!filters.show_future_payments) { %}
{% if(!(filters.customer || filters.supplier)) { %}
{%= data[i][__("Customer")] || data[i][__("Supplier")] %}
@@ -195,7 +195,7 @@
{%= format_currency(data[i]["invoiced_amount"], data[i]["currency"]) %}
- {% if(!filters.show_pdc_in_print) { %}
+ {% if(!filters.show_future_payments) { %}
{%= format_currency(data[i]["paid_amount"], data[i]["currency"]) %}
@@ -204,7 +204,7 @@
{%= format_currency(data[i]["outstanding_amount"], data[i]["currency"]) %}
- {% if(filters.show_pdc_in_print) { %}
+ {% if(filters.show_future_payments) { %}
{% if(report.report_name === "Accounts Receivable") { %}
{%= data[i]["po_no"] %}
@@ -215,10 +215,10 @@
{% } %}
{% } else { %}
- {% if(!filters.show_pdc_in_print) { %}
+ {% if(!filters.show_future_payments) { %}
{% } %}
- {% if(report.report_name === "Accounts Receivable" && filters.show_sales_person_in_print) { %}
+ {% if(report.report_name === "Accounts Receivable" && filters.show_sales_person) { %}
{% } %}
@@ -226,7 +226,7 @@
{%= format_currency(data[i]["invoiced_amount"], data[i]["currency"] ) %}
- {% if(!filters.show_pdc_in_print) { %}
+ {% if(!filters.show_future_payments) { %}
{%= format_currency(data[i]["paid_amount"], data[i]["currency"]) %}
{%= report.report_name === "Accounts Receivable" ? format_currency(data[i]["credit_note"], data[i]["currency"]) : format_currency(data[i]["debit_note"], data[i]["currency"]) %}
@@ -234,7 +234,7 @@
{%= format_currency(data[i]["outstanding_amount"], data[i]["currency"]) %}
- {% if(filters.show_pdc_in_print) { %}
+ {% if(filters.show_future_payments) { %}
{% if(report.report_name === "Accounts Receivable") { %}
{%= data[i][__("Customer LPO")] %}
diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.js b/erpnext/accounts/report/accounts_receivable/accounts_receivable.js
index 4551973ac6..228be18d21 100644
--- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.js
+++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.js
@@ -130,13 +130,18 @@ frappe.query_reports["Accounts Receivable"] = {
"fieldtype": "Check",
},
{
- "fieldname":"show_pdc_in_print",
- "label": __("Show PDC in Print"),
+ "fieldname":"show_future_payments",
+ "label": __("Show Future Payments"),
"fieldtype": "Check",
},
{
- "fieldname":"show_sales_person_in_print",
- "label": __("Show Sales Person in Print"),
+ "fieldname":"show_delivery_notes",
+ "label": __("Show Delivery Notes"),
+ "fieldtype": "Check",
+ },
+ {
+ "fieldname":"show_sales_person",
+ "label": __("Show Sales Person"),
"fieldtype": "Check",
},
{
diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
index 0e4ee12548..88e4227837 100755
--- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
+++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
@@ -4,9 +4,33 @@
from __future__ import unicode_literals
import frappe, erpnext
from frappe import _, scrub
-from frappe.utils import getdate, nowdate, flt, cint, formatdate, cstr
+from frappe.utils import getdate, nowdate, flt, cint, formatdate, cstr, now, time_diff_in_seconds
+from collections import OrderedDict
+from erpnext.accounts.utils import get_currency_precision
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions
+# This report gives a summary of all Outstanding Invoices considering the following
+
+# 1. Invoice can be booked via Sales/Purchase Invoice or Journal Entry
+# 2. Report handles both receivable and payable
+# 3. Key balances for each row are "Invoiced Amount", "Paid Amount", "Credit/Debit Note Amount", "Oustanding Amount"
+# 4. For explicit payment terms in invoice (example: 30% advance, 30% on delivery, 40% post delivery),
+# the invoice will be broken up into multiple rows, one for each payment term
+# 5. If there are payments after the report date (post dated), these will be updated in additional columns
+# for future amount
+# 6. Configurable Ageing Groups (0-30, 30-60 etc) can be set via filters
+# 7. For overpayment against an invoice with payment terms, there will be an additional row
+# 8. Invoice details like Sales Persons, Delivery Notes are also fetched comma separated
+# 9. Report amounts are in "Party Currency" if party is selected, or company currency for multi-party
+# 10. This reports is based on all GL Entries that are made against account_type "Receivable" or "Payable"
+
+def execute(filters=None):
+ args = {
+ "party_type": "Customer",
+ "naming_by": ["Selling Settings", "cust_master_name"],
+ }
+ return ReceivablePayableReport(filters).run(args)
+
class ReceivablePayableReport(object):
def __init__(self, filters=None):
self.filters = frappe._dict(filters or {})
@@ -16,459 +40,429 @@ class ReceivablePayableReport(object):
else self.filters.report_date
def run(self, args):
- party_naming_by = frappe.db.get_value(args.get("naming_by")[0], None, args.get("naming_by")[1])
- columns = self.get_columns(party_naming_by, args)
- data = self.get_data(party_naming_by, args)
- chart = self.get_chart_data(columns, data)
- return columns, data, None, chart
-
- def get_columns(self, party_naming_by, args):
- columns = []
- columns.append({
- "label": _("Posting Date"),
- "fieldtype": "Date",
- "fieldname": "posting_date",
- "width": 90
- })
-
- columns += [_(args.get("party_type")) + ":Link/" + args.get("party_type") + ":200"]
-
- if party_naming_by == "Naming Series":
- columns += [args.get("party_type") + " Name::110"]
-
- if args.get("party_type") == 'Customer':
- columns.append({
- "label": _("Customer Contact"),
- "fieldtype": "Link",
- "fieldname": "contact",
- "options":"Contact",
- "width": 100
- })
-
- columns.append({
- "label": _("Voucher Type"),
- "fieldtype": "Data",
- "fieldname": "voucher_type",
- "width": 110
- })
-
- columns.append({
- "label": _("Voucher No"),
- "fieldtype": "Dynamic Link",
- "fieldname": "voucher_no",
- "width": 110,
- "options": "voucher_type",
- })
-
- columns += [_("Due Date") + ":Date:80"]
-
- if args.get("party_type") == "Supplier":
- columns += [_("Bill No") + "::80", _("Bill Date") + ":Date:80"]
-
- credit_or_debit_note = "Credit Note" if args.get("party_type") == "Customer" else "Debit Note"
-
- if self.filters.based_on_payment_terms:
- columns.append({
- "label": _("Payment Term"),
- "fieldname": "payment_term",
- "fieldtype": "Data",
- "width": 120
- })
- columns.append({
- "label": _("Invoice Grand Total"),
- "fieldname": "invoice_grand_total",
- "fieldtype": "Currency",
- "options": "currency",
- "width": 120
- })
-
- for label in ("Invoiced Amount", "Paid Amount", credit_or_debit_note, "Outstanding Amount"):
- columns.append({
- "label": _(label),
- "fieldname": frappe.scrub(label),
- "fieldtype": "Currency",
- "options": "currency",
- "width": 120
- })
-
- columns += [_("Age (Days)") + ":Int:80"]
-
- self.ageing_col_idx_start = len(columns)
-
- if not "range1" in self.filters:
- self.filters["range1"] = "30"
- if not "range2" in self.filters:
- self.filters["range2"] = "60"
- if not "range3" in self.filters:
- self.filters["range3"] = "90"
- if not "range4" in self.filters:
- self.filters["range4"] = "120"
-
- for label in ("0-{range1}".format(range1=self.filters["range1"]),
- "{range1}-{range2}".format(range1=cint(self.filters["range1"])+ 1, range2=self.filters["range2"]),
- "{range2}-{range3}".format(range2=cint(self.filters["range2"])+ 1, range3=self.filters["range3"]),
- "{range3}-{range4}".format(range3=cint(self.filters["range3"])+ 1, range4=self.filters["range4"]),
- "{range4}-{above}".format(range4=cint(self.filters["range4"])+ 1, above=_("Above"))):
- columns.append({
- "label": label,
- "fieldname":label,
- "fieldtype": "Currency",
- "options": "currency",
- "width": 120
- })
-
- columns += [
- {
- "fieldname": "currency",
- "label": _("Currency"),
- "fieldtype": "Link",
- "options": "Currency",
- "width": 100
- },
- {
- "fieldname": "pdc/lc_ref",
- "label": _("PDC/LC Ref"),
- "fieldtype": "Data",
- "width": 110
- },
- {
- "fieldname": "pdc/lc_amount",
- "label": _("PDC/LC Amount"),
- "fieldtype": "Currency",
- "options": "currency",
- "width": 130
- },
- {
- "fieldname": "remaining_balance",
- "label": _("Remaining Balance"),
- "fieldtype": "Currency",
- "options": "currency",
- "width": 130
- }]
-
- if args.get('party_type') == 'Customer':
- columns += [
- {
- "label": _("Customer LPO"),
- "fieldtype": "Data",
- "fieldname": "po_no",
- "width": 100,
- },
- _("Delivery Note") + ":Data:100",
- _("Territory") + ":Link/Territory:80",
- _("Customer Group") + ":Link/Customer Group:120",
- {
- "label": _("Sales Person"),
- "fieldtype": "Data",
- "fieldname": "sales_person",
- "width": 120,
- }
- ]
- if args.get("party_type") == "Supplier":
- columns += [_("Supplier Group") + ":Link/Supplier Group:80"]
-
- columns.append(_("Remarks") + "::200")
-
- return columns
-
- def get_data(self, party_naming_by, args):
- from erpnext.accounts.utils import get_currency_precision
- self.currency_precision = get_currency_precision() or 2
- self.dr_or_cr = "debit" if args.get("party_type") == "Customer" else "credit"
-
- future_vouchers = self.get_entries_after(self.filters.report_date, args.get("party_type"))
+ self.filters.update(args)
+ self.set_defaults()
+ self.party_naming_by = frappe.db.get_value(args.get("naming_by")[0], None, args.get("naming_by")[1])
+ self.get_columns()
+ self.get_data()
+ self.get_chart_data()
+ return self.columns, self.data, None, self.chart
+ def set_defaults(self):
if not self.filters.get("company"):
- self.filters["company"] = frappe.db.get_single_value('Global Defaults', 'default_company')
-
+ self.filters.company = frappe.db.get_single_value('Global Defaults', 'default_company')
self.company_currency = frappe.get_cached_value('Company', self.filters.get("company"), "default_currency")
+ self.currency_precision = get_currency_precision() or 2
+ self.dr_or_cr = "debit" if self.filters.party_type == "Customer" else "credit"
+ self.party_type = self.filters.party_type
+ self.party_details = {}
+ self.invoices = set()
- return_entries = self.get_return_entries(args.get("party_type"))
+ def get_data(self):
+ t1 = now()
+ self.get_gl_entries()
+ self.voucher_balance = OrderedDict()
+ self.init_voucher_balance() # invoiced, paid, credit_note, outstanding
- data = []
- self.pdc_details = get_pdc_details(args.get("party_type"), self.filters.report_date)
- gl_entries_data = self.get_entries_till(self.filters.report_date, args.get("party_type"))
+ # Build delivery note map against all sales invoices
+ self.build_delivery_note_map()
- if gl_entries_data:
- voucher_nos = [d.voucher_no for d in gl_entries_data] or []
- dn_details = get_dn_details(args.get("party_type"), voucher_nos)
- self.voucher_details = get_voucher_details(args.get("party_type"), voucher_nos, dn_details)
+ # Get invoice details like bill_no, due_date etc for all invoices
+ self.get_invoice_details()
- if self.filters.based_on_payment_terms and gl_entries_data:
- self.payment_term_map = self.get_payment_term_detail(voucher_nos)
+ # fetch future payments against invoices
+ self.get_future_payments()
- self.gle_inclusion_map = {}
- for gle in gl_entries_data:
- if self.is_receivable_or_payable(gle, self.dr_or_cr, future_vouchers, return_entries):
- self.gle_inclusion_map[gle.name] = True
- outstanding_amount, credit_note_amount, payment_amount = self.get_outstanding_amount(
- gle,self.filters.report_date, self.dr_or_cr, return_entries)
- temp_outstanding_amt = outstanding_amount
- temp_credit_note_amt = credit_note_amount
+ self.data = []
+ for gle in self.gl_entries:
+ self.update_voucher_balance(gle)
- if abs(outstanding_amount) > 0.1/10**self.currency_precision:
- if self.filters.based_on_payment_terms and self.payment_term_map.get(gle.voucher_no):
- for d in self.payment_term_map.get(gle.voucher_no):
- # Allocate payment amount based on payment terms(FIFO order)
- payment_amount, d.payment_amount = self.allocate_based_on_fifo(payment_amount, d.payment_term_amount)
+ self.build_data()
- term_outstanding_amount = d.payment_term_amount - d.payment_amount
+ def init_voucher_balance(self):
+ # build all keys, since we want to exclude vouchers beyond the report date
+ for gle in self.gl_entries:
+ # get the balance object for voucher_type
+ key = (gle.voucher_type, gle.voucher_no, gle.party)
+ if not key in self.voucher_balance:
+ self.voucher_balance[key] = frappe._dict(
+ voucher_type = gle.voucher_type,
+ voucher_no = gle.voucher_no,
+ party = gle.party,
+ posting_date = gle.posting_date,
+ remarks = gle.remarks,
+ invoiced = 0.0,
+ paid = 0.0,
+ credit_note = 0.0,
+ outstanding = 0.0
+ )
+ self.get_invoices(gle)
- # Allocate credit note based on payment terms(FIFO order)
- credit_note_amount, d.credit_note_amount = self.allocate_based_on_fifo(credit_note_amount, term_outstanding_amount)
+ def get_invoices(self, gle):
+ if gle.voucher_type in ('Sales Invoice', 'Purchase Invoice'):
+ self.invoices.add(gle.voucher_no)
- term_outstanding_amount -= d.credit_note_amount
-
- row_outstanding = term_outstanding_amount
- # Allocate PDC based on payment terms(FIFO order)
- d.pdc_details, d.pdc_amount = self.allocate_pdc_amount_in_fifo(gle, row_outstanding)
-
- if term_outstanding_amount > 0:
- row = self.prepare_row(party_naming_by, args, gle, term_outstanding_amount,
- d.credit_note_amount, d.due_date, d.payment_amount , d.payment_term_amount,
- d.description, d.pdc_amount, d.pdc_details)
- data.append(row)
-
- if credit_note_amount:
- row = self.prepare_row_without_payment_terms(party_naming_by, args, gle, temp_outstanding_amt,
- temp_credit_note_amt)
- data.append(row)
-
- else:
- row = self.prepare_row_without_payment_terms(party_naming_by, args, gle, outstanding_amount,
- credit_note_amount)
- data.append(row)
- return data
-
- def allocate_pdc_amount_in_fifo(self, gle, row_outstanding):
- pdc_list = self.pdc_details.get((gle.voucher_no, gle.party), [])
-
- pdc_details = []
- pdc_amount = 0
- for pdc in pdc_list:
- if row_outstanding <= pdc.pdc_amount:
- pdc_amount += row_outstanding
- pdc.pdc_amount -= row_outstanding
- if row_outstanding and pdc.pdc_ref and pdc.pdc_date:
- pdc_details.append(cstr(pdc.pdc_ref) + "/" + formatdate(pdc.pdc_date))
- row_outstanding = 0
+ def update_voucher_balance(self, gle):
+ # get the row where this balance needs to be updated
+ # if its a payment, it will return the linked invoice or will be considered as advance
+ row = self.get_voucher_balance(gle)
+ # gle_balance will be the total "debit - credit" for receivable type reports and
+ # and vice-versa for payable type reports
+ gle_balance = self.get_gle_balance(gle)
+ if gle_balance > 0:
+ if gle.voucher_type in ('Journal Entry', 'Payment Entry') and gle.against_voucher:
+ # debit against sales / purchase invoice
+ row.paid -= gle_balance
else:
- pdc_amount = pdc.pdc_amount
- if pdc.pdc_amount and pdc.pdc_ref and pdc.pdc_date:
- pdc_details.append(cstr(pdc.pdc_ref) + "/" + formatdate(pdc.pdc_date))
- pdc.pdc_amount = 0
- row_outstanding -= pdc_amount
-
- return pdc_details, pdc_amount
-
- def prepare_row_without_payment_terms(self, party_naming_by, args, gle, outstanding_amount, credit_note_amount):
- pdc_list = self.pdc_details.get((gle.voucher_no, gle.party), [])
- pdc_amount = 0
- pdc_details = []
- for d in pdc_list:
- pdc_amount += flt(d.pdc_amount)
- if pdc_amount and d.pdc_ref and d.pdc_date:
- pdc_details.append(cstr(d.pdc_ref) + "/" + formatdate(d.pdc_date))
-
- row = self.prepare_row(party_naming_by, args, gle, outstanding_amount,
- credit_note_amount, pdc_amount=pdc_amount, pdc_details=pdc_details)
-
- return row
-
-
- def allocate_based_on_fifo(self, total_amount, row_amount):
- allocated_amount = 0
- if row_amount <= total_amount:
- allocated_amount = row_amount
- total_amount -= row_amount
+ # invoice
+ row.invoiced += gle_balance
else:
- allocated_amount = total_amount
- total_amount = 0
+ # payment or credit note for receivables
+ if self.is_invoice(gle):
+ # stand alone debit / credit note
+ row.credit_note -= gle_balance
+ else:
+ # advance / unlinked payment or other adjustment
+ row.paid -= gle_balance
- return total_amount, allocated_amount
+ def get_voucher_balance(self, gle):
+ voucher_balance = None
- def prepare_row(self, party_naming_by, args, gle, outstanding_amount, credit_note_amount,
- due_date=None, paid_amt=None, payment_term_amount=None, payment_term=None, pdc_amount=None, pdc_details=None):
- row = [gle.posting_date, gle.party]
+ if gle.against_voucher:
+ # find invoice
+ voucher_balance = self.voucher_balance.get((gle.against_voucher_type, gle.against_voucher, gle.party))
- # customer / supplier name
- if party_naming_by == "Naming Series":
- row += [self.get_party_name(gle.party_type, gle.party)]
+ if not voucher_balance:
+ # no invoice, this is an invoice / stand-alone payment / credit note
+ voucher_balance = self.voucher_balance.get((gle.voucher_type, gle.voucher_no, gle.party))
- if args.get("party_type") == 'Customer':
- row += [self.get_customer_contact(gle.party_type, gle.party)]
+ return voucher_balance
- # get due date
- if not due_date:
- due_date = self.voucher_details.get(gle.voucher_no, {}).get("due_date", "")
- bill_date = self.voucher_details.get(gle.voucher_no, {}).get("bill_date", "")
+ def build_data(self):
+ # set outstanding for all the accumulated balances
+ # as we can use this to filter out invoices without outstanding
+ for key, row in self.voucher_balance.items():
+ row.outstanding = flt(row.invoiced - row.paid - row.credit_note, self.currency_precision)
+ row.invoice_grand_total = row.invoiced
- row += [gle.voucher_type, gle.voucher_no, due_date]
+ if abs(row.outstanding) > 0.1/10 ** self.currency_precision:
+ # non-zero oustanding, we must consider this row
- # get supplier bill details
- if args.get("party_type") == "Supplier":
- row += [
- self.voucher_details.get(gle.voucher_no, {}).get("bill_no", ""),
- self.voucher_details.get(gle.voucher_no, {}).get("bill_date", "")
- ]
+ if self.is_invoice(row) and self.filters.based_on_payment_terms:
+ # is an invoice, allocate based on fifo
+ # adds a list `payment_terms` which contains new rows for each term
+ self.allocate_outstanding_based_on_payment_terms(row)
- # invoiced and paid amounts
- invoiced_amount = gle.get(self.dr_or_cr) if (gle.get(self.dr_or_cr) > 0) else 0
+ if row.payment_terms:
+ # make separate rows for each payment term
+ for d in row.payment_terms:
+ if d.outstanding > 0:
+ self.append_row(d)
- if self.filters.based_on_payment_terms:
- row+=[payment_term, invoiced_amount]
- if payment_term_amount:
- invoiced_amount = payment_term_amount
-
- if not payment_term_amount:
- paid_amt = invoiced_amount - outstanding_amount - credit_note_amount
- row += [invoiced_amount, paid_amt, credit_note_amount, outstanding_amount]
-
- # ageing data
- if self.filters.ageing_based_on == "Due Date":
- entry_date = due_date
- elif self.filters.ageing_based_on == "Supplier Invoice Date":
- entry_date = bill_date
- else:
- entry_date = gle.posting_date
-
- row += get_ageing_data(cint(self.filters.range1), cint(self.filters.range2),
- cint(self.filters.range3), cint(self.filters.range4), self.age_as_on, entry_date, outstanding_amount)
-
- # issue 6371-Ageing buckets should not have amounts if due date is not reached
- if self.filters.ageing_based_on == "Due Date" \
- and getdate(due_date) > getdate(self.filters.report_date):
- row[-1]=row[-2]=row[-3]=row[-4]=row[-5]=0
-
- if self.filters.ageing_based_on == "Supplier Invoice Date" \
- and getdate(bill_date) > getdate(self.filters.report_date):
-
- row[-1]=row[-2]=row[-3]=row[-4]=row[-5]=0
-
- if self.filters.get(scrub(args.get("party_type"))):
- row.append(gle.account_currency)
- else:
- row.append(self.company_currency)
-
- remaining_balance = outstanding_amount - flt(pdc_amount)
- pdc_details = ", ".join(pdc_details)
- row += [pdc_details, pdc_amount, remaining_balance]
-
- if args.get('party_type') == 'Customer':
- # customer LPO
- row += [self.voucher_details.get(gle.voucher_no, {}).get("po_no")]
-
- # Delivery Note
- row += [self.voucher_details.get(gle.voucher_no, {}).get("delivery_note")]
-
- # customer territory / supplier group
- if args.get("party_type") == "Customer":
- row += [self.get_territory(gle.party), self.get_customer_group(gle.party),
- self.voucher_details.get(gle.voucher_no, {}).get("sales_person")]
- if args.get("party_type") == "Supplier":
- row += [self.get_supplier_group(gle.party)]
-
- row.append(gle.remarks)
-
- return row
-
- def get_entries_after(self, report_date, party_type):
- # returns a distinct list
- return list(set([(e.voucher_type, e.voucher_no) for e in self.get_gl_entries(party_type, report_date, for_future=True)]))
-
- def get_entries_till(self, report_date, party_type):
- # returns a generator
- return self.get_gl_entries(party_type, report_date)
-
- def is_receivable_or_payable(self, gle, dr_or_cr, future_vouchers, return_entries):
- return (
- # advance
- (not gle.against_voucher) or
-
- # against sales order/purchase order
- (gle.against_voucher_type in ["Sales Order", "Purchase Order"]) or
-
- # sales invoice/purchase invoice
- (gle.against_voucher==gle.voucher_no and gle.get(dr_or_cr) > 0) or
-
- # standalone credit notes
- (gle.against_voucher==gle.voucher_no and gle.voucher_no in return_entries and not return_entries.get(gle.voucher_no)) or
-
- # entries adjusted with future vouchers
- ((gle.against_voucher_type, gle.against_voucher) in future_vouchers)
- )
-
- def get_return_entries(self, party_type):
- doctype = "Sales Invoice" if party_type=="Customer" else "Purchase Invoice"
- return_entries = frappe._dict(frappe.get_all(doctype,
- filters={"is_return": 1, "docstatus": 1}, fields=["name", "return_against"], as_list=1))
- return return_entries
-
- def get_outstanding_amount(self, gle, report_date, dr_or_cr, return_entries):
- payment_amount, credit_note_amount = 0.0, 0.0
- reverse_dr_or_cr = "credit" if dr_or_cr=="debit" else "debit"
- for e in self.get_gl_entries_for(gle.party, gle.party_type, gle.voucher_type, gle.voucher_no):
- if getdate(e.posting_date) <= report_date \
- and (e.name!=gle.name or (e.voucher_no in return_entries and not return_entries.get(e.voucher_no))):
- if e.name!=gle.name and self.gle_inclusion_map.get(e.name):
- continue
- self.gle_inclusion_map[e.name] = True
- amount = flt(e.get(reverse_dr_or_cr), self.currency_precision) - flt(e.get(dr_or_cr), self.currency_precision)
- if e.voucher_no not in return_entries:
- payment_amount += amount
+ # if there is overpayment, add another row
+ self.allocate_extra_payments_or_credits(row)
+ else:
+ self.append_row(row)
else:
- credit_note_amount += amount
+ self.append_row(row)
- voucher_amount = flt(gle.get(dr_or_cr), self.currency_precision) - flt(gle.get(reverse_dr_or_cr), self.currency_precision)
- if gle.voucher_no in return_entries and not return_entries.get(gle.voucher_no):
- voucher_amount = 0
+ def append_row(self, row):
+ self.allocate_future_payments(row)
+ self.set_invoice_details(row)
+ self.set_party_details(row)
+ self.set_ageing(row)
+ self.data.append(row)
- outstanding_amount = flt((voucher_amount - payment_amount - credit_note_amount), self.currency_precision)
- credit_note_amount = flt(credit_note_amount, self.currency_precision)
+ def set_invoice_details(self, row):
+ row.update(self.invoice_details.get(row.voucher_no, {}))
+ if row.voucher_type == 'Sales Invoice':
+ if self.filters.show_delivery_notes:
+ self.set_delivery_notes(row)
- return outstanding_amount, credit_note_amount, payment_amount
+ if self.filters.show_sales_person and row.sales_team:
+ row.sales_person = ", ".join(row.sales_team)
+ del row['sales_team']
- def get_party_name(self, party_type, party_name):
- return self.get_party_map(party_type).get(party_name, {}).get("customer_name" if party_type == "Customer" else "supplier_name") or ""
+ def set_delivery_notes(self, row):
+ delivery_notes = self.delivery_notes.get(row.voucher_no, [])
+ if delivery_notes:
+ row.delivery_notes = ', '.join(delivery_notes)
- def get_customer_contact(self, party_type, party_name):
- return self.get_party_map(party_type).get(party_name, {}).get("customer_primary_contact")
+ def build_delivery_note_map(self):
+ if self.invoices and self.filters.show_delivery_notes:
+ self.delivery_notes = frappe._dict()
- def get_territory(self, party_name):
- return self.get_party_map("Customer").get(party_name, {}).get("territory") or ""
+ # delivery note link inside sales invoice
+ si_against_dn = frappe.db.sql("""
+ select parent, delivery_note
+ from `tabSales Invoice Item`
+ where docstatus=1 and parent in (%s)
+ """ % (','.join(['%s'] * len(self.invoices))), tuple(self.invoices), as_dict=1)
- def get_customer_group(self, party_name):
- return self.get_party_map("Customer").get(party_name, {}).get("customer_group") or ""
+ for d in si_against_dn:
+ if d.delivery_note:
+ self.delivery_notes.setdefault(d.parent, set()).add(d.delivery_note)
- def get_supplier_group(self, party_name):
- return self.get_party_map("Supplier").get(party_name, {}).get("supplier_group") or ""
+ dn_against_si = frappe.db.sql("""
+ select distinct parent, against_sales_invoice
+ from `tabDelivery Note Item`
+ where against_sales_invoice in (%s)
+ """ % (','.join(['%s'] * len(self.invoices))), tuple(self.invoices) , as_dict=1)
- def get_party_map(self, party_type):
- if not hasattr(self, "party_map"):
- if party_type == "Customer":
- select_fields = "name, customer_name, territory, customer_group, customer_primary_contact"
- elif party_type == "Supplier":
- select_fields = "name, supplier_name, supplier_group"
+ for d in dn_against_si:
+ self.delivery_notes.setdefault(d.against_sales_invoice, set()).add(d.parent)
- self.party_map = dict(((r.name, r) for r in frappe.db.sql("select {0} from `tab{1}`"
- .format(select_fields, party_type), as_dict=True)))
+ def get_invoice_details(self):
+ self.invoice_details = frappe._dict()
+ if self.party_type == "Customer":
+ si_list = frappe.db.sql("""
+ select name, due_date, po_no
+ from `tabSales Invoice`
+ where posting_date <= %s
+ """,self.filters.report_date, as_dict=1)
+ for d in si_list:
+ self.invoice_details.setdefault(d.name, d)
- return self.party_map
+ # Get Sales Team
+ if self.filters.show_sales_person:
+ sales_team = frappe.db.sql("""
+ select parent, sales_person
+ from `tabSales Team`
+ where parenttype = 'Sales Invoice'
+ """, as_dict=1)
+ for d in sales_team:
+ self.invoice_details.setdefault(d.parent, {})\
+ .setdefault('sales_team', []).append(d.sales_person)
- def get_gl_entries(self, party_type, date=None, for_future=False):
- conditions, values = self.prepare_conditions(party_type)
+ if self.party_type == "Supplier":
+ for pi in frappe.db.sql("""
+ select name, due_date, bill_no, bill_date
+ from `tabPurchase Invoice`
+ where posting_date <= %s
+ """, self.filters.report_date, as_dict=1):
+ self.invoice_details.setdefault(pi.name, pi)
- if self.filters.get(scrub(party_type)):
- select_fields = "sum(debit_in_account_currency) as debit, sum(credit_in_account_currency) as credit"
+ # Invoices booked via Journal Entries
+ journal_entries = frappe.db.sql("""
+ select name, due_date, bill_no, bill_date
+ from `tabJournal Entry`
+ where posting_date <= %s
+ """, self.filters.report_date, as_dict=1)
+
+ for je in journal_entries:
+ if je.bill_no:
+ self.invoice_details.setdefault(je.name, je)
+
+ def set_party_details(self, row):
+ # customer / supplier name
+ party_details = self.get_party_details(row.party)
+ row.update(party_details)
+
+ if self.filters.get(scrub(self.filters.party_type)):
+ row.currency = row.account_currency
else:
- select_fields = "sum(debit) as debit, sum(credit) as credit"
+ row.currency = self.company_currency
- if date and not for_future:
- conditions += " and posting_date <= '%s'" % date
+ def allocate_outstanding_based_on_payment_terms(self, row):
+ self.get_payment_terms(row)
+ for term in row.payment_terms:
+ term.outstanding = term.invoiced
- if date and for_future:
- conditions += " and posting_date > '%s'" % date
+ # update "paid" and "oustanding" for this term
+ self.allocate_closing_to_term(row, term, 'paid')
+
+ # update "credit_note" and "oustanding" for this term
+ if term.outstanding:
+ self.allocate_closing_to_term(row, term, 'credit_note')
+
+ def get_payment_terms(self, row):
+ # build payment_terms for row
+ payment_terms_details = frappe.db.sql("""
+ select
+ si.name, si.party_account_currency, si.currency, si.conversion_rate,
+ ps.due_date, ps.payment_amount, ps.description
+ from `tab{0}` si, `tabPayment Schedule` ps
+ where
+ si.name = ps.parent and
+ si.name = %s
+ order by ps.due_date
+ """.format(row.voucher_type), row.voucher_no, as_dict = 1)
+
+
+ original_row = frappe._dict(row)
+ row.payment_terms = []
+
+ # If no or single payment terms, no need to split the row
+ if len(payment_terms_details) <= 1:
+ return
+
+ for d in payment_terms_details:
+ term = frappe._dict(original_row)
+ self.append_payment_term(row, d, term)
+
+ def append_payment_term(self, row, d, term):
+ if self.filters.get("customer") and d.currency == d.party_account_currency:
+ invoiced = d.payment_amount
+ else:
+ invoiced = flt(flt(d.payment_amount) * flt(d.conversion_rate), self.currency_precision)
+
+ row.payment_terms.append(term.update({
+ "due_date": d.due_date,
+ "invoiced": invoiced,
+ "invoice_grand_total": row.invoiced,
+ "payment_term": d.description,
+ "paid": 0.0,
+ "credit_note": 0.0,
+ "outstanding": 0.0
+ }))
+
+ def allocate_closing_to_term(self, row, term, key):
+ if row[key]:
+ if row[key] > term.outstanding:
+ term[key] = term.outstanding
+ row[key] -= term.outstanding
+ else:
+ term[key] = row[key]
+ row[key] = 0
+ term.outstanding -= term[key]
+
+ def allocate_extra_payments_or_credits(self, row):
+ # allocate extra payments / credits
+ additional_row = None
+ for key in ('paid', 'credit_note'):
+ if row[key] > 0:
+ if not additional_row:
+ additional_row = frappe._dict(row)
+ additional_row.invoiced = 0.0
+ additional_row[key] = row[key]
+
+ if additional_row:
+ additional_row.outstanding = additional_row.invoiced - additional_row.paid - additional_row.credit_note
+ self.append_row(additional_row)
+
+ def get_future_payments(self):
+ if self.filters.show_future_payments:
+ self.future_payments = frappe._dict()
+ future_payments = list(self.get_future_payments_from_payment_entry())
+ future_payments += list(self.get_future_payments_from_journal_entry())
+ if future_payments:
+ for d in future_payments:
+ if d.future_amount and d.invoice_no:
+ self.future_payments.setdefault((d.invoice_no, d.party), []).append(d)
+
+ def get_future_payments_from_payment_entry(self):
+ return frappe.db.sql("""
+ select
+ ref.reference_name as invoice_no,
+ payment_entry.party,
+ payment_entry.party_type,
+ payment_entry.posting_date as future_date,
+ ref.allocated_amount as future_amount,
+ payment_entry.reference_no as future_ref
+ from
+ `tabPayment Entry` as payment_entry inner join `tabPayment Entry Reference` as ref
+ on
+ (ref.parent = payment_entry.name)
+ where
+ payment_entry.docstatus = 1
+ and payment_entry.posting_date > %s
+ and payment_entry.party_type = %s
+ """, (self.filters.report_date, self.party_type), as_dict=1)
+
+ def get_future_payments_from_journal_entry(self):
+ if self.filters.get('party'):
+ amount_field = ("jea.debit_in_account_currency - jea.credit_in_account_currency"
+ if self.party_type == 'Supplier' else "jea.credit_in_account_currency - jea.debit_in_account_currency")
+ else:
+ amount_field = ("jea.debit - " if self.party_type == 'Supplier' else "jea.credit")
+
+ return frappe.db.sql("""
+ select
+ jea.reference_name as invoice_no,
+ jea.party,
+ jea.party_type,
+ je.posting_date as future_date,
+ sum({0}) as future_amount,
+ je.cheque_no as future_ref
+ from
+ `tabJournal Entry` as je inner join `tabJournal Entry Account` as jea
+ on
+ (jea.parent = je.name)
+ where
+ je.docstatus = 1
+ and je.posting_date > %s
+ and jea.party_type = %s
+ and jea.reference_name is not null and jea.reference_name != ''
+ group by je.name, jea.reference_name
+ having future_amount > 0
+ """.format(amount_field), (self.filters.report_date, self.party_type), as_dict=1)
+
+ def allocate_future_payments(self, row):
+ # future payments are captured in additional columns
+ # this method allocates pending future payments against a voucher to
+ # the current row (which could be generated from payment terms)
+ if not self.filters.show_future_payments:
+ return
+
+ row.remaining_balance = row.outstanding
+ row.future_amount = 0.0
+ for future in self.future_payments.get((row.voucher_no, row.party), []):
+ if row.remaining_balance > 0 and future.future_amount:
+ if future.future_amount > row.outstanding:
+ row.future_amount = row.outstanding
+ future.future_amount = future.future_amount - row.outstanding
+ row.remaining_balance = 0
+ else:
+ row.future_amount += future.future_amount
+ future.future_amount = 0
+ row.remaining_balance = row.outstanding - row.future_amount
+
+ row.setdefault('future_ref', []).append(cstr(future.future_ref) + '/' + cstr(future.future_date))
+
+ if row.future_ref:
+ row.future_ref = ', '.join(row.future_ref)
+
+ def set_ageing(self, row):
+ if self.filters.ageing_based_on == "Due Date":
+ entry_date = row.due_date
+ elif self.filters.ageing_based_on == "Supplier Invoice Date":
+ entry_date = row.bill_date
+ else:
+ entry_date = row.posting_date
+
+ self.get_ageing_data(entry_date, row)
+
+ # ageing buckets should not have amounts if due date is not reached
+ if getdate(entry_date) > getdate(self.filters.report_date):
+ row.range1 = row.range2 = row.range3 = row.range4 = row.range5 = 0.0
+
+ def get_ageing_data(self, entry_date, row):
+ # [0-30, 30-60, 60-90, 90-120, 120-above]
+ row.range1 = row.range2 = row.range3 = row.range4 = range5 = 0.0
+
+ if not (self.age_as_on and entry_date):
+ return
+
+ row.age = (getdate(self.age_as_on) - getdate(entry_date)).days or 0
+ index = None
+ for i, days in enumerate([self.filters.range1, self.filters.range2, self.filters.range3, self.filters.range4]):
+ if row.age <= days:
+ index = i
+ break
+
+ if index is None: index = 4
+ row['range' + str(index+1)] = row.outstanding
+
+ def get_gl_entries(self):
+ # get all the GL entries filtered by the given filters
+
+ conditions, values = self.prepare_conditions()
+
+ if self.filters.get(scrub(self.party_type)):
+ select_fields = "debit_in_account_currency as debit, credit_in_account_currency as credit"
+ else:
+ select_fields = "debit, credit"
self.gl_entries = frappe.db.sql("""
select
@@ -477,91 +471,95 @@ class ReceivablePayableReport(object):
from
`tabGL Entry`
where
- docstatus < 2 and party_type=%s and (party is not null and party != '') {1}
- group by voucher_type, voucher_no, against_voucher_type, against_voucher, party
- order by posting_date, party"""
+ docstatus < 2
+ and party_type=%s
+ and (party is not null and party != '')
+ and posting_date <= %s
+ {1}
+ order by posting_date, party"""
.format(select_fields, conditions), values, as_dict=True)
- return self.gl_entries
-
- def prepare_conditions(self, party_type):
+ def prepare_conditions(self):
conditions = [""]
- values = [party_type]
+ values = [self.party_type, self.filters.report_date]
+ party_type_field = scrub(self.party_type)
- party_type_field = scrub(party_type)
+ self.add_common_filters(conditions, values, party_type_field)
+ if party_type_field=="customer":
+ self.add_customer_filters(conditions, values)
+
+ elif party_type_field=="supplier":
+ self.add_supplier_filters(conditions, values)
+
+ self.add_accounting_dimensions_filters()
+
+ return " and ".join(conditions), values
+
+ def add_common_filters(self, conditions, values, party_type_field):
if self.filters.company:
conditions.append("company=%s")
values.append(self.filters.company)
if self.filters.finance_book:
- conditions.append("ifnull(finance_book,'') in (%s, '')")
+ conditions.append("ifnull(finance_book, '') in (%s, '')")
values.append(self.filters.finance_book)
if self.filters.get(party_type_field):
conditions.append("party=%s")
values.append(self.filters.get(party_type_field))
- if party_type_field=="customer":
- account_type = "Receivable"
- if self.filters.get("customer_group"):
- lft, rgt = frappe.db.get_value("Customer Group",
- self.filters.get("customer_group"), ["lft", "rgt"])
+ # get GL with "receivable" or "payable" account_type
+ account_type = "Receivable" if self.party_type == "Customer" else "Payable"
+ accounts = [d.name for d in frappe.get_all("Account",
+ filters={"account_type": account_type, "company": self.filters.company})]
+ conditions.append("account in (%s)" % ','.join(['%s'] *len(accounts)))
+ values += accounts
- conditions.append("""party in (select name from tabCustomer
- where exists(select name from `tabCustomer Group` where lft >= {0} and rgt <= {1}
- and name=tabCustomer.customer_group))""".format(lft, rgt))
+ def add_customer_filters(self, conditions, values):
+ if self.filters.get("customer_group"):
+ conditions.append(self.get_hierarchical_filters('Customer Group', 'customer_group'))
- if self.filters.get("territory"):
- lft, rgt = frappe.db.get_value("Territory",
- self.filters.get("territory"), ["lft", "rgt"])
+ if self.filters.get("territory"):
+ conditions.append(self.get_hierarchical_filters('Territory', 'territory'))
- conditions.append("""party in (select name from tabCustomer
- where exists(select name from `tabTerritory` where lft >= {0} and rgt <= {1}
- and name=tabCustomer.territory))""".format(lft, rgt))
+ if self.filters.get("payment_terms_template"):
+ conditions.append("party in (select name from tabCustomer where payment_terms=%s)")
+ values.append(self.filters.get("payment_terms_template"))
- if self.filters.get("payment_terms_template"):
- conditions.append("party in (select name from tabCustomer where payment_terms=%s)")
- values.append(self.filters.get("payment_terms_template"))
+ if self.filters.get("sales_partner"):
+ conditions.append("party in (select name from tabCustomer where default_sales_partner=%s)")
+ values.append(self.filters.get("sales_partner"))
- if self.filters.get("sales_partner"):
- conditions.append("party in (select name from tabCustomer where default_sales_partner=%s)")
- values.append(self.filters.get("sales_partner"))
+ if self.filters.get("sales_person"):
+ lft, rgt = frappe.db.get_value("Sales Person",
+ self.filters.get("sales_person"), ["lft", "rgt"])
- if self.filters.get("sales_person"):
- lft, rgt = frappe.db.get_value("Sales Person",
- self.filters.get("sales_person"), ["lft", "rgt"])
+ conditions.append("""exists(select name from `tabSales Team` steam where
+ steam.sales_person in (select name from `tabSales Person` where lft >= {0} and rgt <= {1})
+ and ((steam.parent = voucher_no and steam.parenttype = voucher_type)
+ or (steam.parent = against_voucher and steam.parenttype = against_voucher_type)
+ or (steam.parent = party and steam.parenttype = 'Customer')))""".format(lft, rgt))
- conditions.append("""exists(select name from `tabSales Team` steam where
- steam.sales_person in (select name from `tabSales Person` where lft >= {0} and rgt <= {1})
- and ((steam.parent = voucher_no and steam.parenttype = voucher_type)
- or (steam.parent = against_voucher and steam.parenttype = against_voucher_type)
- or (steam.parent = party and steam.parenttype = 'Customer')))""".format(lft, rgt))
+ def add_supplier_filters(self, conditions, values):
+ if self.filters.get("supplier_group"):
+ conditions.append("""party in (select name from tabSupplier
+ where supplier_group=%s)""")
+ values.append(self.filters.get("supplier_group"))
- elif party_type_field=="supplier":
- account_type = "Payable"
- if self.filters.get("supplier_group"):
- conditions.append("""party in (select name from tabSupplier
- where supplier_group=%s)""")
- values.append(self.filters.get("supplier_group"))
+ if self.filters.get("payment_terms_template"):
+ conditions.append("party in (select name from tabSupplier where payment_terms=%s)")
+ values.append(self.filters.get("payment_terms_template"))
- if self.filters.get("payment_terms_template"):
- conditions.append("party in (select name from tabSupplier where payment_terms=%s)")
- values.append(self.filters.get("payment_terms_template"))
+ def get_hierarchical_filters(self, doctype, key):
+ lft, rgt = frappe.db.get_value(doctype, self.filters.get(key), ["lft", "rgt"])
- if self.filters.get("cost_center"):
- lft, rgt = frappe.get_cached_value("Cost Center",
- self.filters.get("cost_center"), ['lft', 'rgt'])
-
- conditions.append("""cost_center in (select name from `tabCost Center` where
- lft >= {0} and rgt <= {1})""".format(lft, rgt))
-
- if self.filters.company:
- accounts = [d.name for d in frappe.get_all("Account",
- filters={"account_type": account_type, "company": self.filters.company})]
- conditions.append("account in (%s)" % ','.join(['%s'] *len(accounts)))
- values += accounts
+ return """party in (select name from tabCustomer
+ where exists(select name from `tab{doctype}` where lft >= {lft} and rgt <= {rgt}
+ and name=tabCustomer.{key}))""".format(
+ doctype=doctype, lft=lft, rgt=rgt, key=key)
+ def add_accounting_dimensions_filters(self, conditions, values):
accounting_dimensions = get_accounting_dimensions()
if accounting_dimensions:
@@ -570,195 +568,133 @@ class ReceivablePayableReport(object):
conditions.append("{0} = %s".format(dimension))
values.append(self.filters.get(dimension))
- return " and ".join(conditions), values
+ def get_gle_balance(self, gle):
+ # get the balance of the GL (debit - credit) or reverse balance based on report type
+ return gle.get(self.dr_or_cr) - self.get_reverse_balance(gle)
- def get_gl_entries_for(self, party, party_type, against_voucher_type, against_voucher):
- if not hasattr(self, "gl_entries_map"):
- self.gl_entries_map = {}
- for gle in self.get_gl_entries(party_type):
- if gle.against_voucher_type and gle.against_voucher:
- self.gl_entries_map.setdefault(gle.party, {})\
- .setdefault(gle.against_voucher_type, {})\
- .setdefault(gle.against_voucher, [])\
- .append(gle)
+ def get_reverse_balance(self, gle):
+ # get "credit" balance if report type is "debit" and vice versa
+ return gle.get('debit' if self.dr_or_cr=='credit' else 'credit')
- return self.gl_entries_map.get(party, {})\
- .get(against_voucher_type, {})\
- .get(against_voucher, [])
+ def is_invoice(self, gle):
+ if gle.voucher_type in ('Sales Invoice', 'Purchase Invoice'):
+ return True
- def get_payment_term_detail(self, voucher_nos):
- payment_term_map = frappe._dict()
- payment_terms_details = frappe.db.sql(""" select si.name,
- party_account_currency, currency, si.conversion_rate,
- ps.due_date, ps.payment_amount, ps.description
- from `tabSales Invoice` si, `tabPayment Schedule` ps
- where si.name = ps.parent and
- si.docstatus = 1 and si.company = %s and
- si.name in (%s) order by ps.due_date
- """ % (frappe.db.escape(self.filters.company), ','.join(['%s'] *len(voucher_nos))),
- (tuple(voucher_nos)), as_dict = 1)
-
- for d in payment_terms_details:
- if self.filters.get("customer") and d.currency == d.party_account_currency:
- payment_term_amount = d.payment_amount
+ def get_party_details(self, party):
+ if not party in self.party_details:
+ if self.party_type == 'Customer':
+ self.party_details[party] = frappe.db.get_value('Customer', party, ['customer_name',
+ 'territory', 'customer_group', 'customer_primary_contact'], as_dict=True)
else:
- payment_term_amount = flt(flt(d.payment_amount) * flt(d.conversion_rate), self.currency_precision)
+ self.party_details[party] = frappe.db.get_value('Supplier', party, ['supplier_name',
+ 'supplier_group'], as_dict=True)
- payment_term_map.setdefault(d.name, []).append(frappe._dict({
- "due_date": d.due_date,
- "payment_term_amount": payment_term_amount,
- "description": d.description
- }))
- return payment_term_map
+ return self.party_details[party]
- def get_chart_data(self, columns, data):
- ageing_columns = columns[self.ageing_col_idx_start : self.ageing_col_idx_start+5]
+ def get_columns(self):
+ self.columns = []
+ self.add_column('Posting Date', fieldtype='Date')
+ self.add_column(label=_(self.party_type), fieldname='party',
+ fieldtype='Link', options=self.party_type, width=180)
+
+ if self.party_naming_by == "Naming Series":
+ self.add_column(_('{0} Name').format(self.party_type),
+ fieldname = scrub(self.party_type) + '_name', fieldtype='Data')
+
+ if self.party_type == 'Customer':
+ self.add_column(_("Customer Contact"), fieldname='customer_primary_contact',
+ fieldtype='Link', options='Contact')
+
+ self.add_column(label=_('Voucher Type'), fieldname='voucher_type', fieldtype='Data')
+ self.add_column(label=_('Voucher No'), fieldname='voucher_no', fieldtype='Dynamic Link',
+ options='voucher_type', width=180)
+ self.add_column(label='Due Date', fieldtype='Date')
+
+ if self.party_type == "Supplier":
+ self.add_column(label=_('Bill No'), fieldname='bill_no', fieldtype='Data')
+ self.add_column(label=_('Bill Date'), fieldname='bill_date', fieldtype='Date')
+
+ if self.filters.based_on_payment_terms:
+ self.add_column(label=_('Payment Term'), fieldname='payment_term', fieldtype='Data')
+ self.add_column(label=_('Invoice Grand Total'), fieldname='invoice_grand_total')
+
+ self.add_column(_('Invoiced Amount'), fieldname='invoiced')
+ self.add_column(_('Paid Amount'), fieldname='paid')
+ if self.party_type == "Customer":
+ self.add_column(_('Credit Note'), fieldname='credit_note')
+ else:
+ # note: fieldname is still `credit_note`
+ self.add_column(_('Debit Note'), fieldname='credit_note')
+ self.add_column(_('Outstanding Amount'), fieldname='outstanding')
+
+ self.setup_ageing_columns()
+
+ self.add_column(label=_('Currency'), fieldname='currency', fieldtype='Link', options='Currency', width=80)
+
+ if self.filters.show_future_payments:
+ self.add_column(label=_('Future Payment Ref'), fieldname='future_ref', fieldtype='Data')
+ self.add_column(label=_('Future Payment Amount'), fieldname='future_amount')
+ self.add_column(label=_('Remaining Balance'), fieldname='remaining_balance')
+
+ if self.filters.party_type == 'Customer':
+ self.add_column(label=_('Customer LPO'), fieldname='po_no', fieldtype='Data')
+
+ # comma separated list of linked delivery notes
+ if self.filters.show_delivery_notes:
+ self.add_column(label=_('Delivery Notes'), fieldname='delivery_notes', fieldtype='Data')
+ self.add_column(label=_('Territory'), fieldname='territory', fieldtype='Link',
+ options='Territory')
+ self.add_column(label=_('Customer Group'), fieldname='customer_group', fieldtype='Link',
+ options='Customer Group')
+ if self.filters.show_sales_person:
+ self.add_column(label=_('Sales Person'), fieldname='sales_person', fieldtype='Data')
+
+ if self.filters.party_type == "Supplier":
+ self.add_column(label=_('Supplier Group'), fieldname='supplier_group', fieldtype='Link',
+ options='Supplier Group')
+
+ self.add_column(label=_('Remarks'), fieldname='remarks', fieldtype='Text', width=200)
+
+ def add_column(self, label, fieldname=None, fieldtype='Currency', options=None, width=120):
+ if not fieldname: fieldname = scrub(label)
+ if fieldtype=='Currency': options='currency'
+ if fieldtype=='Date': width = 90
+
+ self.columns.append(dict(
+ label=label,
+ fieldname=fieldname,
+ fieldtype=fieldtype,
+ options=options,
+ width=width
+ ))
+
+ def setup_ageing_columns(self):
+ # for charts
+ self.ageing_column_labels = []
+ self.add_column(label=_('Age (Days)'), fieldname='age', fieldtype='Int', width=80)
+
+ for i, label in enumerate(["0-{range1}".format(range1=self.filters["range1"]),
+ "{range1}-{range2}".format(range1=cint(self.filters["range1"])+ 1, range2=self.filters["range2"]),
+ "{range2}-{range3}".format(range2=cint(self.filters["range2"])+ 1, range3=self.filters["range3"]),
+ "{range3}-{range4}".format(range3=cint(self.filters["range3"])+ 1, range4=self.filters["range4"]),
+ "{range4}-{above}".format(range4=cint(self.filters["range4"])+ 1, above=_("Above"))]):
+ self.add_column(label=label, fieldname='range' + str(i+1))
+ self.ageing_column_labels.append(label)
+
+ def get_chart_data(self):
rows = []
- for d in data:
- values = d[self.ageing_col_idx_start : self.ageing_col_idx_start+5]
- precision = cint(frappe.db.get_default("float_precision")) or 2
- formatted_values = [frappe.utils.rounded(val, precision) for val in values]
+ for row in self.data:
rows.append(
{
- 'values': formatted_values
+ 'values': [row.range1, row.range2, row.range3, row.range4, row.range5]
}
)
- return {
+ self.chart = {
"data": {
- 'labels': [d.get("label") for d in ageing_columns],
+ 'labels': self.ageing_column_labels,
'datasets': rows
},
"type": 'percentage'
- }
-
-def execute(filters=None):
- args = {
- "party_type": "Customer",
- "naming_by": ["Selling Settings", "cust_master_name"],
- }
- return ReceivablePayableReport(filters).run(args)
-
-def get_ageing_data(first_range, second_range, third_range,
- fourth_range, age_as_on, entry_date, outstanding_amount):
- # [0-30, 30-60, 60-90, 90-120, 120-above]
- outstanding_range = [0.0, 0.0, 0.0, 0.0, 0.0]
-
- if not (age_as_on and entry_date):
- return [0] + outstanding_range
-
- age = (getdate(age_as_on) - getdate(entry_date)).days or 0
- index = None
- for i, days in enumerate([first_range, second_range, third_range, fourth_range]):
- if age <= days:
- index = i
- break
-
- if index is None: index = 4
- outstanding_range[index] = outstanding_amount
-
- return [age] + outstanding_range
-
-def get_pdc_details(party_type, report_date):
- pdc_details = frappe._dict()
- pdc_via_pe = frappe.db.sql("""
- select
- pref.reference_name as invoice_no, pent.party, pent.party_type,
- pent.posting_date as pdc_date, ifnull(pref.allocated_amount,0) as pdc_amount,
- pent.reference_no as pdc_ref
- from
- `tabPayment Entry` as pent inner join `tabPayment Entry Reference` as pref
- on
- (pref.parent = pent.name)
- where
- pent.docstatus < 2 and pent.posting_date > %s
- and pent.party_type = %s
- """, (report_date, party_type), as_dict=1)
-
- for pdc in pdc_via_pe:
- pdc_details.setdefault((pdc.invoice_no, pdc.party), []).append(pdc)
-
- if scrub(party_type):
- amount_field = ("jea.debit_in_account_currency"
- if party_type == 'Supplier' else "jea.credit_in_account_currency")
- else:
- amount_field = "jea.debit + jea.credit"
-
- pdc_via_je = frappe.db.sql("""
- select
- jea.reference_name as invoice_no, jea.party, jea.party_type,
- je.posting_date as pdc_date, ifnull({0},0) as pdc_amount,
- je.cheque_no as pdc_ref
- from
- `tabJournal Entry` as je inner join `tabJournal Entry Account` as jea
- on
- (jea.parent = je.name)
- where
- je.docstatus < 2 and je.posting_date > %s
- and jea.party_type = %s
- """.format(amount_field), (report_date, party_type), as_dict=1)
-
- for pdc in pdc_via_je:
- pdc_details.setdefault((pdc.invoice_no, pdc.party), []).append(pdc)
-
- return pdc_details
-
-def get_dn_details(party_type, voucher_nos):
- dn_details = frappe._dict()
-
- if party_type == "Customer":
- for si in frappe.db.sql("""
- select
- parent, GROUP_CONCAT(delivery_note SEPARATOR ', ') as dn
- from
- `tabSales Invoice Item`
- where
- docstatus=1 and delivery_note is not null and delivery_note != ''
- and parent in (%s) group by parent
- """ %(','.join(['%s'] * len(voucher_nos))), tuple(voucher_nos) , as_dict=1):
- dn_details.setdefault(si.parent, si.dn)
-
- for si in frappe.db.sql("""
- select
- against_sales_invoice as parent, GROUP_CONCAT(parent SEPARATOR ', ') as dn
- from
- `tabDelivery Note Item`
- where
- docstatus=1 and against_sales_invoice is not null and against_sales_invoice != ''
- and against_sales_invoice in (%s)
- group by against_sales_invoice
- """ %(','.join(['%s'] * len(voucher_nos))), tuple(voucher_nos) , as_dict=1):
- if si.parent in dn_details:
- dn_details[si.parent] += ', %s' %(si.dn)
- else:
- dn_details.setdefault(si.parent, si.dn)
-
- return dn_details
-
-def get_voucher_details(party_type, voucher_nos, dn_details):
- voucher_details = frappe._dict()
-
- if party_type == "Customer":
- for si in frappe.db.sql("""
- select inv.name, inv.due_date, inv.po_no, GROUP_CONCAT(steam.sales_person SEPARATOR ', ') as sales_person
- from `tabSales Invoice` inv
- left join `tabSales Team` steam on steam.parent = inv.name and steam.parenttype = 'Sales Invoice'
- where inv.docstatus=1 and inv.name in (%s)
- group by inv.name
- """ %(','.join(['%s'] *len(voucher_nos))), (tuple(voucher_nos)), as_dict=1):
- si['delivery_note'] = dn_details.get(si.name)
- voucher_details.setdefault(si.name, si)
-
- if party_type == "Supplier":
- for pi in frappe.db.sql("""select name, due_date, bill_no, bill_date
- from `tabPurchase Invoice` where docstatus = 1 and name in (%s)
- """ %(','.join(['%s'] *len(voucher_nos))), (tuple(voucher_nos)), as_dict=1):
- voucher_details.setdefault(pi.name, pi)
-
- for pi in frappe.db.sql("""select name, due_date, bill_no, bill_date from
- `tabJournal Entry` where docstatus = 1 and bill_no is not NULL and name in (%s)
- """ %(','.join(['%s'] *len(voucher_nos))), (tuple(voucher_nos)), as_dict=1):
- voucher_details.setdefault(pi.name, pi)
-
- return voucher_details
+ }
\ No newline at end of file
diff --git a/erpnext/accounts/report/accounts_receivable/test_accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/test_accounts_receivable.py
index 43786a4446..f0274b4472 100644
--- a/erpnext/accounts/report/accounts_receivable/test_accounts_receivable.py
+++ b/erpnext/accounts/report/accounts_receivable/test_accounts_receivable.py
@@ -14,33 +14,44 @@ class TestAccountsReceivable(unittest.TestCase):
filters = {
'company': '_Test Company 2',
- 'based_on_payment_terms': 1
+ 'based_on_payment_terms': 1,
+ 'report_date': today(),
+ 'range1': 30,
+ 'range2': 60,
+ 'range3': 90,
+ 'range4': 120
}
+ # check invoice grand total and invoiced column's value for 3 payment terms
name = make_sales_invoice()
report = execute(filters)
- expected_data = [[100,30], [100,50], [100,20]]
+ expected_data = [[100, 30], [100, 50], [100, 20]]
- self.assertEqual(expected_data[0], report[1][0][7:9])
- self.assertEqual(expected_data[1], report[1][1][7:9])
- self.assertEqual(expected_data[2], report[1][2][7:9])
+ for i in range(3):
+ row = report[1][i-1]
+ self.assertEqual(expected_data[i-1], [row.invoice_grand_total, row.invoiced])
+ # check invoice grand total, invoiced, paid and outstanding column's value after payment
make_payment(name)
report = execute(filters)
- expected_data_after_payment = [[100,50], [100,20]]
+ expected_data_after_payment = [[100, 50, 10, 40], [100, 20, 0, 20]]
- self.assertEqual(expected_data_after_payment[0], report[1][0][7:9])
- self.assertEqual(expected_data_after_payment[1], report[1][1][7:9])
+ for i in range(2):
+ row = report[1][i-1]
+ self.assertEqual(expected_data_after_payment[i-1],
+ [row.invoice_grand_total, row.invoiced, row.paid, row.outstanding])
+ # check invoice grand total, invoiced, paid and outstanding column's value after credit note
make_credit_note(name)
report = execute(filters)
- expected_data_after_credit_note = [[100,100,30,100,-30]]
-
- self.assertEqual(expected_data_after_credit_note[0], report[1][0][7:12])
+ expected_data_after_credit_note = [100, 0, 0, 40, -40]
+ row = report[1][0]
+ self.assertEqual(expected_data_after_credit_note,
+ [row.invoice_grand_total, row.invoiced, row.paid, row.credit_note, row.outstanding])
def make_sales_invoice():
frappe.set_user("Administrator")
@@ -64,7 +75,7 @@ def make_sales_invoice():
return si.name
def make_payment(docname):
- pe = get_payment_entry("Sales Invoice", docname, bank_account="Cash - _TC2", party_amount=30)
+ pe = get_payment_entry("Sales Invoice", docname, bank_account="Cash - _TC2", party_amount=40)
pe.paid_from = "Debtors - _TC2"
pe.insert()
pe.submit()
diff --git a/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py b/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py
index ec24aece5f..350e081957 100644
--- a/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py
+++ b/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py
@@ -3,236 +3,11 @@
from __future__ import unicode_literals
import frappe
-from frappe import _, scrub
-from frappe.utils import flt
+from frappe import _
+from frappe.utils import flt, cint
from erpnext.accounts.party import get_partywise_advanced_payment_amount
from erpnext.accounts.report.accounts_receivable.accounts_receivable import ReceivablePayableReport
-
from six import iteritems
-from six.moves import zip
-
-class AccountsReceivableSummary(ReceivablePayableReport):
- def run(self, args):
- party_naming_by = frappe.db.get_value(args.get("naming_by")[0], None, args.get("naming_by")[1])
- return self.get_columns(party_naming_by, args), self.get_data(party_naming_by, args)
-
- def get_columns(self, party_naming_by, args):
- columns = [_(args.get("party_type")) + ":Link/" + args.get("party_type") + ":200"]
-
- if party_naming_by == "Naming Series":
- columns += [ args.get("party_type") + " Name::140"]
-
- credit_debit_label = "Credit Note Amt" if args.get('party_type') == 'Customer' else "Debit Note Amt"
-
- columns += [{
- "label": _("Advance Amount"),
- "fieldname": "advance_amount",
- "fieldtype": "Currency",
- "options": "currency",
- "width": 100
- },{
- "label": _("Total Invoiced Amt"),
- "fieldname": "total_invoiced_amt",
- "fieldtype": "Currency",
- "options": "currency",
- "width": 100
- },
- {
- "label": _("Total Paid Amt"),
- "fieldname": "total_paid_amt",
- "fieldtype": "Currency",
- "options": "currency",
- "width": 100
- }]
-
- columns += [
- {
- "label": _(credit_debit_label),
- "fieldname": scrub(credit_debit_label),
- "fieldtype": "Currency",
- "options": "currency",
- "width": 140
- },
- {
- "label": _("Total Outstanding Amt"),
- "fieldname": "total_outstanding_amt",
- "fieldtype": "Currency",
- "options": "currency",
- "width": 160
- },
- {
- "label": _("0-" + str(self.filters.range1)),
- "fieldname": scrub("0-" + str(self.filters.range1)),
- "fieldtype": "Currency",
- "options": "currency",
- "width": 160
- },
- {
- "label": _(str(self.filters.range1) + "-" + str(self.filters.range2)),
- "fieldname": scrub(str(self.filters.range1) + "-" + str(self.filters.range2)),
- "fieldtype": "Currency",
- "options": "currency",
- "width": 160
- },
- {
- "label": _(str(self.filters.range2) + "-" + str(self.filters.range3)),
- "fieldname": scrub(str(self.filters.range2) + "-" + str(self.filters.range3)),
- "fieldtype": "Currency",
- "options": "currency",
- "width": 160
- },
- {
- "label": _(str(self.filters.range3) + "-" + str(self.filters.range4)),
- "fieldname": scrub(str(self.filters.range3) + "-" + str(self.filters.range4)),
- "fieldtype": "Currency",
- "options": "currency",
- "width": 160
- },
- {
- "label": _(str(self.filters.range4) + _("-Above")),
- "fieldname": scrub(str(self.filters.range4) + _("-Above")),
- "fieldtype": "Currency",
- "options": "currency",
- "width": 160
- }
- ]
-
- if args.get("party_type") == "Customer":
- columns += [{
- "label": _("Territory"),
- "fieldname": "territory",
- "fieldtype": "Link",
- "options": "Territory",
- "width": 80
- },
- {
- "label": _("Customer Group"),
- "fieldname": "customer_group",
- "fieldtype": "Link",
- "options": "Customer Group",
- "width": 80
- },
- {
- "label": _("Sales Person"),
- "fieldtype": "Data",
- "fieldname": "sales_person",
- "width": 120,
- }]
-
- if args.get("party_type") == "Supplier":
- columns += [{
- "label": _("Supplier Group"),
- "fieldname": "supplier_group",
- "fieldtype": "Link",
- "options": "Supplier Group",
- "width": 80
- }]
-
- columns.append({
- "fieldname": "currency",
- "label": _("Currency"),
- "fieldtype": "Link",
- "options": "Currency",
- "width": 80
- })
-
- return columns
-
- def get_data(self, party_naming_by, args):
- data = []
-
- partywise_total = self.get_partywise_total(party_naming_by, args)
-
- partywise_advance_amount = get_partywise_advanced_payment_amount(args.get("party_type"),
- self.filters.get("report_date")) or {}
- for party, party_dict in iteritems(partywise_total):
- row = [party]
-
- if party_naming_by == "Naming Series":
- row += [self.get_party_name(args.get("party_type"), party)]
-
- row += [partywise_advance_amount.get(party, 0)]
-
- paid_amt = 0
- if party_dict.paid_amt > 0:
- paid_amt = flt(party_dict.paid_amt - partywise_advance_amount.get(party, 0))
-
- row += [
- party_dict.invoiced_amt, paid_amt, party_dict.credit_amt, party_dict.outstanding_amt,
- party_dict.range1, party_dict.range2, party_dict.range3, party_dict.range4, party_dict.range5
- ]
-
- if args.get("party_type") == "Customer":
- row += [self.get_territory(party), self.get_customer_group(party), ", ".join(set(party_dict.sales_person))]
- if args.get("party_type") == "Supplier":
- row += [self.get_supplier_group(party)]
-
- row.append(party_dict.currency)
- data.append(row)
-
- return data
-
- def get_partywise_total(self, party_naming_by, args):
- party_total = frappe._dict()
- for d in self.get_voucherwise_data(party_naming_by, args):
- party_total.setdefault(d.party,
- frappe._dict({
- "invoiced_amt": 0,
- "paid_amt": 0,
- "credit_amt": 0,
- "outstanding_amt": 0,
- "range1": 0,
- "range2": 0,
- "range3": 0,
- "range4": 0,
- "range5": 0,
- "sales_person": []
- })
- )
- for k in list(party_total[d.party]):
- if k not in ["currency", "sales_person"]:
- party_total[d.party][k] += flt(d.get(k, 0))
-
- party_total[d.party].currency = d.currency
-
- if d.sales_person:
- party_total[d.party].sales_person.append(d.sales_person)
-
- return party_total
-
- def get_voucherwise_data(self, party_naming_by, args):
- voucherwise_data = ReceivablePayableReport(self.filters).run(args)[1]
-
- cols = ["posting_date", "party"]
-
- if party_naming_by == "Naming Series":
- cols += ["party_name"]
-
- if args.get("party_type") == 'Customer':
- cols += ["contact"]
-
- cols += ["voucher_type", "voucher_no", "due_date"]
-
- if args.get("party_type") == "Supplier":
- cols += ["bill_no", "bill_date"]
-
- cols += ["invoiced_amt", "paid_amt", "credit_amt",
- "outstanding_amt", "age", "range1", "range2", "range3", "range4", "range5", "currency", "pdc/lc_date", "pdc/lc_ref",
- "pdc/lc_amount"]
-
- if args.get("party_type") == "Supplier":
- cols += ["supplier_group", "remarks"]
- if args.get("party_type") == "Customer":
- cols += ["po_no", "do_no", "territory", "customer_group", "sales_person", "remarks"]
-
- return self.make_data_dict(cols, voucherwise_data)
-
- def make_data_dict(self, cols, data):
- data_dict = []
- for d in data:
- data_dict.append(frappe._dict(zip(cols, d)))
-
- return data_dict
def execute(filters=None):
args = {
@@ -241,3 +16,119 @@ def execute(filters=None):
}
return AccountsReceivableSummary(filters).run(args)
+
+class AccountsReceivableSummary(ReceivablePayableReport):
+ def run(self, args):
+ self.party_type = args.get('party_type')
+ self.party_naming_by = frappe.db.get_value(args.get("naming_by")[0], None, args.get("naming_by")[1])
+ self.get_columns()
+ self.get_data(args)
+ return self.columns, self.data
+
+ def get_data(self, args):
+ self.data = []
+
+ self.receivables = ReceivablePayableReport(self.filters).run(args)[1]
+
+ self.get_party_total(args)
+
+ party_advance_amount = get_partywise_advanced_payment_amount(self.party_type,
+ self.filters.report_date) or {}
+
+ for party, party_dict in iteritems(self.party_total):
+ row = frappe._dict()
+
+ row.party = party
+ if self.party_naming_by == "Naming Series":
+ row.party_name = frappe.get_cached_value(self.party_type, party, [self.party_type + "_name"])
+
+ row.update(party_dict)
+
+ # Advance against party
+ row.advance = party_advance_amount.get(party, 0)
+
+ # In AR/AP, advance shown in paid columns,
+ # but in summary report advance shown in separate column
+ row.paid -= row.advance
+
+ self.data.append(row)
+
+ def get_party_total(self, args):
+ self.party_total = frappe._dict()
+
+ for d in self.receivables:
+ self.init_party_total(d)
+
+ # Add all amount columns
+ for k in list(self.party_total[d.party]):
+ if k not in ["currency", "sales_person"]:
+
+ self.party_total[d.party][k] += d.get(k, 0.0)
+
+ # set territory, customer_group, sales person etc
+ self.set_party_details(d)
+
+ def init_party_total(self, row):
+ self.party_total.setdefault(row.party, frappe._dict({
+ "invoiced": 0.0,
+ "paid": 0.0,
+ "credit_note": 0.0,
+ "outstanding": 0.0,
+ "range1": 0.0,
+ "range2": 0.0,
+ "range3": 0.0,
+ "range4": 0.0,
+ "range5": 0.0,
+ "sales_person": []
+ }))
+
+ def set_party_details(self, row):
+ self.party_total[row.party].currency = row.currency
+
+ for key in ('territory', 'customer_group', 'supplier_group'):
+ if row.get(key):
+ self.party_total[row.party][key] = row.get(key)
+
+ if row.sales_person:
+ self.party_total[row.party].sales_person.append(row.sales_person)
+
+ def get_columns(self):
+ self.columns = []
+ self.add_column(label=_(self.party_type), fieldname='party',
+ fieldtype='Link', options=self.party_type, width=180)
+
+ if self.party_naming_by == "Naming Series":
+ self.add_column(_('{0} Name').format(self.party_type),
+ fieldname = 'party_name', fieldtype='Data')
+
+ credit_debit_label = "Credit Note" if self.party_type == 'Customer' else "Debit Note"
+
+ self.add_column(_('Advance Amount'), fieldname='advance')
+ self.add_column(_('Invoiced Amount'), fieldname='invoiced')
+ self.add_column(_('Paid Amount'), fieldname='paid')
+ self.add_column(_(credit_debit_label), fieldname='credit_note')
+ self.add_column(_('Outstanding Amount'), fieldname='outstanding')
+
+ self.setup_ageing_columns()
+
+ if self.party_type == "Customer":
+ self.add_column(label=_('Territory'), fieldname='territory', fieldtype='Link',
+ options='Territory')
+ self.add_column(label=_('Customer Group'), fieldname='customer_group', fieldtype='Link',
+ options='Customer Group')
+ if self.filters.show_sales_person:
+ self.add_column(label=_('Sales Person'), fieldname='sales_person', fieldtype='Data')
+ else:
+ self.add_column(label=_('Supplier Group'), fieldname='supplier_group', fieldtype='Link',
+ options='Supplier Group')
+
+ self.add_column(label=_('Currency'), fieldname='currency', fieldtype='Link',
+ options='Currency', width=80)
+
+ def setup_ageing_columns(self):
+ for i, label in enumerate(["0-{range1}".format(range1=self.filters["range1"]),
+ "{range1}-{range2}".format(range1=cint(self.filters["range1"])+ 1, range2=self.filters["range2"]),
+ "{range2}-{range3}".format(range2=cint(self.filters["range2"])+ 1, range3=self.filters["range3"]),
+ "{range3}-{range4}".format(range3=cint(self.filters["range3"])+ 1, range4=self.filters["range4"]),
+ "{range4}-{above}".format(range4=cint(self.filters["range4"])+ 1, above=_("Above"))]):
+ self.add_column(label=label, fieldname='range' + str(i+1))
\ No newline at end of file
diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py
index d0b4ba0e65..3c9c3cca03 100644
--- a/erpnext/selling/doctype/customer/customer.py
+++ b/erpnext/selling/doctype/customer/customer.py
@@ -372,7 +372,7 @@ def get_customer_primary_contact(doctype, txt, searchfield, start, page_len, fil
return frappe.db.sql("""
select `tabContact`.name from `tabContact`, `tabDynamic Link`
where `tabContact`.name = `tabDynamic Link`.parent and `tabDynamic Link`.link_name = %(customer)s
- and `tabDynamic Link`.link_doctype = 'Customer' and `tabContact`.is_primary_contact = 1
+ and `tabDynamic Link`.link_doctype = 'Customer'
and `tabContact`.name like %(txt)s
""", {
'customer': customer,
@@ -384,7 +384,7 @@ def get_customer_primary_address(doctype, txt, searchfield, start, page_len, fil
return frappe.db.sql("""
select `tabAddress`.name from `tabAddress`, `tabDynamic Link`
where `tabAddress`.name = `tabDynamic Link`.parent and `tabDynamic Link`.link_name = %(customer)s
- and `tabDynamic Link`.link_doctype = 'Customer' and `tabAddress`.is_primary_address = 1
+ and `tabDynamic Link`.link_doctype = 'Customer'
and `tabAddress`.name like %(txt)s
""", {
'customer': customer,
From a70e2bdbc9fa803f422f2ceed1ea9a86c9a5867a Mon Sep 17 00:00:00 2001
From: Sahil Khan
Date: Tue, 3 Sep 2019 16:20:01 +0530
Subject: [PATCH 397/484] fix(change_log): add v12_1_0 changelog
---
erpnext/change_log/v12/v12_1_0.md | 6 ++++++
1 file changed, 6 insertions(+)
create mode 100644 erpnext/change_log/v12/v12_1_0.md
diff --git a/erpnext/change_log/v12/v12_1_0.md b/erpnext/change_log/v12/v12_1_0.md
new file mode 100644
index 0000000000..aed09c7e39
--- /dev/null
+++ b/erpnext/change_log/v12/v12_1_0.md
@@ -0,0 +1,6 @@
+# Version 12.1.0 Release Notes
+
+### Stock
+
+1. [Pick List](https://erpnext.com/docs/user/manual/en/stock/pick-list)
+2. [Refactored Accounts Receivable Reports](https://erpnext.com/docs/user/manual/en/accounts/accounting-reports#2-accounting-statements)
From e8b1c8253139958a6d15b1beb5604ce47b0143b4 Mon Sep 17 00:00:00 2001
From: Sahil Khan
Date: Tue, 3 Sep 2019 16:53:06 +0550
Subject: [PATCH 398/484] bumped to version 12.1.0
---
erpnext/__init__.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/__init__.py b/erpnext/__init__.py
index 2490f3b42e..ee37c8d780 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__ = '12.0.8'
+__version__ = '12.1.0'
def get_default_company(user=None):
'''Get default company for user'''
From 1e2dc2c8f113fb65640cef0fab4641fc71039d25 Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Tue, 3 Sep 2019 20:45:52 +0530
Subject: [PATCH 399/484] feat: Employee Incentive and Retention Bonus added in
Salary Slip (Additional Salary) (#18647)
* feat: employee incentive and retention bonus added in additional salary
* fix: added salary component field, logic improved
* fix: codacy review
---
.../accounts/doctype/bank/bank_dashboard.py | 2 +-
.../additional_salary/additional_salary.py | 2 +-
.../employee_incentive/employee_incentive.js | 16 +-
.../employee_incentive.json | 424 ++++----------
.../employee_incentive/employee_incentive.py | 37 +-
.../retention_bonus/retention_bonus.js | 9 +-
.../retention_bonus/retention_bonus.json | 536 +++++-------------
.../retention_bonus/retention_bonus.py | 41 +-
8 files changed, 353 insertions(+), 714 deletions(-)
diff --git a/erpnext/accounts/doctype/bank/bank_dashboard.py b/erpnext/accounts/doctype/bank/bank_dashboard.py
index 4a1dad8952..1e2383de5f 100644
--- a/erpnext/accounts/doctype/bank/bank_dashboard.py
+++ b/erpnext/accounts/doctype/bank/bank_dashboard.py
@@ -8,7 +8,7 @@ def get_data():
'fieldname': 'bank',
'transactions': [
{
- 'label': _('Bank Deatils'),
+ 'label': _('Bank Details'),
'items': ['Bank Account', 'Bank Guarantee']
}
]
diff --git a/erpnext/hr/doctype/additional_salary/additional_salary.py b/erpnext/hr/doctype/additional_salary/additional_salary.py
index 82f2a22e81..8498b3d277 100644
--- a/erpnext/hr/doctype/additional_salary/additional_salary.py
+++ b/erpnext/hr/doctype/additional_salary/additional_salary.py
@@ -11,7 +11,7 @@ from frappe.utils import getdate, date_diff
class AdditionalSalary(Document):
def before_insert(self):
if frappe.db.exists("Additional Salary", {"employee": self.employee, "salary_component": self.salary_component,
- "amount": self.amount, "payroll_date": self.payroll_date, "company": self.company}):
+ "amount": self.amount, "payroll_date": self.payroll_date, "company": self.company, "docstatus": 1}):
frappe.throw(_("Additional Salary Component Exists."))
diff --git a/erpnext/hr/doctype/employee_incentive/employee_incentive.js b/erpnext/hr/doctype/employee_incentive/employee_incentive.js
index d2ddfb67a8..db0f83aac9 100644
--- a/erpnext/hr/doctype/employee_incentive/employee_incentive.js
+++ b/erpnext/hr/doctype/employee_incentive/employee_incentive.js
@@ -2,7 +2,21 @@
// For license information, please see license.txt
frappe.ui.form.on('Employee Incentive', {
- refresh: function(frm) {
+ setup: function(frm) {
+ frm.set_query("employee", function() {
+ return {
+ filters: {
+ "status": "Active"
+ }
+ };
+ });
+ frm.set_query("salary_component", function() {
+ return {
+ filters: {
+ "type": "Earning"
+ }
+ };
+ });
}
});
diff --git a/erpnext/hr/doctype/employee_incentive/employee_incentive.json b/erpnext/hr/doctype/employee_incentive/employee_incentive.json
index 5ba1d636be..3bc772cfa6 100644
--- a/erpnext/hr/doctype/employee_incentive/employee_incentive.json
+++ b/erpnext/hr/doctype/employee_incentive/employee_incentive.json
@@ -1,330 +1,130 @@
{
- "allow_copy": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "autoname": "HR-EINV-.YY.-.MM.-.#####",
- "beta": 0,
- "creation": "2018-04-13 16:13:43.404546",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "",
- "editable_grid": 1,
- "engine": "InnoDB",
+ "autoname": "HR-EINV-.YY.-.MM.-.#####",
+ "creation": "2018-04-13 16:13:43.404546",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "employee",
+ "incentive_amount",
+ "payroll_date",
+ "salary_component",
+ "amended_from",
+ "column_break_5",
+ "employee_name",
+ "department",
+ "additional_salary"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "employee",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Employee",
- "length": 0,
- "no_copy": 0,
- "options": "Employee",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "employee",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Employee",
+ "options": "Employee",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "incentive_amount",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Incentive Amount",
- "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": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "incentive_amount",
+ "fieldtype": "Currency",
+ "label": "Incentive Amount",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "payroll_date",
- "fieldtype": "Date",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Payroll Date",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "payroll_date",
+ "fieldtype": "Date",
+ "label": "Payroll Date",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "amended_from",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Amended From",
- "length": 0,
- "no_copy": 1,
- "options": "Employee Incentive",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "amended_from",
+ "fieldtype": "Link",
+ "label": "Amended From",
+ "no_copy": 1,
+ "options": "Employee Incentive",
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_5",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "column_break_5",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_from": "employee.employee_name",
- "fieldname": "employee_name",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Employee Name",
- "length": 0,
- "no_copy": 0,
- "options": "",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fetch_from": "employee.employee_name",
+ "fieldname": "employee_name",
+ "fieldtype": "Data",
+ "label": "Employee Name",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_from": "employee.department",
- "fieldname": "department",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Department",
- "length": 0,
- "no_copy": 0,
- "options": "Department",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "fetch_from": "employee.department",
+ "fieldname": "department",
+ "fieldtype": "Link",
+ "label": "Department",
+ "options": "Department",
+ "read_only": 1
+ },
+ {
+ "fieldname": "additional_salary",
+ "fieldtype": "Link",
+ "label": "Additional Salary",
+ "no_copy": 1,
+ "options": "Additional Salary",
+ "read_only": 1
+ },
+ {
+ "fieldname": "salary_component",
+ "fieldtype": "Link",
+ "label": "Salary Component",
+ "options": "Salary Component",
+ "reqd": 1
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 1,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2018-08-21 16:15:51.811149",
- "modified_by": "Administrator",
- "module": "HR",
- "name": "Employee Incentive",
- "name_case": "",
- "owner": "Administrator",
+ ],
+ "is_submittable": 1,
+ "modified": "2019-09-03 16:48:16.822252",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Employee Incentive",
+ "owner": "Administrator",
"permissions": [
{
- "amend": 1,
- "cancel": 1,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "HR Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 1,
+ "amend": 1,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "HR Manager",
+ "share": 1,
+ "submit": 1,
"write": 1
- },
+ },
{
- "amend": 0,
- "cancel": 0,
- "create": 0,
- "delete": 0,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Employee",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
- "write": 0
- },
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Employee",
+ "share": 1
+ },
{
- "amend": 0,
- "cancel": 0,
- "create": 1,
- "delete": 0,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "HR User",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
+ "create": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "HR User",
+ "share": 1,
"write": 1
}
- ],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "title_field": "employee_name",
- "track_changes": 1,
- "track_seen": 0,
- "track_views": 0
+ ],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "title_field": "employee_name",
+ "track_changes": 1
}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/employee_incentive/employee_incentive.py b/erpnext/hr/doctype/employee_incentive/employee_incentive.py
index 6c9a315336..2e138f8ef5 100644
--- a/erpnext/hr/doctype/employee_incentive/employee_incentive.py
+++ b/erpnext/hr/doctype/employee_incentive/employee_incentive.py
@@ -7,4 +7,39 @@ import frappe
from frappe.model.document import Document
class EmployeeIncentive(Document):
- pass
+ def on_submit(self):
+ company = frappe.db.get_value('Employee', self.employee, 'company')
+ additional_salary = frappe.db.exists('Additional Salary', {
+ 'employee': self.employee,
+ 'salary_component': self.salary_component,
+ 'payroll_date': self.payroll_date,
+ 'company': company,
+ 'docstatus': 1
+ })
+
+ if not additional_salary:
+ additional_salary = frappe.new_doc('Additional Salary')
+ additional_salary.employee = self.employee
+ additional_salary.salary_component = self.salary_component
+ additional_salary.amount = self.incentive_amount
+ additional_salary.payroll_date = self.payroll_date
+ additional_salary.company = company
+ additional_salary.submit()
+ self.db_set('additional_salary', additional_salary.name)
+
+ else:
+ incentive_added = frappe.db.get_value('Additional Salary', additional_salary, 'amount') + self.incentive_amount
+ frappe.db.set_value('Additional Salary', additional_salary, 'amount', incentive_added)
+ self.db_set('additional_salary', additional_salary)
+
+ def on_cancel(self):
+ if self.additional_salary:
+ incentive_removed = frappe.db.get_value('Additional Salary', self.additional_salary, 'amount') - self.incentive_amount
+ if incentive_removed == 0:
+ frappe.get_doc('Additional Salary', self.additional_salary).cancel()
+ else:
+ frappe.db.set_value('Additional Salary', self.additional_salary, 'amount', incentive_removed)
+
+ self.db_set('additional_salary', '')
+
+
diff --git a/erpnext/hr/doctype/retention_bonus/retention_bonus.js b/erpnext/hr/doctype/retention_bonus/retention_bonus.js
index 58f6b53604..64e726db85 100644
--- a/erpnext/hr/doctype/retention_bonus/retention_bonus.js
+++ b/erpnext/hr/doctype/retention_bonus/retention_bonus.js
@@ -10,8 +10,13 @@ frappe.ui.form.on('Retention Bonus', {
}
};
});
- },
- refresh: function(frm) {
+ frm.set_query("salary_component", function() {
+ return {
+ filters: {
+ "type": "Earning"
+ }
+ };
+ });
}
});
diff --git a/erpnext/hr/doctype/retention_bonus/retention_bonus.json b/erpnext/hr/doctype/retention_bonus/retention_bonus.json
index 5a92f07bd6..7781053e13 100644
--- a/erpnext/hr/doctype/retention_bonus/retention_bonus.json
+++ b/erpnext/hr/doctype/retention_bonus/retention_bonus.json
@@ -1,415 +1,165 @@
{
- "allow_copy": 0,
- "allow_guest_to_view": 0,
- "allow_import": 1,
- "allow_rename": 1,
- "autoname": "HR-RTB-.YYYY.-.#####",
- "beta": 0,
- "creation": "2018-05-13 14:59:42.038964",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "",
- "editable_grid": 1,
- "engine": "InnoDB",
+ "allow_import": 1,
+ "allow_rename": 1,
+ "autoname": "HR-RTB-.YYYY.-.#####",
+ "creation": "2018-05-13 14:59:42.038964",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "company",
+ "employee",
+ "bonus_payment_date",
+ "bonus_amount",
+ "salary_component",
+ "amended_from",
+ "column_break_6",
+ "employee_name",
+ "department",
+ "date_of_joining",
+ "additional_salary"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "company",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Company",
- "length": 0,
- "no_copy": 0,
- "options": "Company",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "label": "Company",
+ "options": "Company",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "employee",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Employee",
- "length": 0,
- "no_copy": 0,
- "options": "Employee",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "employee",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Employee",
+ "options": "Employee",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "bonus_payment_date",
- "fieldtype": "Date",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Bonus Payment Date",
- "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": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "bonus_payment_date",
+ "fieldtype": "Date",
+ "in_list_view": 1,
+ "label": "Bonus Payment Date",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "bonus_amount",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Bonus Amount",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "bonus_amount",
+ "fieldtype": "Currency",
+ "label": "Bonus Amount",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "amended_from",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Amended From",
- "length": 0,
- "no_copy": 1,
- "options": "Retention Bonus",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "amended_from",
+ "fieldtype": "Link",
+ "label": "Amended From",
+ "no_copy": 1,
+ "options": "Retention Bonus",
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_6",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "column_break_6",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_from": "employee.employee_name",
- "fieldname": "employee_name",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Employee Name",
- "length": 0,
- "no_copy": 0,
- "options": "",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fetch_from": "employee.employee_name",
+ "fieldname": "employee_name",
+ "fieldtype": "Data",
+ "label": "Employee Name",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_from": "employee.department",
- "fieldname": "department",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Department",
- "length": 0,
- "no_copy": 0,
- "options": "Department",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fetch_from": "employee.department",
+ "fieldname": "department",
+ "fieldtype": "Link",
+ "label": "Department",
+ "options": "Department",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_from": "employee.date_of_joining",
- "fieldname": "date_of_joining",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Date of Joining",
- "length": 0,
- "no_copy": 0,
- "options": "",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "fetch_from": "employee.date_of_joining",
+ "fieldname": "date_of_joining",
+ "fieldtype": "Data",
+ "label": "Date of Joining",
+ "read_only": 1
+ },
+ {
+ "fieldname": "additional_salary",
+ "fieldtype": "Link",
+ "label": "Additional Salary",
+ "no_copy": 1,
+ "options": "Additional Salary",
+ "read_only": 1
+ },
+ {
+ "fieldname": "salary_component",
+ "fieldtype": "Link",
+ "label": "Salary Component",
+ "options": "Salary Component",
+ "reqd": 1
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 1,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2018-08-21 16:15:38.710684",
- "modified_by": "Administrator",
- "module": "HR",
- "name": "Retention Bonus",
- "name_case": "",
- "owner": "Administrator",
+ ],
+ "is_submittable": 1,
+ "modified": "2019-09-03 16:47:24.210422",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Retention Bonus",
+ "owner": "Administrator",
"permissions": [
{
- "amend": 0,
- "cancel": 1,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "System Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 1,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "System Manager",
+ "share": 1,
+ "submit": 1,
"write": 1
- },
+ },
{
- "amend": 0,
- "cancel": 1,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "HR Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 1,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "HR Manager",
+ "share": 1,
+ "submit": 1,
"write": 1
- },
+ },
{
- "amend": 0,
- "cancel": 1,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "HR User",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 1,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "HR User",
+ "share": 1,
+ "submit": 1,
"write": 1
- },
+ },
{
- "amend": 0,
- "cancel": 0,
- "create": 0,
- "delete": 0,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Employee",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
- "write": 0
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Employee",
+ "share": 1
}
- ],
- "quick_entry": 1,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1,
- "track_seen": 0,
- "track_views": 0
+ ],
+ "quick_entry": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/retention_bonus/retention_bonus.py b/erpnext/hr/doctype/retention_bonus/retention_bonus.py
index 20d4c13f19..48637a350c 100644
--- a/erpnext/hr/doctype/retention_bonus/retention_bonus.py
+++ b/erpnext/hr/doctype/retention_bonus/retention_bonus.py
@@ -10,7 +10,42 @@ from frappe.utils import getdate
class RetentionBonus(Document):
def validate(self):
- if frappe.get_value("Employee", self.employee, "status") == "Left":
- frappe.throw(_("Cannot create Retention Bonus for left Employees"))
+ if frappe.get_value('Employee', self.employee, 'status') == 'Left':
+ frappe.throw(_('Cannot create Retention Bonus for left Employees'))
if getdate(self.bonus_payment_date) < getdate():
- frappe.throw(_("Bonus Payment Date cannot be a past date"))
+ frappe.throw(_('Bonus Payment Date cannot be a past date'))
+
+ def on_submit(self):
+ company = frappe.db.get_value('Employee', self.employee, 'company')
+ additional_salary = frappe.db.exists('Additional Salary', {
+ 'employee': self.employee,
+ 'salary_component': self.salary_component,
+ 'payroll_date': self.bonus_payment_date,
+ 'company': company,
+ 'docstatus': 1
+ })
+
+ if not additional_salary:
+ additional_salary = frappe.new_doc('Additional Salary')
+ additional_salary.employee = self.employee
+ additional_salary.salary_component = self.salary_component
+ additional_salary.amount = self.bonus_amount
+ additional_salary.payroll_date = self.bonus_payment_date
+ additional_salary.company = company
+ additional_salary.submit()
+ self.db_set('additional_salary', additional_salary.name)
+
+ else:
+ bonus_added = frappe.db.get_value('Additional Salary', additional_salary, 'amount') + self.bonus_amount
+ frappe.db.set_value('Additional Salary', additional_salary, 'amount', bonus_added)
+ self.db_set('additional_salary', additional_salary)
+
+ def on_cancel(self):
+ if self.additional_salary:
+ bonus_removed = frappe.db.get_value('Additional Salary', self.additional_salary, 'amount') - self.bonus_amount
+ if bonus_removed == 0:
+ frappe.get_doc('Additional Salary', self.additional_salary).cancel()
+ else:
+ frappe.db.set_value('Additional Salary', self.additional_salary, 'amount', bonus_removed)
+
+ self.db_set('additional_salary', '')
\ No newline at end of file
From 93bad51659454eebf0d2443fd5a0d2b9a752c63b Mon Sep 17 00:00:00 2001
From: Rohit Waghchaure
Date: Tue, 3 Sep 2019 23:29:41 +0530
Subject: [PATCH 400/484] fix: offline pos item search not working
---
erpnext/accounts/page/pos/pos.js | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/erpnext/accounts/page/pos/pos.js b/erpnext/accounts/page/pos/pos.js
index b5a02d0e49..8d57c71a32 100755
--- a/erpnext/accounts/page/pos/pos.js
+++ b/erpnext/accounts/page/pos/pos.js
@@ -1121,7 +1121,8 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
if (key) {
return $.grep(this.items_list, function (item) {
if (search_status) {
- if (in_list(me.batch_no_data[item.item_code], me.search_item.$input.val())) {
+ if (me.batch_no_data[item.item_code] &&
+ in_list(me.batch_no_data[item.item_code], me.search_item.$input.val())) {
search_status = false;
return me.item_batch_no[item.item_code] = me.search_item.$input.val()
} else if (me.serial_no_data[item.item_code]
@@ -1129,7 +1130,8 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
search_status = false;
me.item_serial_no[item.item_code] = [me.search_item.$input.val(), me.serial_no_data[item.item_code][me.search_item.$input.val()]]
return true
- } else if (in_list(me.barcode_data[item.item_code], me.search_item.$input.val())) {
+ } else if (me.barcode_data[item.item_code] &&
+ in_list(me.barcode_data[item.item_code], me.search_item.$input.val())) {
search_status = false;
return true;
} else if (reg.test(item.item_code.toLowerCase()) || (item.description && reg.test(item.description.toLowerCase())) ||
From 561a2e966e76832977bffe7edf79a2acc05de59c Mon Sep 17 00:00:00 2001
From: Nabin Hait
Date: Wed, 4 Sep 2019 11:02:48 +0530
Subject: [PATCH 401/484] Update accounts_receivable.py
---
.../report/accounts_receivable/accounts_receivable.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
index 88e4227837..b2bf3f90a7 100755
--- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
+++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
@@ -492,7 +492,7 @@ class ReceivablePayableReport(object):
elif party_type_field=="supplier":
self.add_supplier_filters(conditions, values)
- self.add_accounting_dimensions_filters()
+ self.add_accounting_dimensions_filters(conditions, values)
return " and ".join(conditions), values
@@ -697,4 +697,4 @@ class ReceivablePayableReport(object):
'datasets': rows
},
"type": 'percentage'
- }
\ No newline at end of file
+ }
From e46c56bfe83de3526fa6117365a5406b686c59a4 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Wed, 4 Sep 2019 11:02:52 +0530
Subject: [PATCH 402/484] fix: Use medium instead of to number to get schedule
---
erpnext/communication/doctype/call_log/call_log.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/communication/doctype/call_log/call_log.py b/erpnext/communication/doctype/call_log/call_log.py
index 35c31a0bf8..5343bef62c 100644
--- a/erpnext/communication/doctype/call_log/call_log.py
+++ b/erpnext/communication/doctype/call_log/call_log.py
@@ -28,7 +28,7 @@ class CallLog(Document):
self.trigger_call_popup()
def trigger_call_popup(self):
- scheduled_employees = get_scheduled_employees_for_popup(self.to)
+ scheduled_employees = get_scheduled_employees_for_popup(self.medium)
employee_emails = get_employees_with_number(self.to)
# check if employees with matched number are scheduled to receive popup
From a5907e17d565852f09b771c146327fd8de541fa2 Mon Sep 17 00:00:00 2001
From: Nabin Hait
Date: Wed, 4 Sep 2019 11:04:27 +0530
Subject: [PATCH 403/484] Update accounts_receivable.py
---
.../report/accounts_receivable/accounts_receivable.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
index 88e4227837..b2bf3f90a7 100755
--- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
+++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
@@ -492,7 +492,7 @@ class ReceivablePayableReport(object):
elif party_type_field=="supplier":
self.add_supplier_filters(conditions, values)
- self.add_accounting_dimensions_filters()
+ self.add_accounting_dimensions_filters(conditions, values)
return " and ".join(conditions), values
@@ -697,4 +697,4 @@ class ReceivablePayableReport(object):
'datasets': rows
},
"type": 'percentage'
- }
\ No newline at end of file
+ }
From 1635967c4eb82975f96917aa220d966aff0211fb Mon Sep 17 00:00:00 2001
From: Rohan
Date: Thu, 5 Sep 2019 12:16:49 +0530
Subject: [PATCH 404/484] fix: attribute error when trying to fetch items
(#18900)
---
.../manufacturing/doctype/production_plan/production_plan.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.py b/erpnext/manufacturing/doctype/production_plan/production_plan.py
index 650ab137a0..048ce0d6ef 100644
--- a/erpnext/manufacturing/doctype/production_plan/production_plan.py
+++ b/erpnext/manufacturing/doctype/production_plan/production_plan.py
@@ -99,7 +99,7 @@ class ProductionPlan(Document):
self.get_mr_items()
def get_so_items(self):
- so_list = [d.sales_order for d in self.sales_orders if d.sales_order]
+ so_list = [d.sales_order for d in self.get("sales_orders", []) if d.sales_order]
if not so_list:
msgprint(_("Please enter Sales Orders in the above table"))
return []
@@ -134,7 +134,7 @@ class ProductionPlan(Document):
self.calculate_total_planned_qty()
def get_mr_items(self):
- mr_list = [d.material_request for d in self.material_requests if d.material_request]
+ mr_list = [d.material_request for d in self.get("material_requests", []) if d.material_request]
if not mr_list:
msgprint(_("Please enter Material Requests in the above table"))
return []
From 805b8634da12f9659fecf63a30237ab25be11df5 Mon Sep 17 00:00:00 2001
From: rohitwaghchaure
Date: Thu, 5 Sep 2019 12:18:33 +0530
Subject: [PATCH 405/484] fix: incorrect stock value difference when stock move
from negative to positive (#18887)
---
erpnext/stock/stock_ledger.py | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py
index f7deac3591..69a4b94b4e 100644
--- a/erpnext/stock/stock_ledger.py
+++ b/erpnext/stock/stock_ledger.py
@@ -181,10 +181,7 @@ class update_entries_after(object):
# rounding as per precision
self.stock_value = flt(self.stock_value, self.precision)
- if self.prev_stock_value < 0 and self.stock_value >= 0 and sle.voucher_type != 'Stock Reconciliation':
- stock_value_difference = sle.actual_qty * self.valuation_rate
- else:
- stock_value_difference = self.stock_value - self.prev_stock_value
+ stock_value_difference = self.stock_value - self.prev_stock_value
self.prev_stock_value = self.stock_value
From a2db94761addee2826e476a9808880039e882d1a Mon Sep 17 00:00:00 2001
From: Faris Ansari
Date: Thu, 5 Sep 2019 12:19:50 +0530
Subject: [PATCH 406/484] fix: Honor Shopping Cart Price List (#18885)
---
erpnext/shopping_cart/cart.py | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/erpnext/shopping_cart/cart.py b/erpnext/shopping_cart/cart.py
index 0922f3d1a0..db2c3277d0 100644
--- a/erpnext/shopping_cart/cart.py
+++ b/erpnext/shopping_cart/cart.py
@@ -336,19 +336,20 @@ def set_price_list_and_rate(quotation, cart_settings):
def _set_price_list(quotation, cart_settings):
"""Set price list based on customer or shopping cart default"""
- if quotation.selling_price_list:
- return
+ from erpnext.accounts.party import get_default_price_list
# check if customer price list exists
selling_price_list = None
if quotation.party_name:
- from erpnext.accounts.party import get_default_price_list
- selling_price_list = get_default_price_list(frappe.get_doc("Customer", quotation.party_name))
+ selling_price_list = frappe.db.get_value('Customer', quotation.party_name, 'default_price_list')
# else check for territory based price list
if not selling_price_list:
selling_price_list = cart_settings.price_list
+ if not selling_price_list and quotation.party_name:
+ selling_price_list = get_default_price_list(frappe.get_doc("Customer", quotation.party_name))
+
quotation.selling_price_list = selling_price_list
def set_taxes(quotation, cart_settings):
From 1e0b0da7ad8f6c20573006d650b9f1a0a276ee5b Mon Sep 17 00:00:00 2001
From: sahil28297 <37302950+sahil28297@users.noreply.github.com>
Date: Thu, 5 Sep 2019 12:21:44 +0530
Subject: [PATCH 407/484] fix(patch): add company in filters to get proper
parent account (#18905)
---
erpnext/patches/v12_0/move_item_tax_to_item_tax_template.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/patches/v12_0/move_item_tax_to_item_tax_template.py b/erpnext/patches/v12_0/move_item_tax_to_item_tax_template.py
index 02203d29d4..9f4c445365 100644
--- a/erpnext/patches/v12_0/move_item_tax_to_item_tax_template.py
+++ b/erpnext/patches/v12_0/move_item_tax_to_item_tax_template.py
@@ -82,7 +82,7 @@ def get_item_tax_template(item_tax_templates, rename_template_to_untitled, item_
account_name = " - ".join(parts[:-1])
company = frappe.db.get_value("Company", filters={"abbr": parts[-1]})
parent_account = frappe.db.get_value("Account",
- filters={"account_type": "Tax", "root_type": "Liability", "is_group": 0}, fieldname="parent_account")
+ filters={"account_type": "Tax", "root_type": "Liability", "is_group": 0, "company": company}, fieldname="parent_account")
frappe.get_doc({
"doctype": "Account",
From 7834a0182b96cc372d50fc58eefcbdaeceb71e3d Mon Sep 17 00:00:00 2001
From: Nabin Hait
Date: Thu, 5 Sep 2019 12:22:48 +0530
Subject: [PATCH 408/484] Update move_credit_limit_to_customer_credit_limit.py
---
.../patches/v12_0/move_credit_limit_to_customer_credit_limit.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/patches/v12_0/move_credit_limit_to_customer_credit_limit.py b/erpnext/patches/v12_0/move_credit_limit_to_customer_credit_limit.py
index ca01c604dd..30acfe68ea 100644
--- a/erpnext/patches/v12_0/move_credit_limit_to_customer_credit_limit.py
+++ b/erpnext/patches/v12_0/move_credit_limit_to_customer_credit_limit.py
@@ -36,4 +36,4 @@ def move_credit_limit_to_child_table():
'bypass_credit_limit_check': record.bypass_credit_limit_check_at_sales_order,
'company': company.name
})
- customer.save()
\ No newline at end of file
+ customer.db_insert()
From c78c86663dfd170fb8f81ac8820852cbe456777c Mon Sep 17 00:00:00 2001
From: Nabin Hait
Date: Thu, 5 Sep 2019 12:24:37 +0530
Subject: [PATCH 409/484] Update customer_credit_balance.py
---
.../report/customer_credit_balance/customer_credit_balance.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/erpnext/selling/report/customer_credit_balance/customer_credit_balance.py b/erpnext/selling/report/customer_credit_balance/customer_credit_balance.py
index 6b8b8581d2..cd50568cf9 100644
--- a/erpnext/selling/report/customer_credit_balance/customer_credit_balance.py
+++ b/erpnext/selling/report/customer_credit_balance/customer_credit_balance.py
@@ -60,7 +60,7 @@ def get_details(filters):
conditions = ""
if filters.get("customer"):
- conditions += " AND name = " + filters.get("customer")
+ conditions += " AND c.name = " + filters.get("customer")
return frappe.db.sql("""SELECT
c.name, c.customer_name,
@@ -71,4 +71,4 @@ def get_details(filters):
c.name = ccl.parent
AND ccl.company = %s
{0}
- """.format(conditions), (filters.get("company")), as_dict=1) #nosec
\ No newline at end of file
+ """.format(conditions), (filters.get("company")), as_dict=1) #nosec
From f4fde51bba4b62afb6a73eb70b25bb3439aba26c Mon Sep 17 00:00:00 2001
From: Nabin Hait
Date: Thu, 5 Sep 2019 12:33:29 +0530
Subject: [PATCH 410/484] Update customer.py
---
erpnext/selling/doctype/customer/customer.py | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py
index 5d0e8ed98c..4dd02da333 100644
--- a/erpnext/selling/doctype/customer/customer.py
+++ b/erpnext/selling/doctype/customer/customer.py
@@ -170,14 +170,14 @@ class Customer(TransactionBase):
if self.get("__islocal") or not self.credit_limit_reference:
return
- company_record = [c.company for c in self.credit_limit_reference]
-
- for limit in frappe.get_all("Customer Credit Limit", {'parent': self.name}, ["credit_limit", "company"]):
- outstanding_amt = get_customer_outstanding(self.name, limit.company)
- company_record.append(limit.company)
- if company_record.count(limit.company) >2:
+ company_record = []
+ for limit in self.credit_limit_reference:
+ if limit.company in company_record:
frappe.throw(_("Credit limit is already defined for the Company {0}").format(limit.company, self.name))
+ else:
+ company_record.append(limit.company)
+ outstanding_amt = get_customer_outstanding(self.name, limit.company)
if flt(limit.credit_limit) < outstanding_amt:
frappe.throw(_("""New credit limit is less than current outstanding amount for the customer. Credit limit has to be atleast {0}""").format(outstanding_amt))
@@ -330,7 +330,7 @@ def get_credit_limit(customer, company):
credit_limit = frappe.db.get_value("Customer Credit Limit", {'parent': customer, 'company': company}, 'credit_limit')
if not credit_limit:
- customer_group = frappe.db.get_value("Customer", customer, 'customer_group')
+ customer_group = frappe.get_cached_value("Customer", customer, 'customer_group')
credit_limit = frappe.get_cached_value("Customer Group", customer_group, "credit_limit")
if not credit_limit:
From 607a21e02acbcad21c7d304f748e6eddaa0cc422 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Thu, 5 Sep 2019 12:42:29 +0530
Subject: [PATCH 411/484] feat: Init Employee Leave Balance Summary report
---
.../__init__.py | 0
.../employee_leave_balance_summary.js | 36 +++++++++++
.../employee_leave_balance_summary.json | 34 ++++++++++
.../employee_leave_balance_summary.py | 63 +++++++++++++++++++
4 files changed, 133 insertions(+)
create mode 100644 erpnext/hr/report/employee_leave_balance_summary/__init__.py
create mode 100644 erpnext/hr/report/employee_leave_balance_summary/employee_leave_balance_summary.js
create mode 100644 erpnext/hr/report/employee_leave_balance_summary/employee_leave_balance_summary.json
create mode 100644 erpnext/hr/report/employee_leave_balance_summary/employee_leave_balance_summary.py
diff --git a/erpnext/hr/report/employee_leave_balance_summary/__init__.py b/erpnext/hr/report/employee_leave_balance_summary/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/hr/report/employee_leave_balance_summary/employee_leave_balance_summary.js b/erpnext/hr/report/employee_leave_balance_summary/employee_leave_balance_summary.js
new file mode 100644
index 0000000000..a05db33050
--- /dev/null
+++ b/erpnext/hr/report/employee_leave_balance_summary/employee_leave_balance_summary.js
@@ -0,0 +1,36 @@
+// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+/* eslint-disable */
+
+frappe.query_reports["Employee Leave Balance Summary"] = {
+ "filters": [
+ {
+ "fieldname":"from_date",
+ "label": __("From Date"),
+ "fieldtype": "Date",
+ "reqd": 1,
+ "default": frappe.defaults.get_default("year_start_date")
+ },
+ {
+ "fieldname":"to_date",
+ "label": __("To Date"),
+ "fieldtype": "Date",
+ "reqd": 1,
+ "default": frappe.defaults.get_default("year_end_date")
+ },
+ {
+ "fieldname":"company",
+ "label": __("Company"),
+ "fieldtype": "Link",
+ "options": "Company",
+ "reqd": 1,
+ "default": frappe.defaults.get_user_default("Company")
+ },
+ {
+ "fieldname":"employee",
+ "label": __("Employee"),
+ "fieldtype": "Link",
+ "options": "Employee",
+ }
+ ]
+};
diff --git a/erpnext/hr/report/employee_leave_balance_summary/employee_leave_balance_summary.json b/erpnext/hr/report/employee_leave_balance_summary/employee_leave_balance_summary.json
new file mode 100644
index 0000000000..60fe1ae25c
--- /dev/null
+++ b/erpnext/hr/report/employee_leave_balance_summary/employee_leave_balance_summary.json
@@ -0,0 +1,34 @@
+{
+ "add_total_row": 0,
+ "creation": "2019-09-05 11:18:06.209397",
+ "disable_prepared_report": 0,
+ "disabled": 0,
+ "docstatus": 0,
+ "doctype": "Report",
+ "idx": 0,
+ "is_standard": "Yes",
+ "letter_head": "sapcon-old",
+ "modified": "2019-09-05 11:18:06.209397",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Employee Leave Balance Summary",
+ "owner": "Administrator",
+ "prepared_report": 0,
+ "ref_doctype": "Employee",
+ "report_name": "Employee Leave Balance Summary",
+ "report_type": "Script Report",
+ "roles": [
+ {
+ "role": "Employee"
+ },
+ {
+ "role": "HR Manager"
+ },
+ {
+ "role": "HR User"
+ },
+ {
+ "role": "Leave Approver"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/erpnext/hr/report/employee_leave_balance_summary/employee_leave_balance_summary.py b/erpnext/hr/report/employee_leave_balance_summary/employee_leave_balance_summary.py
new file mode 100644
index 0000000000..5512f7aa25
--- /dev/null
+++ b/erpnext/hr/report/employee_leave_balance_summary/employee_leave_balance_summary.py
@@ -0,0 +1,63 @@
+# 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.utils import flt
+from frappe import _
+from erpnext.hr.doctype.leave_application.leave_application \
+ import get_leave_balance_on, get_leaves_for_period
+
+from erpnext.hr.report.employee_leave_balance.employee_leave_balance \
+ import get_total_allocated_leaves
+
+def execute(filters=None):
+ columns = get_columns()
+ data = get_data(filters)
+
+ return columns, data
+
+def get_columns():
+ columns = []
+ columns.append(_('Leave Type') )
+ columns.append(_('Employee'))
+ columns.append(_('Employee Name'))
+ columns.append(_('Opening Balance') + ':Float:160')
+ columns.append(_('Leaves Taken') + ':Float:160')
+ columns.append(_('Closing Balance') + ':Float:160')
+
+ return columns
+
+def get_data(filters):
+ leave_types = frappe.db.sql_list("SELECT `name` FROM `tabLeave Type` ORDER BY `name` ASC")
+
+ if filters.to_date <= filters.from_date:
+ frappe.throw(_('From date can not be greater than than To date'))
+
+ conditions = {
+ 'status': 'Active',
+ }
+
+ if filters.get('employee'):
+ conditions['name'] = filters.get('employee')
+
+ active_employees = frappe.get_all('Employee',
+ filters=conditions,
+ fields=['name', 'employee_name', 'department', 'user_id'])
+
+ data = []
+
+ for leave_type in leave_types:
+ for employee in active_employees:
+ row = [leave_type, employee.name, employee.employee_name]
+
+ leaves_taken = get_leaves_for_period(employee.name, leave_type,
+ filters.from_date, filters.to_date) * -1
+
+ opening = get_total_allocated_leaves(employee.name, leave_type, filters.from_date, filters.to_date)
+ closing = flt(opening) - flt(leaves_taken)
+
+ row += [opening, leaves_taken, closing]
+ data.append(row)
+
+ return data
From 16a7ec95dc8292efe98d4d817d3a0da1104dc0e7 Mon Sep 17 00:00:00 2001
From: Nabin Hait
Date: Thu, 5 Sep 2019 13:01:15 +0530
Subject: [PATCH 412/484] fix: tax category is optional argument
---
erpnext/accounts/party.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/accounts/party.py b/erpnext/accounts/party.py
index e42f4af2a5..26c2950f3a 100644
--- a/erpnext/accounts/party.py
+++ b/erpnext/accounts/party.py
@@ -365,7 +365,7 @@ def validate_due_date(posting_date, due_date, party_type, party, company=None, b
.format(formatdate(default_due_date)))
@frappe.whitelist()
-def get_address_tax_category(tax_category, billing_address=None, shipping_address=None):
+def get_address_tax_category(tax_category=None, billing_address=None, shipping_address=None):
addr_tax_category_from = frappe.db.get_single_value("Accounts Settings", "determine_address_tax_category_from")
if addr_tax_category_from == "Shipping Address":
if shipping_address:
From 5aaf15d145576b57a4e670166d21c5e49db51e4c Mon Sep 17 00:00:00 2001
From: rohitwaghchaure
Date: Thu, 5 Sep 2019 14:42:28 +0530
Subject: [PATCH 413/484] fix: healthcare practitioner not showing in the
dropdown (#18929)
---
.../healthcare_practitioner.py | 33 +++----------------
1 file changed, 5 insertions(+), 28 deletions(-)
diff --git a/erpnext/healthcare/doctype/healthcare_practitioner/healthcare_practitioner.py b/erpnext/healthcare/doctype/healthcare_practitioner/healthcare_practitioner.py
index ed9eae3529..ad32e94631 100644
--- a/erpnext/healthcare/doctype/healthcare_practitioner/healthcare_practitioner.py
+++ b/erpnext/healthcare/doctype/healthcare_practitioner/healthcare_practitioner.py
@@ -69,33 +69,10 @@ def validate_service_item(item, msg):
def get_practitioner_list(doctype, txt, searchfield, start, page_len, filters=None):
fields = ["name", "first_name", "mobile_phone"]
- match_conditions = build_match_conditions("Healthcare Practitioner")
- match_conditions = "and {}".format(match_conditions) if match_conditions else ""
- if filters:
- filter_conditions = get_filters_cond(doctype, filters, [])
- match_conditions += "{}".format(filter_conditions)
+ filters = {
+ 'name': ("like", "%%%s%%" % txt)
+ }
- return frappe.db.sql("""select %s from `tabHealthcare Practitioner` where docstatus < 2
- and (%s like %s or first_name like %s)
- and active = 1
- {match_conditions}
- order by
- case when name like %s then 0 else 1 end,
- case when first_name like %s then 0 else 1 end,
- name, first_name limit %s, %s""".format(
- match_conditions=match_conditions) %
- (
- ", ".join(fields),
- frappe.db.escape(searchfield),
- "%s", "%s", "%s", "%s", "%s", "%s"
- ),
- (
- "%%%s%%" % frappe.db.escape(txt),
- "%%%s%%" % frappe.db.escape(txt),
- "%%%s%%" % frappe.db.escape(txt),
- "%%%s%%" % frappe.db.escape(txt),
- start,
- page_len
- )
- )
+ return frappe.get_all("Healthcare Practitioner", fields = fields,
+ filters = filters, start=start, page_length=page_len, order_by="name, first_name", as_list=1)
From f1fab871b8d66d51638117344ba1cbee5a84ec12 Mon Sep 17 00:00:00 2001
From: rohitwaghchaure
Date: Thu, 5 Sep 2019 14:47:43 +0530
Subject: [PATCH 414/484] fix: mismatch between warehouse tree value and
warehouse based stock balance report value (#18879)
---
erpnext/stock/utils.py | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/erpnext/stock/utils.py b/erpnext/stock/utils.py
index 6ea322872e..aec37d4e94 100644
--- a/erpnext/stock/utils.py
+++ b/erpnext/stock/utils.py
@@ -15,7 +15,7 @@ def get_stock_value_from_bin(warehouse=None, item_code=None):
values = {}
conditions = ""
if warehouse:
- conditions += """ and warehouse in (
+ conditions += """ and `tabBin`.warehouse in (
select w2.name from `tabWarehouse` w1
join `tabWarehouse` w2 on
w1.name = %(warehouse)s
@@ -25,11 +25,12 @@ def get_stock_value_from_bin(warehouse=None, item_code=None):
values['warehouse'] = warehouse
if item_code:
- conditions += " and item_code = %(item_code)s"
+ conditions += " and `tabBin`.item_code = %(item_code)s"
values['item_code'] = item_code
- query = "select sum(stock_value) from `tabBin` where 1 = 1 %s" % conditions
+ query = """select sum(stock_value) from `tabBin`, `tabItem` where 1 = 1
+ and `tabItem`.name = `tabBin`.item_code and ifnull(`tabItem`.disabled, 0) = 0 %s""" % conditions
stock_value = frappe.db.sql(query, values)
From 7496548c3978b6991ff516021d4bd0cdd86ec932 Mon Sep 17 00:00:00 2001
From: rohitwaghchaure
Date: Thu, 5 Sep 2019 14:48:51 +0530
Subject: [PATCH 415/484] fix: not able to create invoice against patient
(#18858)
---
erpnext/healthcare/doctype/patient/patient.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/erpnext/healthcare/doctype/patient/patient.py b/erpnext/healthcare/doctype/patient/patient.py
index bf15cad5d5..e3eea96f85 100644
--- a/erpnext/healthcare/doctype/patient/patient.py
+++ b/erpnext/healthcare/doctype/patient/patient.py
@@ -6,7 +6,7 @@ from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.model.document import Document
-from frappe.utils import cint, cstr, getdate
+from frappe.utils import cint, cstr, getdate, flt
import dateutil
from frappe.model.naming import set_name_by_naming_series
from erpnext.healthcare.doctype.healthcare_settings.healthcare_settings import get_receivable_account,get_income_account,send_registration_sms
@@ -64,7 +64,7 @@ class Patient(Document):
def invoice_patient_registration(self):
frappe.db.set_value("Patient", self.name, "disabled", 0)
send_registration_sms(self)
- if(frappe.get_value("Healthcare Settings", None, "registration_fee")>0):
+ if(flt(frappe.get_value("Healthcare Settings", None, "registration_fee"))>0):
company = frappe.defaults.get_user_default('company')
if not company:
company = frappe.db.get_value("Global Defaults", None, "default_company")
From c901d6322c45034d9240b1ac6284090d1b8c56d9 Mon Sep 17 00:00:00 2001
From: Govind S Menokee
Date: Thu, 5 Sep 2019 14:50:23 +0530
Subject: [PATCH 416/484] fix(18837): Student creation error (#18838)
Academic user not able to create student
---
erpnext/education/doctype/student/student.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/erpnext/education/doctype/student/student.py b/erpnext/education/doctype/student/student.py
index da25880c81..705c6e4e98 100644
--- a/erpnext/education/doctype/student/student.py
+++ b/erpnext/education/doctype/student/student.py
@@ -54,6 +54,7 @@ class Student(Document):
'send_welcome_email': 1,
'user_type': 'Website User'
})
+ student_user.flags.ignore_permissions = True
student_user.add_roles("Student")
student_user.save()
update_password_link = student_user.reset_password()
From 9d77e9f719b47f8c38fbabac8f20252249cc3d12 Mon Sep 17 00:00:00 2001
From: Rohan
Date: Thu, 5 Sep 2019 14:51:22 +0530
Subject: [PATCH 417/484] fix: error while trying to get directions (#18827)
---
erpnext/stock/doctype/delivery_trip/delivery_trip.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/stock/doctype/delivery_trip/delivery_trip.py b/erpnext/stock/doctype/delivery_trip/delivery_trip.py
index a253811b27..77d322ed28 100644
--- a/erpnext/stock/doctype/delivery_trip/delivery_trip.py
+++ b/erpnext/stock/doctype/delivery_trip/delivery_trip.py
@@ -238,7 +238,7 @@ class DeliveryTrip(Document):
try:
directions = maps_client.directions(**directions_data)
except Exception as e:
- frappe.throw(_(e.message))
+ frappe.throw(_(e))
return directions[0] if directions else False
From 77da3b4347ade309d1547e872c1fb9b89b71775f Mon Sep 17 00:00:00 2001
From: Rohan
Date: Thu, 5 Sep 2019 14:53:43 +0530
Subject: [PATCH 418/484] fix: pull project from task (#18776)
---
erpnext/projects/doctype/timesheet/timesheet.js | 12 +++++++++---
erpnext/projects/doctype/timesheet/timesheet.py | 5 +++++
2 files changed, 14 insertions(+), 3 deletions(-)
diff --git a/erpnext/projects/doctype/timesheet/timesheet.js b/erpnext/projects/doctype/timesheet/timesheet.js
index 101d903bed..3eea390ff3 100644
--- a/erpnext/projects/doctype/timesheet/timesheet.js
+++ b/erpnext/projects/doctype/timesheet/timesheet.js
@@ -147,6 +147,15 @@ frappe.ui.form.on("Timesheet Detail", {
calculate_time_and_amount(frm);
},
+ task: (frm, cdt, cdn) => {
+ let row = frm.selected_doc;
+ if (row.task) {
+ frappe.db.get_value("Task", row.task, "project", (r) => {
+ frappe.model.set_value(cdt, cdn, "project", r.project);
+ });
+ }
+ },
+
from_time: function(frm, cdt, cdn) {
calculate_end_time(frm, cdt, cdn);
},
@@ -200,9 +209,6 @@ frappe.ui.form.on("Timesheet Detail", {
},
activity_type: function(frm, cdt, cdn) {
- frm.script_manager.copy_from_first_row('time_logs', frm.selected_doc,
- 'project');
-
frappe.call({
method: "erpnext.projects.doctype.timesheet.timesheet.get_activity_cost",
args: {
diff --git a/erpnext/projects/doctype/timesheet/timesheet.py b/erpnext/projects/doctype/timesheet/timesheet.py
index 3c719227bd..9ee292796c 100644
--- a/erpnext/projects/doctype/timesheet/timesheet.py
+++ b/erpnext/projects/doctype/timesheet/timesheet.py
@@ -145,12 +145,17 @@ class Timesheet(Document):
def validate_time_logs(self):
for data in self.get('time_logs'):
self.validate_overlap(data)
+ self.validate_task_project()
def validate_overlap(self, data):
settings = frappe.get_single('Projects Settings')
self.validate_overlap_for("user", data, self.user, settings.ignore_user_time_overlap)
self.validate_overlap_for("employee", data, self.employee, settings.ignore_employee_time_overlap)
+ def validate_task_project(self):
+ for log in self.time_logs:
+ log.project = log.project or frappe.db.get_value("Task", log.task, "project")
+
def validate_overlap_for(self, fieldname, args, value, ignore_validation=False):
if not value or ignore_validation:
return
From a7d448dcbaa11280fa973d08f912bec1a3a445cb Mon Sep 17 00:00:00 2001
From: John Clarke
Date: Thu, 5 Sep 2019 03:25:35 -0600
Subject: [PATCH 419/484] fix: Error "TypeError: unorderable types: int() >
str()" When Trying to Create Packing Slip (#18913)
User report here https://discuss.erpnext.com/t/error-typeerror-unorderable-types-int-str-when-trying-to-create-packing-slip/52445
This has not been noted to github issues and is just a suggested fix, an expert may need to refactor more here?
User and traceback does not state whether Python 2 or 3 but perhaps 3 since that apparently does not 'guess' when types do not match?
See also https://stackoverflow.com/questions/14886881/unorderable-types-int-str
---
erpnext/stock/doctype/packing_slip/packing_slip.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/stock/doctype/packing_slip/packing_slip.py b/erpnext/stock/doctype/packing_slip/packing_slip.py
index b99215c426..4139a19abf 100644
--- a/erpnext/stock/doctype/packing_slip/packing_slip.py
+++ b/erpnext/stock/doctype/packing_slip/packing_slip.py
@@ -49,7 +49,7 @@ class PackingSlip(Document):
frappe.msgprint(_("Please specify a valid 'From Case No.'"), raise_exception=1)
elif not self.to_case_no:
self.to_case_no = self.from_case_no
- elif self.from_case_no > self.to_case_no:
+ elif cint(self.from_case_no) > cint(self.to_case_no):
frappe.msgprint(_("'To Case No.' cannot be less than 'From Case No.'"),
raise_exception=1)
From 91596f2467ecc48166700627d1c4a9fcd24bbcbf Mon Sep 17 00:00:00 2001
From: Andy Zhu <30763348+AndyOverLord@users.noreply.github.com>
Date: Thu, 5 Sep 2019 21:31:38 +1200
Subject: [PATCH 420/484] Change the field name for Payment Entry (#18874)
In the Payment Entry Form, the field name for customer name is 'party' instead of 'party_name'.
Need to change the customer_dashboard file accordingly.
---
erpnext/selling/doctype/customer/customer_dashboard.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/selling/doctype/customer/customer_dashboard.py b/erpnext/selling/doctype/customer/customer_dashboard.py
index 8e790bf9ce..654dd48c66 100644
--- a/erpnext/selling/doctype/customer/customer_dashboard.py
+++ b/erpnext/selling/doctype/customer/customer_dashboard.py
@@ -9,7 +9,7 @@ def get_data():
'heatmap_message': _('This is based on transactions against this Customer. See timeline below for details'),
'fieldname': 'customer',
'non_standard_fieldnames': {
- 'Payment Entry': 'party_name',
+ 'Payment Entry': 'party',
'Quotation': 'party_name',
'Opportunity': 'party_name'
},
From 1d1427de60c3070f2fd6103a04c0037c45c669de Mon Sep 17 00:00:00 2001
From: Karthikeyan S
Date: Thu, 5 Sep 2019 15:02:33 +0530
Subject: [PATCH 421/484] fix(auto attendance): handling None case for IN/OUT
Logs (#18867)
---
erpnext/hr/doctype/employee_checkin/employee_checkin.py | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/erpnext/hr/doctype/employee_checkin/employee_checkin.py b/erpnext/hr/doctype/employee_checkin/employee_checkin.py
index d7d6706140..86705121ac 100644
--- a/erpnext/hr/doctype/employee_checkin/employee_checkin.py
+++ b/erpnext/hr/doctype/employee_checkin/employee_checkin.py
@@ -142,8 +142,10 @@ def calculate_working_hours(logs, check_in_out_type, working_hours_calc_type):
elif check_in_out_type == 'Strictly based on Log Type in Employee Checkin':
if working_hours_calc_type == 'First Check-in and Last Check-out':
- first_in_log = logs[find_index_in_dict(logs, 'log_type', 'IN')]
- last_out_log = logs[len(logs)-1-find_index_in_dict(reversed(logs), 'log_type', 'OUT')]
+ first_in_log_index = find_index_in_dict(logs, 'log_type', 'IN')
+ first_in_log = logs[first_in_log_index] if first_in_log_index or first_in_log_index == 0 else None
+ last_out_log_index = find_index_in_dict(reversed(logs), 'log_type', 'OUT')
+ last_out_log = logs[len(logs)-1-last_out_log_index] if last_out_log_index or last_out_log_index == 0 else None
if first_in_log and last_out_log:
in_time, out_time = first_in_log.time, last_out_log.time
total_hours = time_diff_in_hours(in_time, out_time)
From d114c8f88fde3ed412c071b7cf60876535389ea0 Mon Sep 17 00:00:00 2001
From: KanchanChauhan
Date: Thu, 5 Sep 2019 15:11:43 +0530
Subject: [PATCH 422/484] fix(Purchase Order): Status updater (#18612)
---
erpnext/buying/doctype/purchase_order/purchase_order_list.js | 4 ++--
erpnext/controllers/status_updater.py | 4 ++--
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order_list.js b/erpnext/buying/doctype/purchase_order/purchase_order_list.js
index a67d69dc26..8413eb65c3 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order_list.js
+++ b/erpnext/buying/doctype/purchase_order/purchase_order_list.js
@@ -16,9 +16,9 @@ frappe.listview_settings['Purchase Order'] = {
return [__("To Receive"), "orange",
"per_received,<,100|per_billed,=,100|status,!=,Closed"];
}
- } else if (flt(doc.per_received, 2) == 100 && flt(doc.per_billed, 2) < 100 && doc.status !== "Closed") {
+ } else if (flt(doc.per_received, 2) >= 100 && flt(doc.per_billed, 2) < 100 && doc.status !== "Closed") {
return [__("To Bill"), "orange", "per_received,=,100|per_billed,<,100|status,!=,Closed"];
- } else if (flt(doc.per_received, 2) == 100 && flt(doc.per_billed, 2) == 100 && doc.status !== "Closed") {
+ } else if (flt(doc.per_received, 2) >= 100 && flt(doc.per_billed, 2) == 100 && doc.status !== "Closed") {
return [__("Completed"), "green", "per_received,=,100|per_billed,=,100|status,!=,Closed"];
}
},
diff --git a/erpnext/controllers/status_updater.py b/erpnext/controllers/status_updater.py
index b2057ca40f..64d49b4549 100644
--- a/erpnext/controllers/status_updater.py
+++ b/erpnext/controllers/status_updater.py
@@ -57,9 +57,9 @@ status_map = {
"Purchase Order": [
["Draft", None],
["To Receive and Bill", "eval:self.per_received < 100 and self.per_billed < 100 and self.docstatus == 1"],
- ["To Bill", "eval:self.per_received == 100 and self.per_billed < 100 and self.docstatus == 1"],
+ ["To Bill", "eval:self.per_received >= 100 and self.per_billed < 100 and self.docstatus == 1"],
["To Receive", "eval:self.per_received < 100 and self.per_billed == 100 and self.docstatus == 1"],
- ["Completed", "eval:self.per_received == 100 and self.per_billed == 100 and self.docstatus == 1"],
+ ["Completed", "eval:self.per_received >= 100 and self.per_billed == 100 and self.docstatus == 1"],
["Delivered", "eval:self.status=='Delivered'"],
["Cancelled", "eval:self.docstatus==2"],
["On Hold", "eval:self.status=='On Hold'"],
From 867ac10ffd71a058c4dcafc29374d6a8f86e535d Mon Sep 17 00:00:00 2001
From: Anurag Mishra <32095923+Anurag810@users.noreply.github.com>
Date: Thu, 5 Sep 2019 15:13:21 +0530
Subject: [PATCH 423/484] fix: handle for product bundle (#18420)
* fix: handle for product bundle
* fix: Requested changes and some general fixes
---
.../doctype/sales_order/sales_order.py | 2 +-
.../pending_so_items_for_purchase_request.py | 92 ++++++++++++++-----
erpnext/stock/get_item_details.py | 2 +-
3 files changed, 69 insertions(+), 27 deletions(-)
diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py
index c9aaab4b21..67fa0d43c8 100755
--- a/erpnext/selling/doctype/sales_order/sales_order.py
+++ b/erpnext/selling/doctype/sales_order/sales_order.py
@@ -518,7 +518,7 @@ def make_material_request(source_name, target_doc=None):
"doctype": "Material Request Item",
"field_map": {
"parent": "sales_order",
- "stock_uom": "uom"
+ "uom": "stock_uom"
},
"postprocess": update_item
},
diff --git a/erpnext/selling/report/pending_so_items_for_purchase_request/pending_so_items_for_purchase_request.py b/erpnext/selling/report/pending_so_items_for_purchase_request/pending_so_items_for_purchase_request.py
index 670b4e98bf..14d8031582 100644
--- a/erpnext/selling/report/pending_so_items_for_purchase_request/pending_so_items_for_purchase_request.py
+++ b/erpnext/selling/report/pending_so_items_for_purchase_request/pending_so_items_for_purchase_request.py
@@ -4,7 +4,7 @@
from __future__ import unicode_literals
import frappe
from frappe import _
-from frappe.utils import cint,cstr
+from frappe.utils import flt
def execute(filters=None):
columns = get_columns()
@@ -100,7 +100,7 @@ def get_data():
so.transaction_date,
so.customer,
so.territory,
- sum(so_item.qty) as net_qty,
+ sum(so_item.qty) as total_qty,
so.company
FROM `tabSales Order` so, `tabSales Order Item` so_item
WHERE
@@ -111,10 +111,15 @@ def get_data():
so.name,so_item.item_code
""", as_dict = 1)
+ sales_orders = [row.name for row in sales_order_entry]
mr_records = frappe.get_all("Material Request Item",
- {"sales_order_item": ("!=",""), "docstatus": 1},
+ {"sales_order": ("in", sales_orders), "docstatus": 1},
["parent", "qty", "sales_order", "item_code"])
+ bundled_item_map = get_packed_items(sales_orders)
+
+ item_with_product_bundle = get_items_with_product_bundle([row.item_code for row in sales_order_entry])
+
materials_request_dict = {}
for record in mr_records:
@@ -131,27 +136,64 @@ def get_data():
if record.parent not in details.get('material_requests'):
details['material_requests'].append(record.parent)
- pending_so=[]
+ pending_so = []
for so in sales_order_entry:
- # fetch all the material request records for a sales order item
- key = (so.name, so.item_code)
- materials_request = materials_request_dict.get(key) or {}
+ if so.item_code not in item_with_product_bundle:
+ material_requests_against_so = materials_request_dict.get((so.name, so.item_code)) or {}
+ # check for pending sales order
+ if flt(so.total_qty) > flt(material_requests_against_so.get('qty')):
+ so_record = {
+ "item_code": so.item_code,
+ "item_name": so.item_name,
+ "description": so.description,
+ "sales_order_no": so.name,
+ "date": so.transaction_date,
+ "material_request": ','.join(material_requests_against_so.get('material_requests', [])),
+ "customer": so.customer,
+ "territory": so.territory,
+ "so_qty": so.total_qty,
+ "requested_qty": material_requests_against_so.get('qty'),
+ "pending_qty": so.total_qty - flt(material_requests_against_so.get('qty')),
+ "company": so.company
+ }
+ pending_so.append(so_record)
+ else:
+ for item in bundled_item_map.get((so.name, so.item_code)):
+ material_requests_against_so = materials_request_dict.get((so.name, item.item_code)) or {}
+ if flt(item.qty) > flt(material_requests_against_so.get('qty')):
+ so_record = {
+ "item_code": item.item_code,
+ "item_name": item.item_name,
+ "description": item.description,
+ "sales_order_no": so.name,
+ "date": so.transaction_date,
+ "material_request": ','.join(material_requests_against_so.get('material_requests', [])),
+ "customer": so.customer,
+ "territory": so.territory,
+ "so_qty": item.qty,
+ "requested_qty": material_requests_against_so.get('qty', 0),
+ "pending_qty": item.qty - flt(material_requests_against_so.get('qty', 0)),
+ "company": so.company
+ }
+ pending_so.append(so_record)
- # check for pending sales order
- if cint(so.net_qty) > cint(materials_request.get('qty')):
- so_record = {
- "item_code": so.item_code,
- "item_name": so.item_name,
- "description": so.description,
- "sales_order_no": so.name,
- "date": so.transaction_date,
- "material_request": ','.join(materials_request.get('material_requests', [])),
- "customer": so.customer,
- "territory": so.territory,
- "so_qty": so.net_qty,
- "requested_qty": cint(materials_request.get('qty')),
- "pending_qty": so.net_qty - cint(materials_request.get('qty')),
- "company": so.company
- }
- pending_so.append(so_record)
- return pending_so
\ No newline at end of file
+
+ return pending_so
+
+def get_items_with_product_bundle(item_list):
+ bundled_items = frappe.get_all("Product Bundle", filters = [
+ ("new_item_code", "IN", item_list)
+ ], fields = ["new_item_code"])
+
+ return [d.new_item_code for d in bundled_items]
+
+def get_packed_items(sales_order_list):
+ packed_items = frappe.get_all("Packed Item", filters = [
+ ("parent", "IN", sales_order_list)
+ ], fields = ["parent_item", "item_code", "qty", "item_name", "description", "parent"])
+
+ bundled_item_map = frappe._dict()
+ for d in packed_items:
+ bundled_item_map.setdefault((d.parent, d.parent_item), []).append(d)
+
+ return bundled_item_map
diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py
index bf5a8180bd..35c0bb6165 100644
--- a/erpnext/stock/get_item_details.py
+++ b/erpnext/stock/get_item_details.py
@@ -639,7 +639,7 @@ def validate_price_list(args):
if not frappe.db.get_value("Price List",
{"name": args.price_list, args.transaction_type: 1, "enabled": 1}):
throw(_("Price List {0} is disabled or does not exist").format(args.price_list))
- elif not args.get("supplier"):
+ elif args.get("customer"):
throw(_("Price List not selected"))
def validate_conversion_rate(args, meta):
From c257ce82c5a8897247a2ee8c132110329a96858f Mon Sep 17 00:00:00 2001
From: hendrik
Date: Thu, 5 Sep 2019 16:44:09 +0700
Subject: [PATCH 424/484] Party accounts if don't have default company (#18771)
Add check for get_default company
---
erpnext/accounts/party.py | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/erpnext/accounts/party.py b/erpnext/accounts/party.py
index 26c2950f3a..59936d5116 100644
--- a/erpnext/accounts/party.py
+++ b/erpnext/accounts/party.py
@@ -292,8 +292,11 @@ def validate_party_accounts(doc):
party_account_currency = frappe.db.get_value("Account", account.account, "account_currency", cache=True)
existing_gle_currency = get_party_gle_currency(doc.doctype, doc.name, account.company)
- company_default_currency = frappe.get_cached_value('Company',
- frappe.db.get_default("Company"), "default_currency")
+ if frappe.db.get_default("Company"):
+ company_default_currency = frappe.get_cached_value('Company',
+ frappe.db.get_default("Company"), "default_currency")
+ else:
+ company_default_currency = frappe.db.get_value('Company', account.company, "default_currency")
if existing_gle_currency and party_account_currency != existing_gle_currency:
frappe.throw(_("Accounting entries have already been made in currency {0} for company {1}. Please select a receivable or payable account with currency {0}.").format(existing_gle_currency, account.company))
@@ -607,4 +610,4 @@ def get_partywise_advanced_payment_amount(party_type, posting_date = None):
.format(("credit") if party_type == "Customer" else "debit", cond) , party_type)
if data:
- return frappe._dict(data)
\ No newline at end of file
+ return frappe._dict(data)
From 48d1463825578fa288ec4e895e7c35dcbb0b44b9 Mon Sep 17 00:00:00 2001
From: Raffael Meyer
Date: Thu, 5 Sep 2019 04:45:28 -0500
Subject: [PATCH 425/484] fix(CoA): SKR04 (#18820)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- move debitors into receivables
- move creditors into payables
- rename "C - Verb." to "C-Verbindlichkeiten" for consitency
- move "Erlösschmälerungen" into a root of type "Expense"
- move "Erhaltene Boni" and "Erhaltene Rabatte" into a root of type "Income"
---
..._kontenplan_SKR04_with_account_number.json | 286 +++++++++---------
1 file changed, 143 insertions(+), 143 deletions(-)
diff --git a/erpnext/accounts/doctype/account/chart_of_accounts/verified/de_kontenplan_SKR04_with_account_number.json b/erpnext/accounts/doctype/account/chart_of_accounts/verified/de_kontenplan_SKR04_with_account_number.json
index b042bcc420..adfa9f89e2 100644
--- a/erpnext/accounts/doctype/account/chart_of_accounts/verified/de_kontenplan_SKR04_with_account_number.json
+++ b/erpnext/accounts/doctype/account/chart_of_accounts/verified/de_kontenplan_SKR04_with_account_number.json
@@ -406,7 +406,11 @@
"is_group": 1,
"Bewertungskorrektur zu Forderungen aus Lieferungen und Leistungen": {
"account_number": "9960"
- },
+ },
+ "Debitoren": {
+ "is_group": 1,
+ "account_number": "10000"
+ },
"Forderungen aus Lieferungen und Leistungen": {
"account_number": "1200",
"account_type": "Receivable"
@@ -1077,7 +1081,7 @@
}
}
},
- "C - Verb.": {
+ "C - Verbindlichkeiten": {
"account_type": "Payable",
"1 - Anleihen": {
"is_group": 1,
@@ -1193,7 +1197,15 @@
"is_group": 1,
"Bewertungskorrektur zu Verb. aus Lieferungen und Leistungen": {
"account_number": "9964"
- },
+ },
+ "Kreditoren": {
+ "account_number": "70000",
+ "is_group": 1,
+ "Wareneingangs-ÂVerrechnungskonto" : {
+ "account_number": "70001",
+ "account_type": "Stock Received But Not Billed"
+ }
+ },
"Verb. aus Lieferungen und Leistungen": {
"account_number": "3300",
"account_type": "Payable"
@@ -1682,90 +1694,6 @@
"account_type": "Income Account"
}
},
- "Erl\u00f6sschm\u00e4lerungen (Gruppe)": {
- "is_group": 1,
- "Erl\u00f6sschm\u00e4lerungen": {
- "account_number": "4700"
- },
- "Erl\u00f6sschm\u00e4lerungen aus steuerfreien Ums\u00e4tzen \u00a7 4 Nr. 1a UStG": {
- "account_number": "4705"
- },
- "Erl\u00f6sschm\u00e4lerungen 7 % USt": {
- "account_number": "4710"
- },
- "Erl\u00f6sschm\u00e4lerungen 19 % USt": {
- "account_number": "4720"
- },
- "Erl\u00f6sschm\u00e4lerungen 16 % USt": {
- "account_number": "4723"
- },
- "Erl\u00f6sschm\u00e4lerungen aus steuerfreien innergem. Lieferungen": {
- "account_number": "4724"
- },
- "Erl\u00f6sschm\u00e4lerungen aus im Inland steuerpfl. EU-Lieferungen 7 % USt": {
- "account_number": "4725"
- },
- "Erl\u00f6sschm\u00e4lerungen aus im Inland steuerpfl. EU-Lieferungen 19 % USt": {
- "account_number": "4726"
- },
- "Erl\u00f6sschm\u00e4lerungen aus im anderen EU-Land steuerpfl. Lieferungen": {
- "account_number": "4727"
- },
- "Erl\u00f6sschm\u00e4lerungen aus im Inland steuerpfl. EU-Lieferungen 16 % USt": {
- "account_number": "4729"
- },
- "Gew\u00e4hrte Skonti (Gruppe)": {
- "is_group": 1,
- "Gew. Skonti": {
- "account_number": "4730"
- },
- "Gew. Skonti 7 % USt": {
- "account_number": "4731"
- },
- "Gew. Skonti 19 % USt": {
- "account_number": "4736"
- },
- "Gew. Skonti aus Lieferungen von Mobilfunkger./Schaltkr., f. die der Leistungsempf. die Ust. schuldet": {
- "account_number": "4738"
- },
- "Gew. Skonti aus Leistungen, f. die der Leistungsempf. die Umsatzsteuer nach \u00a7 13b UStG schuldet": {
- "account_number": "4741"
- },
- "Gew. Skonti aus Erl\u00f6sen aus im anderen EU-Land steuerpfl. Leistungen, f. die der Leistungsempf. die Ust. schuldet": {
- "account_number": "4742"
- },
- "Gew. Skonti aus steuerfreien innergem. Lieferungen \u00a7 4 Nr. 1b UStG": {
- "account_number": "4743"
- },
- "Gew. Skonti aus im Inland steuerpfl. EU-Lieferungen": {
- "account_number": "4745"
- },
- "Gew. Skonti aus im Inland steuerpfl. EU-Lieferungen 7% USt": {
- "account_number": "4746"
- },
- "Gew. Skonti aus im Inland steuerpfl. EU-Lieferungen 19% USt": {
- "account_number": "4748"
- }
- },
- "Gew\u00e4hrte Boni 7 % USt": {
- "account_number": "4750"
- },
- "Gew\u00e4hrte Boni 19 % USt": {
- "account_number": "4760"
- },
- "Gew\u00e4hrte Boni": {
- "account_number": "4769"
- },
- "Gew\u00e4hrte Rabatte": {
- "account_number": "4770"
- },
- "Gew\u00e4hrte Rabatte 7 % USt": {
- "account_number": "4780"
- },
- "Gew\u00e4hrte Rabatte 19 % USt": {
- "account_number": "4790"
- }
- },
"Grundst\u00fccksertr\u00e4ge (Gruppe)": {
"is_group": 1,
"Grundst\u00fccksertr\u00e4ge": {
@@ -2049,48 +1977,6 @@
"Erh. Skonti aus Erwerb Waren als letzter Abnehmer innerh. Dreiecksgesch. 19% Vorst. u. 19% Ust.": {
"account_number": "5793"
}
- },
- "Erhaltene Boni (Gruppe)": {
- "is_group": 1,
- "Erhaltene Boni 7 % Vorsteuer": {
- "account_number": "5750"
- },
- "Erhaltene Boni aus Einkauf Roh-, Hilfs- und Betriebsstoffe": {
- "account_number": "5753"
- },
- "Erhaltene Boni aus Einkauf Roh-, Hilfs- und Betriebsstoffe 7% Vorsteuer": {
- "account_number": "5754"
- },
- "Erhaltene Boni aus Einkauf Roh-, Hilfs- und Betriebsstoffe 19% Vorsteuer": {
- "account_number": "5755"
- },
- "Erhaltene Boni 19 % Vorsteuer": {
- "account_number": "5760"
- },
- "Erhaltene Boni": {
- "account_number": "5769"
- }
- },
- "Erhaltene Rabatte (Gruppe)": {
- "is_group": 1,
- "Erhaltene Rabatte": {
- "account_number": "5770"
- },
- "Erhaltene Rabatte 7 % Vorsteuer": {
- "account_number": "5780"
- },
- "Erhaltene Rabatte aus Einkauf Roh-, Hilfs- und Betriebsstoffe": {
- "account_number": "5783"
- },
- "Erhaltene Rabatte aus Einkauf Roh-, Hilfs- und Betriebsstoffe 7% Vorsteuer": {
- "account_number": "5784"
- },
- "Erhaltene Rabatte aus Einkauf Roh-, Hilfs- und Betriebsstoffe 19% Vorsteuer": {
- "account_number": "5785"
- },
- "Erhaltene Rabatte 19 % Vorsteuer": {
- "account_number": "5790"
- }
}
},
"Bezugsnebenkosten (Gruppe)": {
@@ -2409,7 +2295,49 @@
},
"6 - sonstige betriebliche Ertr\u00e4ge": {
"root_type": "Income",
- "is_group": 1,
+ "is_group": 1,
+ "Erhaltene Boni (Gruppe)": {
+ "is_group": 1,
+ "Erhaltene Boni 7 % Vorsteuer": {
+ "account_number": "5750"
+ },
+ "Erhaltene Boni aus Einkauf Roh-, Hilfs- und Betriebsstoffe": {
+ "account_number": "5753"
+ },
+ "Erhaltene Boni aus Einkauf Roh-, Hilfs- und Betriebsstoffe 7% Vorsteuer": {
+ "account_number": "5754"
+ },
+ "Erhaltene Boni aus Einkauf Roh-, Hilfs- und Betriebsstoffe 19% Vorsteuer": {
+ "account_number": "5755"
+ },
+ "Erhaltene Boni 19 % Vorsteuer": {
+ "account_number": "5760"
+ },
+ "Erhaltene Boni": {
+ "account_number": "5769"
+ }
+ },
+ "Erhaltene Rabatte (Gruppe)": {
+ "is_group": 1,
+ "Erhaltene Rabatte": {
+ "account_number": "5770"
+ },
+ "Erhaltene Rabatte 7 % Vorsteuer": {
+ "account_number": "5780"
+ },
+ "Erhaltene Rabatte aus Einkauf Roh-, Hilfs- und Betriebsstoffe": {
+ "account_number": "5783"
+ },
+ "Erhaltene Rabatte aus Einkauf Roh-, Hilfs- und Betriebsstoffe 7% Vorsteuer": {
+ "account_number": "5784"
+ },
+ "Erhaltene Rabatte aus Einkauf Roh-, Hilfs- und Betriebsstoffe 19% Vorsteuer": {
+ "account_number": "5785"
+ },
+ "Erhaltene Rabatte 19 % Vorsteuer": {
+ "account_number": "5790"
+ }
+ },
"Andere aktivierte Eigenleistungen": {
"account_number": "4820"
},
@@ -2732,7 +2660,91 @@
},
"7 - sonstige betriebliche Aufwendungen": {
"root_type": "Expense",
- "is_group": 1,
+ "is_group": 1,
+ "Erl\u00f6sschm\u00e4lerungen (Gruppe)": {
+ "is_group": 1,
+ "Erl\u00f6sschm\u00e4lerungen": {
+ "account_number": "4700"
+ },
+ "Erl\u00f6sschm\u00e4lerungen aus steuerfreien Ums\u00e4tzen \u00a7 4 Nr. 1a UStG": {
+ "account_number": "4705"
+ },
+ "Erl\u00f6sschm\u00e4lerungen 7 % USt": {
+ "account_number": "4710"
+ },
+ "Erl\u00f6sschm\u00e4lerungen 19 % USt": {
+ "account_number": "4720"
+ },
+ "Erl\u00f6sschm\u00e4lerungen 16 % USt": {
+ "account_number": "4723"
+ },
+ "Erl\u00f6sschm\u00e4lerungen aus steuerfreien innergem. Lieferungen": {
+ "account_number": "4724"
+ },
+ "Erl\u00f6sschm\u00e4lerungen aus im Inland steuerpfl. EU-Lieferungen 7 % USt": {
+ "account_number": "4725"
+ },
+ "Erl\u00f6sschm\u00e4lerungen aus im Inland steuerpfl. EU-Lieferungen 19 % USt": {
+ "account_number": "4726"
+ },
+ "Erl\u00f6sschm\u00e4lerungen aus im anderen EU-Land steuerpfl. Lieferungen": {
+ "account_number": "4727"
+ },
+ "Erl\u00f6sschm\u00e4lerungen aus im Inland steuerpfl. EU-Lieferungen 16 % USt": {
+ "account_number": "4729"
+ },
+ "Gew\u00e4hrte Skonti (Gruppe)": {
+ "is_group": 1,
+ "Gew. Skonti": {
+ "account_number": "4730"
+ },
+ "Gew. Skonti 7 % USt": {
+ "account_number": "4731"
+ },
+ "Gew. Skonti 19 % USt": {
+ "account_number": "4736"
+ },
+ "Gew. Skonti aus Lieferungen von Mobilfunkger./Schaltkr., f. die der Leistungsempf. die Ust. schuldet": {
+ "account_number": "4738"
+ },
+ "Gew. Skonti aus Leistungen, f. die der Leistungsempf. die Umsatzsteuer nach \u00a7 13b UStG schuldet": {
+ "account_number": "4741"
+ },
+ "Gew. Skonti aus Erl\u00f6sen aus im anderen EU-Land steuerpfl. Leistungen, f. die der Leistungsempf. die Ust. schuldet": {
+ "account_number": "4742"
+ },
+ "Gew. Skonti aus steuerfreien innergem. Lieferungen \u00a7 4 Nr. 1b UStG": {
+ "account_number": "4743"
+ },
+ "Gew. Skonti aus im Inland steuerpfl. EU-Lieferungen": {
+ "account_number": "4745"
+ },
+ "Gew. Skonti aus im Inland steuerpfl. EU-Lieferungen 7% USt": {
+ "account_number": "4746"
+ },
+ "Gew. Skonti aus im Inland steuerpfl. EU-Lieferungen 19% USt": {
+ "account_number": "4748"
+ }
+ },
+ "Gew\u00e4hrte Boni 7 % USt": {
+ "account_number": "4750"
+ },
+ "Gew\u00e4hrte Boni 19 % USt": {
+ "account_number": "4760"
+ },
+ "Gew\u00e4hrte Boni": {
+ "account_number": "4769"
+ },
+ "Gew\u00e4hrte Rabatte": {
+ "account_number": "4770"
+ },
+ "Gew\u00e4hrte Rabatte 7 % USt": {
+ "account_number": "4780"
+ },
+ "Gew\u00e4hrte Rabatte 19 % USt": {
+ "account_number": "4790"
+ }
+ },
"Sonstige betriebliche Aufwendungen": {
"account_number": "6300"
},
@@ -3609,18 +3621,6 @@
"Ertr\u00e4ge aus der Aufl\u00f6sung von R\u00fcckstellungen f. sonstige Steuern": {
"account_number": "7694"
}
- },
- "Debitoren": {
- "root_type": "Asset",
- "is_group": 1
- },
- "Kreditoren": {
- "root_type": "Liability",
- "is_group": 1,
- "Wareneingangs-ÂVerrechnungskonto" : {
- "account_number": "70001",
- "account_type": "Stock Received But Not Billed"
- }
}
}
}
From cffe577028ef63628c86bedab1c939ccb14f9707 Mon Sep 17 00:00:00 2001
From: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com>
Date: Thu, 5 Sep 2019 16:03:15 +0530
Subject: [PATCH 426/484] fix: Add UOM in anlytics report when viewing based on
item (#18902)
---
.../report/sales_analytics/sales_analytics.py | 19 ++++++++++++++++++-
1 file changed, 18 insertions(+), 1 deletion(-)
diff --git a/erpnext/selling/report/sales_analytics/sales_analytics.py b/erpnext/selling/report/sales_analytics/sales_analytics.py
index 8a5e50a61e..72767f0689 100644
--- a/erpnext/selling/report/sales_analytics/sales_analytics.py
+++ b/erpnext/selling/report/sales_analytics/sales_analytics.py
@@ -40,6 +40,16 @@ class Analytics(object):
"fieldtype": "Data",
"width": 140
})
+
+ if self.filters.tree_type == "Item":
+ self.columns.append({
+ "label": _("UOM"),
+ "fieldname": 'stock_uom',
+ "fieldtype": "Link",
+ "options": "UOM",
+ "width": 100
+ })
+
for end_date in self.periodic_daterange:
period = self.get_period(end_date)
self.columns.append({
@@ -129,7 +139,7 @@ class Analytics(object):
value_field = 'qty'
self.entries = frappe.db.sql("""
- select i.item_code as entity, i.item_name as entity_name, i.{value_field} as value_field, s.{date_field}
+ select i.item_code as entity, i.item_name as entity_name, i.stock_uom, i.{value_field} as value_field, s.{date_field}
from `tab{doctype} Item` i , `tab{doctype}` s
where s.name = i.parent and i.docstatus = 1 and s.company = %s
and s.{date_field} between %s and %s
@@ -198,6 +208,10 @@ class Analytics(object):
total += amount
row["total"] = total
+
+ if self.filters.tree_type == "Item":
+ row["stock_uom"] = period_data.get("stock_uom")
+
self.data.append(row)
def get_rows_by_group(self):
@@ -232,6 +246,9 @@ class Analytics(object):
self.entity_periodic_data.setdefault(d.entity, frappe._dict()).setdefault(period, 0.0)
self.entity_periodic_data[d.entity][period] += flt(d.value_field)
+ if self.filters.tree_type == "Item":
+ self.entity_periodic_data[d.entity]['stock_uom'] = d.stock_uom
+
def get_period(self, posting_date):
if self.filters.range == 'Weekly':
period = "Week " + str(posting_date.isocalendar()[1]) + " " + str(posting_date.year)
From 6298da44586d1fd34c117812819240a3469b7165 Mon Sep 17 00:00:00 2001
From: Himanshu
Date: Thu, 5 Sep 2019 16:12:33 +0530
Subject: [PATCH 427/484] fix: treeview fixes (#18803)
---
.../doctype/quality_procedure/quality_procedure.py | 14 +++++++++++++-
.../quality_procedure/quality_procedure_tree.js | 4 +---
2 files changed, 14 insertions(+), 4 deletions(-)
diff --git a/erpnext/quality_management/doctype/quality_procedure/quality_procedure.py b/erpnext/quality_management/doctype/quality_procedure/quality_procedure.py
index 4d3c522956..b4de03e1e4 100644
--- a/erpnext/quality_management/doctype/quality_procedure/quality_procedure.py
+++ b/erpnext/quality_management/doctype/quality_procedure/quality_procedure.py
@@ -52,7 +52,19 @@ class QualityProcedure(NestedSet):
def get_children(doctype, parent=None, parent_quality_procedure=None, is_root=False):
if parent is None or parent == "All Quality Procedures":
parent = ""
- return frappe.get_all(doctype, fields=["name as value", "is_group as expandable"], filters={"parent_quality_procedure": parent})
+
+ return frappe.db.sql("""
+ select
+ name as value,
+ is_group as expandable
+ from
+ `tab{doctype}`
+ where
+ ifnull(parent_quality_procedure, "")={parent}
+ """.format(
+ doctype = doctype,
+ parent=frappe.db.escape(parent)
+ ), as_dict=1)
@frappe.whitelist()
def add_node():
diff --git a/erpnext/quality_management/doctype/quality_procedure/quality_procedure_tree.js b/erpnext/quality_management/doctype/quality_procedure/quality_procedure_tree.js
index 8fd785f205..dbdbbab392 100644
--- a/erpnext/quality_management/doctype/quality_procedure/quality_procedure_tree.js
+++ b/erpnext/quality_management/doctype/quality_procedure/quality_procedure_tree.js
@@ -1,5 +1,3 @@
-frappe.provide("frappe.treeview_settings");
-
frappe.treeview_settings["Quality Procedure"] = {
ignore_fields:["parent_quality_procedure"],
get_tree_nodes: 'erpnext.quality_management.doctype.quality_procedure.quality_procedure.get_children',
@@ -19,7 +17,7 @@ frappe.treeview_settings["Quality Procedure"] = {
],
breadcrumb: "Setup",
root_label: "All Quality Procedures",
- get_tree_root: true,
+ get_tree_root: false,
menu_items: [
{
label: __("New Quality Procedure"),
From b5bd91417d4a394cbfbc7e76d44b270ca54bc62d Mon Sep 17 00:00:00 2001
From: Nabin Hait
Date: Thu, 5 Sep 2019 16:43:20 +0530
Subject: [PATCH 428/484] fix: Print/PDF of AR/AP report after refactoring
(#18931)
---
.../accounts_receivable.html | 498 +++++++++---------
1 file changed, 246 insertions(+), 252 deletions(-)
diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.html b/erpnext/accounts/report/accounts_receivable/accounts_receivable.html
index d00bcf643e..791f3f8008 100644
--- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.html
+++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.html
@@ -1,275 +1,269 @@
+ .print-format {
+ padding: 4mm;
+ font-size: 8.0pt !important;
+ }
+ .print-format td {
+ vertical-align:middle !important;
+ }
+
-{%= __(report.report_name) %}
-
- {% if (filters.customer_name) { %}
- {%= filters.customer_name %}
- {% } else { %}
- {%= filters.customer || filters.supplier %}
- {% } %}
-
-
- {% if (filters.tax_id) { %}
- {%= __("Tax Id: ")%} {%= filters.tax_id %}
+ {%= __(report.report_name) %}
+
+ {% if (filters.customer_name) { %}
+ {%= filters.customer_name %}
+ {% } else { %}
+ {%= filters.customer || filters.supplier %}
{% } %}
-
-
- {%= __(filters.ageing_based_on) %}
- {%= __("Until") %}
- {%= frappe.datetime.str_to_user(filters.report_date) %}
-
+
+
+ {% if (filters.tax_id) { %}
+ {%= __("Tax Id: ")%} {%= filters.tax_id %}
+ {% } %}
+
+
+ {%= __(filters.ageing_based_on) %}
+ {%= __("Until") %}
+ {%= frappe.datetime.str_to_user(filters.report_date) %}
+
-
-
- {% if(filters.payment_terms) { %}
-
{%= __("Payment Terms") %}: {%= filters.payment_terms %}
- {% } %}
+
+
+ {% if(filters.payment_terms) { %}
+ {%= __("Payment Terms") %}: {%= filters.payment_terms %}
+ {% } %}
+
+
+ {% if(filters.credit_limit) { %}
+ {%= __("Credit Limit") %}: {%= format_currency(filters.credit_limit) %}
+ {% } %}
+
-
- {% if(filters.credit_limit) { %}
-
{%= __("Credit Limit") %}: {%= format_currency(filters.credit_limit) %}
+
+ {% if(filters.show_future_payments) { %}
+ {% var balance_row = data.slice(-1).pop();
+ var range1 = report.columns[11].label;
+ var range2 = report.columns[12].label;
+ var range3 = report.columns[13].label;
+ var range4 = report.columns[14].label;
+ var range5 = report.columns[15].label;
+ %}
+ {% if(balance_row) { %}
+
+ (Amount in {%= data[0]["currency"] || "" %})
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {%= __(" ") %}
+ {%= __(range1) %}
+ {%= __(range2) %}
+ {%= __(range3) %}
+ {%= __(range4) %}
+ {%= __(range5) %}
+ {%= __("Total") %}
+
+
+
+
+ {%= __("Total Outstanding") %}
+ {%= format_number(balance_row["range1"], null, 2) %}
+ {%= format_currency(balance_row["range2"]) %}
+ {%= format_currency(balance_row["range3"]) %}
+ {%= format_currency(balance_row["range4"]) %}
+ {%= format_currency(balance_row["range5"]) %}
+
+ {%= format_currency(flt(balance_row["outstanding"]), data[data.length-1]["currency"]) %}
+
+
+ {%= __("Future Payments") %}
+
+
+
+
+
+
+ {%= format_currency(flt(balance_row[("future_amount")]), data[data.length-1]["currency"]) %}
+
+
+
+
+
+ {% } %}
{% } %}
-
-
-
-{% if(filters.show_future_payments) { %}
- {% var balance_row = data.slice(-1).pop();
- var range1 = report.columns[11].label;
- var range2 = report.columns[12].label;
- var range3 = report.columns[13].label;
- var range4 = report.columns[14].label;
- var range5 = report.columns[15].label;
- var range6 = report.columns[16].label;
- %}
- {% if(balance_row) { %}
-
- (Amount in {%= data[0][__("currency")] || "" %})
-
-
-
-
-
-
-
-
-
-
-
-
+
- {%= __(" ") %}
- {%= __(range1) %}
- {%= __(range2) %}
- {%= __(range3) %}
- {%= __(range4) %}
- {%= __(range5) %}
- {%= __(range6) %}
- {%= __("Total") %}
+ {% if(report.report_name === "Accounts Receivable" || report.report_name === "Accounts Payable") { %}
+ {%= __("Date") %}
+ {%= __("Age (Days)") %}
+
+ {% if(report.report_name === "Accounts Receivable" && filters.show_sales_person) { %}
+ {%= __("Reference") %}
+ {%= __("Sales Person") %}
+ {% } else { %}
+ {%= __("Reference") %}
+ {% } %}
+ {% if(!filters.show_future_payments) { %}
+ {%= (filters.customer || filters.supplier) ? __("Remarks"): __("Party") %}
+ {% } %}
+ {%= __("Invoiced Amount") %}
+ {% if(!filters.show_future_payments) { %}
+ {%= __("Paid Amount") %}
+ {%= report.report_name === "Accounts Receivable" ? __('Credit Note') : __('Debit Note') %}
+ {% } %}
+ {%= __("Outstanding Amount") %}
+ {% if(filters.show_future_payments) { %}
+ {% if(report.report_name === "Accounts Receivable") { %}
+ {%= __("Customer LPO No.") %}
+ {% } %}
+ {%= __("Future Payment Ref") %}
+ {%= __("Future Payment Amount") %}
+ {%= __("Remaining Balance") %}
+ {% } %}
+ {% } else { %}
+ {%= (filters.customer || filters.supplier) ? __("Remarks"): __("Party") %}
+ {%= __("Total Invoiced Amount") %}
+ {%= __("Total Paid Amount") %}
+ {%= report.report_name === "Accounts Receivable Summary" ? __('Credit Note Amount') : __('Debit Note Amount') %}
+ {%= __("Total Outstanding Amount") %}
+ {% } %}
-
- {%= __("Total Outstanding") %}
- {%= format_number(balance_row[range1], null, 2) %}
- {%= format_currency(balance_row[range2]) %}
- {%= format_currency(balance_row[range3]) %}
- {%= format_currency(balance_row[range4]) %}
- {%= format_currency(balance_row[range5]) %}
- {%= format_currency(balance_row[range6]) %}
-
- {%= format_currency(flt(balance_row[("outstanding_amount")]), data[data.length-1]["currency"]) %}
-
-
- {%= __("PDC/LC") %}
-
-
-
-
-
-
-
- {%= format_currency(flt(balance_row[("pdc/lc_amount")]), data[data.length-1]["currency"]) %}
-
-
-
-
-
- {% } %}
-{% } %}
-
-
-
- {% if(report.report_name === "Accounts Receivable" || report.report_name === "Accounts Payable") { %}
- {%= __("Date") %}
- {%= __("Age (Days)") %}
-
- {% if(report.report_name === "Accounts Receivable" && filters.show_sales_person) { %}
- {%= __("Reference") %}
- {%= __("Sales Person") %}
- {% } else { %}
- {%= __("Reference") %}
- {% } %}
- {% if(!filters.show_future_payments) { %}
- {%= (filters.customer || filters.supplier) ? __("Remarks"): __("Party") %}
- {% } %}
- {%= __("Invoiced Amount") %}
- {% if(!filters.show_future_payments) { %}
- {%= __("Paid Amount") %}
- {%= report.report_name === "Accounts Receivable" ? __('Credit Note') : __('Debit Note') %}
- {% } %}
- {%= __("Outstanding Amount") %}
- {% if(filters.show_future_payments) { %}
- {% if(report.report_name === "Accounts Receivable") { %}
- {%= __("Customer LPO No.") %}
- {% } %}
- {%= __("PDC/LC Ref") %}
- {%= __("PDC/LC Amount") %}
- {%= __("Remaining Balance") %}
- {% } %}
- {% } else { %}
- {%= (filters.customer || filters.supplier) ? __("Remarks"): __("Party") %}
- {%= __("Total Invoiced Amount") %}
- {%= __("Total Paid Amount") %}
- {%= report.report_name === "Accounts Receivable Summary" ? __('Credit Note Amount') : __('Debit Note Amount') %}
- {%= __("Total Outstanding Amount") %}
- {% } %}
-
-
-
- {% for(var i=0, l=data.length; i
- {% if(report.report_name === "Accounts Receivable" || report.report_name === "Accounts Payable") { %}
- {% if(data[i][__("Customer")] || data[i][__("Supplier")]) { %}
- {%= frappe.datetime.str_to_user(data[i]["posting_date"]) %}
- {%= data[i][__("Age (Days)")] %}
-
- {% if(!filters.show_future_payments) { %}
- {%= data[i]["voucher_type"] %}
-
- {% } %}
- {%= data[i]["voucher_no"] %}
-
-
- {% if(report.report_name === "Accounts Receivable" && filters.show_sales_person) { %}
- {%= data[i]["sales_person"] %}
- {% } %}
-
- {% if(!filters.show_future_payments) { %}
-
- {% if(!(filters.customer || filters.supplier)) { %}
- {%= data[i][__("Customer")] || data[i][__("Supplier")] %}
- {% if(data[i][__("Customer Name")] && data[i][__("Customer Name")] != data[i][__("Customer")]) { %}
- {%= data[i][__("Customer Name")] %}
- {% } else if(data[i][__("Supplier Name")] != data[i][__("Supplier")]) { %}
- {%= data[i][__("Supplier Name")] %}
+ {% for(var i=0, l=data.length; i
+ {% if(report.report_name === "Accounts Receivable" || report.report_name === "Accounts Payable") { %}
+ {% if(data[i]["party"]) { %}
+ {%= frappe.datetime.str_to_user(data[i]["posting_date"]) %}
+ {%= data[i]["age"] %}
+
+ {% if(!filters.show_future_payments) { %}
+ {%= data[i]["voucher_type"] %}
+
{% } %}
+ {%= data[i]["voucher_no"] %}
+
+
+ {% if(report.report_name === "Accounts Receivable" && filters.show_sales_person) { %}
+ {%= data[i]["sales_person"] %}
{% } %}
-
- {% if data[i][__("Remarks")] %}
- {%= __("Remarks") %}:
- {%= data[i][__("Remarks")] %}
- {% } %}
-
-
- {% } %}
-
- {%= format_currency(data[i]["invoiced_amount"], data[i]["currency"]) %}
-
- {% if(!filters.show_future_payments) { %}
-
- {%= format_currency(data[i]["paid_amount"], data[i]["currency"]) %}
-
- {%= report.report_name === "Accounts Receivable" ? format_currency(data[i]["credit_note"], data[i]["currency"]) : format_currency(data[i]["debit_note"], data[i]["currency"]) %}
- {% } %}
-
- {%= format_currency(data[i]["outstanding_amount"], data[i]["currency"]) %}
-
- {% if(filters.show_future_payments) { %}
- {% if(report.report_name === "Accounts Receivable") { %}
-
- {%= data[i]["po_no"] %}
- {% } %}
- {%= data[i][("pdc/lc_ref")] %}
- {%= format_currency(data[i][("pdc/lc_amount")], data[i]["currency"]) %}
- {%= format_currency(data[i][("remaining_balance")], data[i]["currency"]) %}
- {% } %}
- {% } else { %}
-
- {% if(!filters.show_future_payments) { %}
-
- {% } %}
- {% if(report.report_name === "Accounts Receivable" && filters.show_sales_person) { %}
-
- {% } %}
-
- {%= __("Total") %}
-
- {%= format_currency(data[i]["invoiced_amount"], data[i]["currency"] ) %}
-
- {% if(!filters.show_future_payments) { %}
-
- {%= format_currency(data[i]["paid_amount"], data[i]["currency"]) %}
- {%= report.report_name === "Accounts Receivable" ? format_currency(data[i]["credit_note"], data[i]["currency"]) : format_currency(data[i]["debit_note"], data[i]["currency"]) %}
- {% } %}
-
- {%= format_currency(data[i]["outstanding_amount"], data[i]["currency"]) %}
-
- {% if(filters.show_future_payments) { %}
- {% if(report.report_name === "Accounts Receivable") { %}
-
- {%= data[i][__("Customer LPO")] %}
- {% } %}
- {%= data[i][("pdc/lc_ref")] %}
- {%= format_currency(data[i][("pdc/lc_amount")], data[i]["currency"]) %}
- {%= format_currency(data[i][("remaining_balance")], data[i]["currency"]) %}
- {% } %}
- {% } %}
- {% } else { %}
- {% if(data[i][__("Customer")] || data[i][__("Supplier")]|| " ") { %}
- {% if((data[i][__("Customer")] || data[i][__("Supplier")]) != __("'Total'")) { %}
+ {% if(!filters.show_future_payments) { %}
{% if(!(filters.customer || filters.supplier)) { %}
- {%= data[i][__("Customer")] || data[i][__("Supplier")] %}
- {% if(data[i][__("Customer Name")] && data[i][__("Customer Name")] != data[i][__("Customer")]) { %}
- {%= data[i][__("Customer Name")] %}
- {% } else if(data[i][__("Supplier Name")] != data[i][__("Supplier")]) { %}
- {%= data[i][__("Supplier Name")] %}
+ {%= data[i]["party"] %}
+ {% if(data[i]["customer_name"] && data[i]["customer_name"] != data[i]["party"]) { %}
+ {%= data[i]["customer_name"] %}
+ {% } else if(data[i]["supplier_name"] != data[i]["party"]) { %}
+ {%= data[i]["supplier_name"] %}
{% } %}
{% } %}
- {%= __("Remarks") %}:
- {%= data[i][__("Remarks")] %}
+
+ {% if data[i]["remarks"] %}
+ {%= __("Remarks") %}:
+ {%= data[i]["remarks"] %}
+ {% } %}
+
+ {% } %}
+
+
+ {%= format_currency(data[i]["invoiced"], data[i]["currency"]) %}
+
+ {% if(!filters.show_future_payments) { %}
+
+ {%= format_currency(data[i]["paid"], data[i]["currency"]) %}
+
+ {%= format_currency(data[i]["credit_note"], data[i]["currency"]) %}
+ {% } %}
+
+ {%= format_currency(data[i]["outstanding"], data[i]["currency"]) %}
+
+ {% if(filters.show_future_payments) { %}
+ {% if(report.report_name === "Accounts Receivable") { %}
+
+ {%= data[i]["po_no"] %}
+ {% } %}
+ {%= data[i]["future_ref"] %}
+ {%= format_currency(data[i]["future_amount"], data[i]["currency"]) %}
+ {%= format_currency(data[i]["remaining_balance"], data[i]["currency"]) %}
+ {% } %}
{% } else { %}
- {%= __("Total") %}
+
+ {% if(!filters.show_future_payments) { %}
+
+ {% } %}
+ {% if(report.report_name === "Accounts Receivable" && filters.show_sales_person) { %}
+
+ {% } %}
+
+ {%= __("Total") %}
+
+ {%= format_currency(data[i]["invoiced"], data[i]["currency"] ) %}
+
+ {% if(!filters.show_future_payments) { %}
+
+ {%= format_currency(data[i]["paid"], data[i]["currency"]) %}
+ {%= format_currency(data[i]["credit_note"], data[i]["currency"]) %}
+ {% } %}
+
+ {%= format_currency(data[i]["outstanding"], data[i]["currency"]) %}
+
+ {% if(filters.show_future_payments) { %}
+ {% if(report.report_name === "Accounts Receivable") { %}
+
+ {%= data[i]["po_no"] %}
+ {% } %}
+ {%= data[i]["future_ref"] %}
+ {%= format_currency(data[i]["future_amount"], data[i]["currency"]) %}
+ {%= format_currency(data[i]["remaining_balance"], data[i]["currency"]) %}
+ {% } %}
+ {% } %}
+ {% } else { %}
+ {% if(data[i]["party"]|| " ") { %}
+ {% if((data[i]["party"]) != __("'Total'")) { %}
+
+ {% if(!(filters.customer || filters.supplier)) { %}
+ {%= data[i]["party"] %}
+ {% if(data[i]["customer_name"] && data[i]["customer_name"] != data[i]["party"]) { %}
+ {%= data[i]["customer_name"] %}
+ {% } else if(data[i]["supplier_name"] != data[i]["party"]) { %}
+ {%= data[i]["supplier_name"] %}
+ {% } %}
+ {% } %}
+ {%= __("Remarks") %}:
+ {%= data[i]["remarks"] %}
+
+ {% } else { %}
+ {%= __("Total") %}
+ {% } %}
+ {%= format_currency(data[i]["invoiced"], data[i]["currency"]) %}
+ {%= format_currency(data[i]["paid"], data[i]["currency"]) %}
+ {%= format_currency(data[i]["credit_note"], data[i]["currency"]) %}
+ {%= format_currency(data[i]["outstanding"], data[i]["currency"]) %}
{% } %}
- {%= format_currency(data[i][("total_invoiced_amt")], data[i]["currency"]) %}
- {%= format_currency(data[i][("total_paid_amt")], data[i]["currency"]) %}
- {%= report.report_name === "Accounts Receivable Summary" ? format_currency(data[i][__("credit_note_amt")], data[i]["currency"]) : format_currency(data[i][__("debit_note_amt")], data[i]["currency"]) %}
- {%= format_currency(data[i][("total_outstanding_amt")], data[i]["currency"]) %}
{% } %}
+
{% } %}
-
- {% } %}
-
-
-{{ __("Printed On ") }}{%= frappe.datetime.str_to_user(frappe.datetime.get_datetime_as_string()) %}
+
+
+
{{ __("Printed On ") }}{%= frappe.datetime.str_to_user(frappe.datetime.get_datetime_as_string()) %}
From ac2b5ed84f4cfcaf7f7fef059ae03d53dcd608e5 Mon Sep 17 00:00:00 2001
From: Nabin Hait
Date: Thu, 5 Sep 2019 16:57:26 +0530
Subject: [PATCH 429/484] fix: credit limit patch
---
.../move_credit_limit_to_customer_credit_limit.py | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/erpnext/patches/v12_0/move_credit_limit_to_customer_credit_limit.py b/erpnext/patches/v12_0/move_credit_limit_to_customer_credit_limit.py
index 30acfe68ea..3bcdb8fc7f 100644
--- a/erpnext/patches/v12_0/move_credit_limit_to_customer_credit_limit.py
+++ b/erpnext/patches/v12_0/move_credit_limit_to_customer_credit_limit.py
@@ -21,10 +21,10 @@ def move_credit_limit_to_child_table():
if frappe.db.has_column('Customer', 'bypass_credit_limit_check_at_sales_order'):
fields = ", bypass_credit_limit_check_at_sales_order"
- credit_limit_record = frappe.db.sql(''' SELECT
- name, credit_limit
- {0}
- FROM `tabCustomer`'''.format(fields), as_dict=1) #nosec
+ credit_limit_record = frappe.db.sql('''
+ SELECT name, credit_limit {0}
+ FROM `tabCustomer` where credit_limit > 0
+ '''.format(fields), as_dict=1) #nosec
companies = frappe.get_all("Company", 'name')
@@ -36,4 +36,5 @@ def move_credit_limit_to_child_table():
'bypass_credit_limit_check': record.bypass_credit_limit_check_at_sales_order,
'company': company.name
})
- customer.db_insert()
+ for row in customer.credit_limit_reference:
+ row.db_insert()
From 0906bc8430ef28d159adb96872bb6fe3ff47b8f3 Mon Sep 17 00:00:00 2001
From: Sahil Khan
Date: Thu, 5 Sep 2019 17:50:44 +0550
Subject: [PATCH 430/484] bumped to version 12.1.1
---
erpnext/__init__.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/__init__.py b/erpnext/__init__.py
index ee37c8d780..106384ade0 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__ = '12.1.0'
+__version__ = '12.1.1'
def get_default_company(user=None):
'''Get default company for user'''
From a93b6654274b87d383c70a25820adfbaef2a69f0 Mon Sep 17 00:00:00 2001
From: Marica
Date: Thu, 5 Sep 2019 18:26:45 +0530
Subject: [PATCH 431/484] fix: Print Format 'Point of Sale' removed from Sales
invoice Print Format List (#18937)
'Point of Sale' Print Format for offline POS ,now doesn't appear in the Print Format Labels List in Sales Invoice for v12.
---
.../point_of_sale/point_of_sale.json | 39 ++++++++++---------
1 file changed, 20 insertions(+), 19 deletions(-)
diff --git a/erpnext/accounts/print_format/point_of_sale/point_of_sale.json b/erpnext/accounts/print_format/point_of_sale/point_of_sale.json
index a8bedc2b66..c0c50cb4e2 100644
--- a/erpnext/accounts/print_format/point_of_sale/point_of_sale.json
+++ b/erpnext/accounts/print_format/point_of_sale/point_of_sale.json
@@ -1,22 +1,23 @@
{
- "align_labels_right": 0,
- "creation": "2016-05-05 17:16:18.564460",
- "custom_format": 1,
- "disabled": 0,
- "doc_type": "Sales Invoice",
- "docstatus": 0,
- "doctype": "Print Format",
- "font": "Default",
- "html": "\n\n\n\t{{ company }} \n\t{{ __(\"POS No : \") }} {{ offline_pos_name }} \n
\n\n\t{{ __(\"Customer\") }}: {{ customer }} \n
\n\n\n\t{{ __(\"Date\") }}: {{ dateutil.global_date_format(posting_date) }} \n
\n\n \n\n\t\n\t\t\n\t\t\t{{ __(\"Item\") }} \n\t\t\t{{ __(\"Qty\") }} \n\t\t\t{{ __(\"Amount\") }} \n\t\t \n\t \n\t\n\t\t{% for item in items %}\n\t\t\n\t\t\t\n\t\t\t\t{{ item.item_name }}\n\t\t\t \n\t\t\t{{ format_number(item.qty, null,precision(\"difference\")) }} @ {{ format_currency(item.rate, currency) }} \n\t\t\t{{ format_currency(item.amount, currency) }} \n\t\t \n\t\t{% endfor %}\n\t \n
\n\n\n\t\n\t\t\n\t\t\t\n\t\t\t\t{{ __(\"Net Total\") }}\n\t\t\t \n\t\t\t\n\t\t\t\t{{ format_currency(total, currency) }}\n\t\t\t \n\t\t \n\t\t{% for row in taxes %}\n\t\t{% if not row.included_in_print_rate %}\n\t\t\n\t\t\t\n\t\t\t\t{{ row.description }}\n\t\t\t \n\t\t\t\n\t\t\t\t{{ format_currency(row.tax_amount, currency) }}\n\t\t\t \n\t\t \n\t\t{% endif %}\n\t\t{% endfor %}\n\t\t{% if discount_amount %}\n\t\t\n\t\t\t\n\t\t\t\t{{ __(\"Discount\") }}\n\t\t\t \n\t\t\t\n\t\t\t\t{{ format_currency(discount_amount, currency) }}\n\t\t\t \n\t\t \n\t\t{% endif %}\n\t\t\n\t\t\t\n\t\t\t\t{{ __(\"Grand Total\") }} \n\t\t\t \n\t\t\t\n\t\t\t\t{{ format_currency(grand_total, currency) }}\n\t\t\t \n\t\t \n\t\t\n\t\t\t\n\t\t\t\t{{ __(\"Paid Amount\") }} \n\t\t\t \n\t\t\t\n\t\t\t\t{{ format_currency(paid_amount, currency) }}\n\t\t\t \n\t\t \n\t\t\n\t\t\t\n\t\t\t\t{{ __(\"Qty Total\") }} \n\t\t\t \n\t\t\t\n\t\t\t\t{{ qty_total }}\n\t\t\t \n\t\t \n\t \n
\n\n\n \n{{ terms }}
\n{{ __(\"Thank you, please visit again.\") }}
",
- "idx": 0,
- "line_breaks": 0,
- "modified": "2018-03-21 09:10:16.693732",
- "modified_by": "Administrator",
- "module": "Accounts",
- "name": "Point of Sale",
- "owner": "Administrator",
- "print_format_builder": 0,
- "print_format_type": "Js",
- "show_section_headings": 0,
+ "align_labels_right": 0,
+ "creation": "2016-05-05 17:16:18.564460",
+ "custom_format": 1,
+ "disabled": 0,
+ "doc_type": "Sales Invoice",
+ "docstatus": 0,
+ "doctype": "Print Format",
+ "font": "Default",
+ "html": "\n\n\n\t{{ company }} \n\t{{ __(\"POS No : \") }} {{ offline_pos_name }} \n
\n\n\t{{ __(\"Customer\") }}: {{ customer }} \n
\n\n\n\t{{ __(\"Date\") }}: {{ dateutil.global_date_format(posting_date) }} \n
\n\n \n\n\t\n\t\t\n\t\t\t{{ __(\"Item\") }} \n\t\t\t{{ __(\"Qty\") }} \n\t\t\t{{ __(\"Amount\") }} \n\t\t \n\t \n\t\n\t\t{% for item in items %}\n\t\t\n\t\t\t\n\t\t\t\t{{ item.item_name }}\n\t\t\t \n\t\t\t{{ format_number(item.qty, null,precision(\"difference\")) }} @ {{ format_currency(item.rate, currency) }} \n\t\t\t{{ format_currency(item.amount, currency) }} \n\t\t \n\t\t{% endfor %}\n\t \n
\n\n\n\t\n\t\t\n\t\t\t\n\t\t\t\t{{ __(\"Net Total\") }}\n\t\t\t \n\t\t\t\n\t\t\t\t{{ format_currency(total, currency) }}\n\t\t\t \n\t\t \n\t\t{% for row in taxes %}\n\t\t{% if not row.included_in_print_rate %}\n\t\t\n\t\t\t\n\t\t\t\t{{ row.description }}\n\t\t\t \n\t\t\t\n\t\t\t\t{{ format_currency(row.tax_amount, currency) }}\n\t\t\t \n\t\t \n\t\t{% endif %}\n\t\t{% endfor %}\n\t\t{% if discount_amount %}\n\t\t\n\t\t\t\n\t\t\t\t{{ __(\"Discount\") }}\n\t\t\t \n\t\t\t\n\t\t\t\t{{ format_currency(discount_amount, currency) }}\n\t\t\t \n\t\t \n\t\t{% endif %}\n\t\t\n\t\t\t\n\t\t\t\t{{ __(\"Grand Total\") }} \n\t\t\t \n\t\t\t\n\t\t\t\t{{ format_currency(grand_total, currency) }}\n\t\t\t \n\t\t \n\t\t\n\t\t\t\n\t\t\t\t{{ __(\"Paid Amount\") }} \n\t\t\t \n\t\t\t\n\t\t\t\t{{ format_currency(paid_amount, currency) }}\n\t\t\t \n\t\t \n\t\t\n\t\t\t\n\t\t\t\t{{ __(\"Qty Total\") }} \n\t\t\t \n\t\t\t\n\t\t\t\t{{ qty_total }}\n\t\t\t \n\t\t \n\t \n
\n\n\n \n{{ terms }}
\n{{ __(\"Thank you, please visit again.\") }}
",
+ "idx": 0,
+ "line_breaks": 0,
+ "modified": "2019-09-05 17:20:30.726659",
+ "modified_by": "Administrator",
+ "module": "Accounts",
+ "name": "Point of Sale",
+ "owner": "Administrator",
+ "print_format_builder": 0,
+ "print_format_type": "JS",
+ "raw_printing": 0,
+ "show_section_headings": 0,
"standard": "Yes"
}
\ No newline at end of file
From ac0c1edd23946073c4f1ca53f8196fba45d125b9 Mon Sep 17 00:00:00 2001
From: Anurag Mishra <32095923+Anurag810@users.noreply.github.com>
Date: Fri, 6 Sep 2019 12:10:10 +0530
Subject: [PATCH 432/484] feat: added date filter based on billing date and
based date (#18936)
---
erpnext/controllers/trends.py | 4 +-
erpnext/public/js/purchase_trends_filters.js | 39 +++++++++++++-------
2 files changed, 27 insertions(+), 16 deletions(-)
diff --git a/erpnext/controllers/trends.py b/erpnext/controllers/trends.py
index 28a8fddfac..0404a1e6b0 100644
--- a/erpnext/controllers/trends.py
+++ b/erpnext/controllers/trends.py
@@ -39,7 +39,6 @@ def validate_filters(filters):
frappe.throw(_("'Based On' and 'Group By' can not be same"))
def get_data(filters, conditions):
-
data = []
inc, cond= '',''
query_details = conditions["based_on_select"] + conditions["period_wise_select"]
@@ -47,10 +46,11 @@ def get_data(filters, conditions):
posting_date = 't1.transaction_date'
if conditions.get('trans') in ['Sales Invoice', 'Purchase Invoice', 'Purchase Receipt', 'Delivery Note']:
posting_date = 't1.posting_date'
+ if filters.period_based_on:
+ posting_date = 't1.'+filters.period_based_on
if conditions["based_on_select"] in ["t1.project,", "t2.project,"]:
cond = ' and '+ conditions["based_on_select"][:-1] +' IS Not NULL'
-
if conditions.get('trans') in ['Sales Order', 'Purchase Order']:
cond += " and t1.status != 'Closed'"
diff --git a/erpnext/public/js/purchase_trends_filters.js b/erpnext/public/js/purchase_trends_filters.js
index 595a138f12..cd767f5d16 100644
--- a/erpnext/public/js/purchase_trends_filters.js
+++ b/erpnext/public/js/purchase_trends_filters.js
@@ -3,6 +3,14 @@
erpnext.get_purchase_trends_filters = function() {
return [
+ {
+ "fieldname":"company",
+ "label": __("Company"),
+ "fieldtype": "Link",
+ "options": "Company",
+ "reqd": 1,
+ "default": frappe.defaults.get_user_default("Company")
+ },
{
"fieldname":"period",
"label": __("Period"),
@@ -15,6 +23,23 @@ erpnext.get_purchase_trends_filters = function() {
],
"default": "Monthly"
},
+ {
+ "fieldname":"fiscal_year",
+ "label": __("Fiscal Year"),
+ "fieldtype": "Link",
+ "options":'Fiscal Year',
+ "default": frappe.sys_defaults.fiscal_year
+ },
+ {
+ "fieldname":"period_based_on",
+ "label": __("Period based On"),
+ "fieldtype": "Select",
+ "options": [
+ { "value": "posting_date", "label": __("Posting Date") },
+ { "value": "bill_date", "label": __("Billing Date") },
+ ],
+ "default": "posting_date"
+ },
{
"fieldname":"based_on",
"label": __("Based On"),
@@ -39,19 +64,5 @@ erpnext.get_purchase_trends_filters = function() {
],
"default": ""
},
- {
- "fieldname":"fiscal_year",
- "label": __("Fiscal Year"),
- "fieldtype": "Link",
- "options":'Fiscal Year',
- "default": frappe.sys_defaults.fiscal_year
- },
- {
- "fieldname":"company",
- "label": __("Company"),
- "fieldtype": "Link",
- "options": "Company",
- "default": frappe.defaults.get_user_default("Company")
- },
];
}
From bbc1b5cdcfb749101c5f9b65ccd855fa5255a7c1 Mon Sep 17 00:00:00 2001
From: Anurag Mishra <32095923+Anurag810@users.noreply.github.com>
Date: Fri, 6 Sep 2019 12:10:37 +0530
Subject: [PATCH 433/484] feat: added date filter based on billing date and
based date (#18935)
---
erpnext/controllers/trends.py | 4 +-
erpnext/public/js/purchase_trends_filters.js | 39 +++++++++++++-------
2 files changed, 27 insertions(+), 16 deletions(-)
diff --git a/erpnext/controllers/trends.py b/erpnext/controllers/trends.py
index 28a8fddfac..0404a1e6b0 100644
--- a/erpnext/controllers/trends.py
+++ b/erpnext/controllers/trends.py
@@ -39,7 +39,6 @@ def validate_filters(filters):
frappe.throw(_("'Based On' and 'Group By' can not be same"))
def get_data(filters, conditions):
-
data = []
inc, cond= '',''
query_details = conditions["based_on_select"] + conditions["period_wise_select"]
@@ -47,10 +46,11 @@ def get_data(filters, conditions):
posting_date = 't1.transaction_date'
if conditions.get('trans') in ['Sales Invoice', 'Purchase Invoice', 'Purchase Receipt', 'Delivery Note']:
posting_date = 't1.posting_date'
+ if filters.period_based_on:
+ posting_date = 't1.'+filters.period_based_on
if conditions["based_on_select"] in ["t1.project,", "t2.project,"]:
cond = ' and '+ conditions["based_on_select"][:-1] +' IS Not NULL'
-
if conditions.get('trans') in ['Sales Order', 'Purchase Order']:
cond += " and t1.status != 'Closed'"
diff --git a/erpnext/public/js/purchase_trends_filters.js b/erpnext/public/js/purchase_trends_filters.js
index 595a138f12..cd767f5d16 100644
--- a/erpnext/public/js/purchase_trends_filters.js
+++ b/erpnext/public/js/purchase_trends_filters.js
@@ -3,6 +3,14 @@
erpnext.get_purchase_trends_filters = function() {
return [
+ {
+ "fieldname":"company",
+ "label": __("Company"),
+ "fieldtype": "Link",
+ "options": "Company",
+ "reqd": 1,
+ "default": frappe.defaults.get_user_default("Company")
+ },
{
"fieldname":"period",
"label": __("Period"),
@@ -15,6 +23,23 @@ erpnext.get_purchase_trends_filters = function() {
],
"default": "Monthly"
},
+ {
+ "fieldname":"fiscal_year",
+ "label": __("Fiscal Year"),
+ "fieldtype": "Link",
+ "options":'Fiscal Year',
+ "default": frappe.sys_defaults.fiscal_year
+ },
+ {
+ "fieldname":"period_based_on",
+ "label": __("Period based On"),
+ "fieldtype": "Select",
+ "options": [
+ { "value": "posting_date", "label": __("Posting Date") },
+ { "value": "bill_date", "label": __("Billing Date") },
+ ],
+ "default": "posting_date"
+ },
{
"fieldname":"based_on",
"label": __("Based On"),
@@ -39,19 +64,5 @@ erpnext.get_purchase_trends_filters = function() {
],
"default": ""
},
- {
- "fieldname":"fiscal_year",
- "label": __("Fiscal Year"),
- "fieldtype": "Link",
- "options":'Fiscal Year',
- "default": frappe.sys_defaults.fiscal_year
- },
- {
- "fieldname":"company",
- "label": __("Company"),
- "fieldtype": "Link",
- "options": "Company",
- "default": frappe.defaults.get_user_default("Company")
- },
];
}
From 4ce38059aca818da540a6dd3a02940678f169e83 Mon Sep 17 00:00:00 2001
From: Nabin Hait
Date: Fri, 6 Sep 2019 14:33:10 +0530
Subject: [PATCH 434/484] feat: Company wise credit limit
---
.../doctype/sales_invoice/sales_invoice.py | 2 +-
...e_credit_limit_to_customer_credit_limit.py | 44 +-
.../selling/doctype/customer/customer.json | 6 +-
erpnext/selling/doctype/customer/customer.py | 10 +-
.../selling/doctype/customer/test_customer.py | 29 +-
.../doctype/sales_order/sales_order.py | 4 +-
...es_order_with_bypass_credit_limit_check.js | 13 +-
...order_without_bypass_credit_limit_check.js | 18 +-
.../customer_group/customer_group.json | 447 ++----------------
.../doctype/delivery_note/delivery_note.py | 2 +-
10 files changed, 122 insertions(+), 453 deletions(-)
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index 4f8d3bdd9a..abbac77783 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -305,7 +305,7 @@ class SalesInvoice(SellingController):
validate_against_credit_limit = False
bypass_credit_limit_check_at_sales_order = frappe.db.get_value("Customer Credit Limit",
- filters={'parent': self.customer, 'company': self.company},
+ filters={'parent': self.customer, 'parenttype': 'Customer', 'company': self.company},
fieldname=["bypass_credit_limit_check"])
if bypass_credit_limit_check_at_sales_order:
diff --git a/erpnext/patches/v12_0/move_credit_limit_to_customer_credit_limit.py b/erpnext/patches/v12_0/move_credit_limit_to_customer_credit_limit.py
index 3bcdb8fc7f..c9293b9b63 100644
--- a/erpnext/patches/v12_0/move_credit_limit_to_customer_credit_limit.py
+++ b/erpnext/patches/v12_0/move_credit_limit_to_customer_credit_limit.py
@@ -8,6 +8,7 @@ def execute():
''' Move credit limit and bypass credit limit to the child table of customer credit limit '''
frappe.reload_doc("Selling", "doctype", "Customer Credit Limit")
frappe.reload_doc("Selling", "doctype", "Customer")
+ frappe.reload_doc("Setup", "doctype", "Customer Group")
if frappe.db.a_row_exists("Customer Credit Limit"):
return
@@ -17,24 +18,29 @@ def execute():
def move_credit_limit_to_child_table():
''' maps data from old field to the new field in the child table '''
- fields=""
- if frappe.db.has_column('Customer', 'bypass_credit_limit_check_at_sales_order'):
- fields = ", bypass_credit_limit_check_at_sales_order"
-
- credit_limit_record = frappe.db.sql('''
- SELECT name, credit_limit {0}
- FROM `tabCustomer` where credit_limit > 0
- '''.format(fields), as_dict=1) #nosec
-
companies = frappe.get_all("Company", 'name')
+ for doctype in ("Customer", "Customer Group"):
+ fields = ""
+ if doctype == "Customer" \
+ and frappe.db.has_column('Customer', 'bypass_credit_limit_check_at_sales_order'):
+ fields = ", bypass_credit_limit_check_at_sales_order"
- for record in credit_limit_record:
- customer = frappe.get_doc("Customer", record.name)
- for company in companies:
- customer.append("credit_limit_reference", {
- 'credit_limit': record.credit_limit,
- 'bypass_credit_limit_check': record.bypass_credit_limit_check_at_sales_order,
- 'company': company.name
- })
- for row in customer.credit_limit_reference:
- row.db_insert()
+ credit_limit_records = frappe.db.sql('''
+ SELECT name, credit_limit {0}
+ FROM `tab{1}` where credit_limit > 0
+ '''.format(fields, doctype), as_dict=1) #nosec
+
+ for record in credit_limit_records:
+ doc = frappe.get_doc(doctype, record.name)
+ for company in companies:
+ row = frappe._dict({
+ 'credit_limit': record.credit_limit,
+ 'company': company.name
+ })
+ if doctype == "Customer":
+ row.bypass_credit_limit_check = record.bypass_credit_limit_check_at_sales_order
+
+ doc.append("credit_limits", row)
+
+ for row in doc.credit_limits:
+ row.db_insert()
diff --git a/erpnext/selling/doctype/customer/customer.json b/erpnext/selling/doctype/customer/customer.json
index b83e284697..c2c8c1971a 100644
--- a/erpnext/selling/doctype/customer/customer.json
+++ b/erpnext/selling/doctype/customer/customer.json
@@ -50,7 +50,7 @@
"accounts",
"credit_limit_section",
"payment_terms",
- "credit_limit_reference",
+ "credit_limits",
"more_info",
"customer_details",
"column_break_45",
@@ -460,7 +460,7 @@
},
{
"default": "0",
- "fieldname": "credit_limit_reference",
+ "fieldname": "credit_limits",
"fieldtype": "Table",
"label": "Credit Limit",
"options": "Customer Credit Limit"
@@ -469,7 +469,7 @@
"icon": "fa fa-user",
"idx": 363,
"image_field": "image",
- "modified": "2019-08-30 18:03:13.332934",
+ "modified": "2019-09-06 12:40:31.801424",
"modified_by": "Administrator",
"module": "Selling",
"name": "Customer",
diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py
index 972a6102ae..4ca5af51a4 100644
--- a/erpnext/selling/doctype/customer/customer.py
+++ b/erpnext/selling/doctype/customer/customer.py
@@ -167,11 +167,11 @@ class Customer(TransactionBase):
frappe.throw(_("A Customer Group exists with same name please change the Customer name or rename the Customer Group"), frappe.NameError)
def validate_credit_limit_on_change(self):
- if self.get("__islocal") or not self.credit_limit_reference:
+ if self.get("__islocal") or not self.credit_limits:
return
company_record = []
- for limit in self.credit_limit_reference:
+ for limit in self.credit_limits:
if limit.company in company_record:
frappe.throw(_("Credit limit is already defined for the Company {0}").format(limit.company, self.name))
else:
@@ -327,11 +327,13 @@ def get_credit_limit(customer, company):
credit_limit = None
if customer:
- credit_limit = frappe.db.get_value("Customer Credit Limit", {'parent': customer, 'company': company}, 'credit_limit')
+ credit_limit = frappe.db.get_value("Customer Credit Limit",
+ {'parent': customer, 'parenttype': 'Customer', 'company': company}, 'credit_limit')
if not credit_limit:
customer_group = frappe.get_cached_value("Customer", customer, 'customer_group')
- credit_limit = frappe.get_cached_value("Customer Group", customer_group, "credit_limit")
+ credit_limit = frappe.db.get_value("Customer Credit Limit",
+ {'parent': customer_group, 'parenttype': 'Customer Group', 'company': company}, 'credit_limit')
if not credit_limit:
credit_limit = frappe.get_cached_value('Company', company, "credit_limit")
diff --git a/erpnext/selling/doctype/customer/test_customer.py b/erpnext/selling/doctype/customer/test_customer.py
index 35d1b2cf1c..87fdaa366f 100644
--- a/erpnext/selling/doctype/customer/test_customer.py
+++ b/erpnext/selling/doctype/customer/test_customer.py
@@ -25,7 +25,7 @@ class TestCustomer(unittest.TestCase):
make_test_records('Item')
def tearDown(self):
- frappe.db.set_value("Customer Credit Limit", {'parent': '_Test Customer', 'company': '_Test Company'}, 'credit_limit', 0.0)
+ set_credit_limit('_Test Customer', '_Test Company', 0)
def test_party_details(self):
from erpnext.accounts.party import get_party_details
@@ -225,8 +225,8 @@ class TestCustomer(unittest.TestCase):
item_qty = int((abs(outstanding_amt) + 200)/100)
make_sales_order(qty=item_qty)
- if credit_limit == 0.0:
- frappe.db.set_value("Customer Credit Limit", {'parent': '_Test Customer', 'company': '_Test Company'}, 'credit_limit', outstanding_amt - 50.0)
+ if not credit_limit:
+ set_credit_limit('_Test Customer', '_Test Company', outstanding_amt - 50)
# Sales Order
so = make_sales_order(do_not_submit=True)
@@ -241,7 +241,7 @@ class TestCustomer(unittest.TestCase):
self.assertRaises(frappe.ValidationError, si.submit)
if credit_limit > outstanding_amt:
- frappe.db.set_value("Customer", {'parent': '_Test Customer', 'company': '_Test Company'}, 'credit_limit', credit_limit)
+ set_credit_limit('_Test Customer', '_Test Company', credit_limit)
# Makes Sales invoice from Sales Order
so.save(ignore_permissions=True)
@@ -252,10 +252,10 @@ class TestCustomer(unittest.TestCase):
def test_customer_credit_limit_on_change(self):
outstanding_amt = self.get_customer_outstanding_amount()
customer = frappe.get_doc("Customer", '_Test Customer')
- customer.append('credit_limit_reference', {'credit_limit': flt(outstanding_amt - 100), 'company': '_Test Company'})
+ customer.append('credit_limits', {'credit_limit': flt(outstanding_amt - 100), 'company': '_Test Company'})
''' define new credit limit for same company '''
- customer.append('credit_limit_reference', {'credit_limit': flt(outstanding_amt - 100), 'company': '_Test Company'})
+ customer.append('credit_limits', {'credit_limit': flt(outstanding_amt - 100), 'company': '_Test Company'})
self.assertRaises(frappe.ValidationError, customer.save)
def test_customer_payment_terms(self):
@@ -295,3 +295,20 @@ def get_customer_dict(customer_name):
"doctype": "Customer",
"territory": "_Test Territory"
}
+
+def set_credit_limit(customer, company, credit_limit):
+ customer = frappe.get_doc("Customer", customer)
+ existing_row = None
+ for d in customer.credit_limits:
+ if d.company == company:
+ existing_row = d
+ d.credit_limit = credit_limit
+ d.db_update()
+ break
+
+ if not existing_row:
+ customer.append('credit_limits', {
+ 'company': company,
+ 'credit_limit': credit_limit
+ })
+ customer.credit_limits[-1].db_insert()
diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py
index 7d2eaf599e..12b9a8e96d 100755
--- a/erpnext/selling/doctype/sales_order/sales_order.py
+++ b/erpnext/selling/doctype/sales_order/sales_order.py
@@ -208,7 +208,9 @@ class SalesOrder(SellingController):
def check_credit_limit(self):
# if bypass credit limit check is set to true (1) at sales order level,
# then we need not to check credit limit and vise versa
- if not cint(frappe.db.get_value("Customer Credit Limit", {'parent': self.customer, 'company': self.company}, "bypass_credit_limit_check")):
+ if not cint(frappe.db.get_value("Customer Credit Limit",
+ {'parent': self.customer, 'parenttype': 'Customer', 'company': self.company},
+ "bypass_credit_limit_check")):
check_credit_limit(self.customer, self.company)
def check_nextdoc_docstatus(self):
diff --git a/erpnext/selling/doctype/sales_order/tests/test_sales_order_with_bypass_credit_limit_check.js b/erpnext/selling/doctype/sales_order/tests/test_sales_order_with_bypass_credit_limit_check.js
index 1f73f91f61..79d798b944 100644
--- a/erpnext/selling/doctype/sales_order/tests/test_sales_order_with_bypass_credit_limit_check.js
+++ b/erpnext/selling/doctype/sales_order/tests/test_sales_order_with_bypass_credit_limit_check.js
@@ -1,7 +1,7 @@
QUnit.module('Sales Order');
QUnit.test("test_sales_order_with_bypass_credit_limit_check", function(assert) {
-//#PR : 10861, Author : ashish-greycube & jigneshpshah, Email:mr.ashish.shah@gmail.com
+//#PR : 10861, Author : ashish-greycube & jigneshpshah, Email:mr.ashish.shah@gmail.com
assert.expect(2);
let done = assert.async();
frappe.run_serially([
@@ -10,7 +10,8 @@ QUnit.test("test_sales_order_with_bypass_credit_limit_check", function(assert) {
() => frappe.quick_entry.dialog.$wrapper.find('.edit-full').click(),
() => frappe.timeout(1),
() => cur_frm.set_value("customer_name", "Test Customer 10"),
- () => cur_frm.add_child('credit_limit_reference', {
+ () => cur_frm.add_child('credit_limits', {
+ 'company': cur_frm.doc.company || '_Test Company'
'credit_limit': 1000,
'bypass_credit_limit_check': 1}),
// save form
@@ -23,10 +24,10 @@ QUnit.test("test_sales_order_with_bypass_credit_limit_check", function(assert) {
() => frappe.timeout(1),
() => cur_frm.set_value("item_code", "Test Product 10"),
() => cur_frm.set_value("item_group", "Products"),
- () => cur_frm.set_value("standard_rate", 100),
+ () => cur_frm.set_value("standard_rate", 100),
// save form
() => cur_frm.save(),
- () => frappe.timeout(1),
+ () => frappe.timeout(1),
() => {
return frappe.tests.make('Sales Order', [
@@ -47,11 +48,11 @@ QUnit.test("test_sales_order_with_bypass_credit_limit_check", function(assert) {
() => frappe.tests.click_button('Yes'),
() => frappe.timeout(3),
() => {
-
+
assert.ok(cur_frm.doc.status=="To Deliver and Bill", "It is submited. Credit limit is NOT checked for sales order");
- },
+ },
() => done()
]);
});
diff --git a/erpnext/selling/doctype/sales_order/tests/test_sales_order_without_bypass_credit_limit_check.js b/erpnext/selling/doctype/sales_order/tests/test_sales_order_without_bypass_credit_limit_check.js
index 34560b6900..8de39f9aa3 100644
--- a/erpnext/selling/doctype/sales_order/tests/test_sales_order_without_bypass_credit_limit_check.js
+++ b/erpnext/selling/doctype/sales_order/tests/test_sales_order_without_bypass_credit_limit_check.js
@@ -1,7 +1,7 @@
QUnit.module('Sales Order');
QUnit.test("test_sales_order_without_bypass_credit_limit_check", function(assert) {
-//#PR : 10861, Author : ashish-greycube & jigneshpshah, Email:mr.ashish.shah@gmail.com
+//#PR : 10861, Author : ashish-greycube & jigneshpshah, Email:mr.ashish.shah@gmail.com
assert.expect(2);
let done = assert.async();
frappe.run_serially([
@@ -10,7 +10,7 @@ QUnit.test("test_sales_order_without_bypass_credit_limit_check", function(assert
() => frappe.quick_entry.dialog.$wrapper.find('.edit-full').click(),
() => frappe.timeout(1),
() => cur_frm.set_value("customer_name", "Test Customer 11"),
- () => cur_frm.add_child('credit_limit_reference', {
+ () => cur_frm.add_child('credit_limits', {
'credit_limit': 1000,
'company': '_Test Company',
'bypass_credit_limit_check': 1}),
@@ -23,10 +23,10 @@ QUnit.test("test_sales_order_without_bypass_credit_limit_check", function(assert
() => frappe.click_link('Edit in full page'),
() => cur_frm.set_value("item_code", "Test Product 11"),
() => cur_frm.set_value("item_group", "Products"),
- () => cur_frm.set_value("standard_rate", 100),
+ () => cur_frm.set_value("standard_rate", 100),
// save form
() => cur_frm.save(),
- () => frappe.timeout(1),
+ () => frappe.timeout(1),
() => {
return frappe.tests.make('Sales Order', [
@@ -47,14 +47,14 @@ QUnit.test("test_sales_order_without_bypass_credit_limit_check", function(assert
() => frappe.tests.click_button('Yes'),
() => frappe.timeout(3),
() => {
-
- if (cur_dialog.body.innerText.match(/^Credit limit has been crossed for customer.*$/))
- {
+
+ if (cur_dialog.body.innerText.match(/^Credit limit has been crossed for customer.*$/))
+ {
/*Match found */
assert.ok(true, "Credit Limit crossed message received");
}
-
-
+
+
},
() => cur_dialog.cancel(),
() => done()
diff --git a/erpnext/setup/doctype/customer_group/customer_group.json b/erpnext/setup/doctype/customer_group/customer_group.json
index c130e79541..3565b4b38a 100644
--- a/erpnext/setup/doctype/customer_group/customer_group.json
+++ b/erpnext/setup/doctype/customer_group/customer_group.json
@@ -1,553 +1,194 @@
{
- "allow_copy": 0,
- "allow_guest_to_view": 0,
+ "_comments": "[]",
"allow_import": 1,
"allow_rename": 1,
"autoname": "field:customer_group_name",
- "beta": 0,
"creation": "2013-01-10 16:34:23",
- "custom": 0,
- "docstatus": 0,
"doctype": "DocType",
"document_type": "Setup",
- "editable_grid": 0,
+ "field_order": [
+ "customer_group_name",
+ "parent_customer_group",
+ "is_group",
+ "cb0",
+ "default_price_list",
+ "payment_terms",
+ "lft",
+ "rgt",
+ "old_parent",
+ "default_receivable_account",
+ "accounts",
+ "credit_limit_section",
+ "credit_limits"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "customer_group_name",
"fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
"in_list_view": 1,
- "in_standard_filter": 0,
"label": "Customer Group Name",
- "length": 0,
"no_copy": 1,
"oldfieldname": "customer_group_name",
"oldfieldtype": "Data",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
"reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
"unique": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
"bold": 1,
- "collapsible": 0,
- "columns": 0,
- "description": "",
"fieldname": "parent_customer_group",
"fieldtype": "Link",
- "hidden": 0,
"ignore_user_permissions": 1,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
"in_list_view": 1,
- "in_standard_filter": 0,
"label": "Parent Customer Group",
- "length": 0,
- "no_copy": 0,
"oldfieldname": "parent_customer_group",
"oldfieldtype": "Link",
- "options": "Customer Group",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
+ "options": "Customer Group"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
"bold": 1,
- "collapsible": 0,
- "columns": 0,
+ "default": "0",
"description": "Only leaf nodes are allowed in transaction",
"fieldname": "is_group",
"fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
"in_list_view": 1,
- "in_standard_filter": 0,
"label": "Is Group",
- "length": 0,
- "no_copy": 0,
"oldfieldname": "is_group",
- "oldfieldtype": "Select",
- "options": "",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
+ "oldfieldtype": "Select"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "cb0",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
+ "fieldtype": "Column Break"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "default_price_list",
"fieldtype": "Link",
- "hidden": 0,
"ignore_user_permissions": 1,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Default Price List",
- "length": 0,
- "no_copy": 0,
- "options": "Price List",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
+ "options": "Price List"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
"fieldname": "payment_terms",
"fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Default Payment Terms Template",
- "length": 0,
- "no_copy": 0,
- "options": "Payment Terms Template",
- "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,
- "translatable": 0,
- "unique": 0
+ "options": "Payment Terms Template"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "credit_limit",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Credit Limit",
- "length": 0,
- "no_copy": 0,
- "permlevel": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "lft",
"fieldtype": "Int",
"hidden": 1,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "lft",
- "length": 0,
"no_copy": 1,
"oldfieldname": "lft",
"oldfieldtype": "Int",
- "permlevel": 0,
"print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
"report_hide": 1,
- "reqd": 0,
- "search_index": 1,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "search_index": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "rgt",
"fieldtype": "Int",
"hidden": 1,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "rgt",
- "length": 0,
"no_copy": 1,
"oldfieldname": "rgt",
"oldfieldtype": "Int",
- "permlevel": 0,
"print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
"report_hide": 1,
- "reqd": 0,
- "search_index": 1,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "search_index": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "",
"fieldname": "old_parent",
"fieldtype": "Link",
"hidden": 1,
"ignore_user_permissions": 1,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "old_parent",
- "length": 0,
"no_copy": 1,
"oldfieldname": "old_parent",
"oldfieldtype": "Data",
"options": "Customer Group",
- "permlevel": 0,
"print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 1,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "report_hide": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "default_receivable_account",
"fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Default Receivable Account",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
+ "label": "Default Receivable Account"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"depends_on": "eval:!doc.__islocal",
"description": "Mention if non-standard receivable account applicable",
"fieldname": "accounts",
"fieldtype": "Table",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Accounts",
- "length": 0,
- "no_copy": 0,
- "options": "Party Account",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
+ "options": "Party Account"
+ },
+ {
+ "fieldname": "credit_limit_section",
+ "fieldtype": "Section Break",
+ "label": "Credit Limits"
+ },
+ {
+ "fieldname": "credit_limits",
+ "fieldtype": "Table",
+ "label": "Credit Limit",
+ "options": "Customer Credit Limit"
}
],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
"icon": "fa fa-sitemap",
"idx": 1,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2018-08-29 06:26:05.935871",
+ "modified": "2019-09-06 12:40:14.954697",
"modified_by": "Administrator",
"module": "Setup",
"name": "Customer Group",
"owner": "Administrator",
"permissions": [
{
- "amend": 0,
- "cancel": 0,
- "create": 0,
- "delete": 0,
"email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
- "role": "Sales Manager",
- "set_user_permissions": 0,
- "share": 0,
- "submit": 0,
- "write": 0
+ "role": "Sales Manager"
},
{
- "amend": 0,
- "cancel": 0,
- "create": 0,
- "delete": 0,
"email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
- "role": "Sales User",
- "set_user_permissions": 0,
- "share": 0,
- "submit": 0,
- "write": 0
+ "role": "Sales User"
},
{
- "amend": 0,
- "cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
- "if_owner": 0,
"import": 1,
- "permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Sales Master Manager",
"set_user_permissions": 1,
"share": 1,
- "submit": 0,
"write": 1
},
{
- "amend": 0,
- "cancel": 0,
- "create": 0,
- "delete": 0,
- "email": 0,
- "export": 0,
- "if_owner": 0,
- "import": 0,
"permlevel": 1,
- "print": 0,
"read": 1,
- "report": 0,
"role": "Sales Master Manager",
- "set_user_permissions": 0,
- "share": 0,
- "submit": 0,
"write": 1
},
{
- "amend": 0,
- "cancel": 0,
- "create": 0,
- "delete": 0,
- "email": 0,
- "export": 0,
- "if_owner": 0,
- "import": 0,
"permlevel": 1,
- "print": 0,
"read": 1,
- "report": 0,
- "role": "Sales User",
- "set_user_permissions": 0,
- "share": 0,
- "submit": 0,
- "write": 0
+ "role": "Sales User"
},
{
- "amend": 0,
- "cancel": 0,
- "create": 0,
- "delete": 0,
- "email": 0,
- "export": 0,
- "if_owner": 0,
- "import": 0,
"permlevel": 1,
- "print": 0,
"read": 1,
- "report": 0,
- "role": "Sales Manager",
- "set_user_permissions": 0,
- "share": 0,
- "submit": 0,
- "write": 0
+ "role": "Sales Manager"
}
],
"quick_entry": 1,
- "read_only": 0,
- "read_only_onload": 0,
"search_fields": "parent_customer_group",
"show_name_in_global_search": 1,
- "sort_order": "DESC",
- "track_changes": 0,
- "track_seen": 0,
- "track_views": 0
+ "sort_order": "DESC"
}
\ No newline at end of file
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.py b/erpnext/stock/doctype/delivery_note/delivery_note.py
index e29cd1b792..bdb49e4919 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.py
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.py
@@ -235,7 +235,7 @@ class DeliveryNote(SellingController):
extra_amount = 0
validate_against_credit_limit = False
bypass_credit_limit_check_at_sales_order = cint(frappe.db.get_value("Customer Credit Limit",
- filters={'parent': self.customer, 'company': self.company},
+ filters={'parent': self.customer, 'parenttype': 'Customer', 'company': self.company},
fieldname="bypass_credit_limit_check"))
if bypass_credit_limit_check_at_sales_order:
From ddfbb07c3bbd5078c3e3459cfb7f2dfb7e093632 Mon Sep 17 00:00:00 2001
From: Prssanna Desai
Date: Fri, 6 Sep 2019 15:38:06 +0530
Subject: [PATCH 435/484] fix: fix accounts balance timeline dashboard chart
source (#18942)
* fix: fix accounts balance timeline dashboard chart source
* fix: pass chart_name to get function instead of chart object
---
.../account_balance_timeline/account_balance_timeline.py | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/erpnext/accounts/dashboard_chart_source/account_balance_timeline/account_balance_timeline.py b/erpnext/accounts/dashboard_chart_source/account_balance_timeline/account_balance_timeline.py
index 648cc68dac..bc07b6d807 100644
--- a/erpnext/accounts/dashboard_chart_source/account_balance_timeline/account_balance_timeline.py
+++ b/erpnext/accounts/dashboard_chart_source/account_balance_timeline/account_balance_timeline.py
@@ -12,11 +12,14 @@ from frappe.utils.nestedset import get_descendants_of
@frappe.whitelist()
@cache_source
-def get(chart_name=None, from_date = None, to_date = None):
- chart = frappe.get_doc('Dashboard Chart', chart_name)
+def get(chart_name = None, chart = None, no_cache = None, from_date = None, to_date = None):
+ if chart_name:
+ chart = frappe.get_doc('Dashboard Chart', chart_name)
+ else:
+ chart = frappe._dict(frappe.parse_json(chart))
timespan = chart.timespan
timegrain = chart.time_interval
- filters = json.loads(chart.filters_json)
+ filters = frappe.parse_json(chart.filters_json)
account = filters.get("account")
company = filters.get("company")
From c69cc13c8564682f3e4c011ea3e122622bc2b603 Mon Sep 17 00:00:00 2001
From: Shivam Mishra
Date: Fri, 6 Sep 2019 15:40:15 +0530
Subject: [PATCH 436/484] fix: updated footer message (#18949)
---
erpnext/templates/includes/footer/footer_powered.html | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/templates/includes/footer/footer_powered.html b/erpnext/templates/includes/footer/footer_powered.html
index 8d5523ff97..d4deaaef68 100644
--- a/erpnext/templates/includes/footer/footer_powered.html
+++ b/erpnext/templates/includes/footer/footer_powered.html
@@ -1,3 +1,3 @@
{% set domains = frappe.get_doc("Domain Settings").active_domains %}
-Powered by ERPNext - {{ domains[0].domain if domains else 'Open Source' }} ERP Software
+Powered by ERPNext - ERP Software {{ ('for ' + domains[0].domain + ' Companies') if domains else '' }}
From 4726fc4893073b0ae0cc0ca42700aaa4e8b1d2dd Mon Sep 17 00:00:00 2001
From: Nabin Hait
Date: Fri, 6 Sep 2019 15:45:07 +0530
Subject: [PATCH 437/484] fix: Deleted unwanted production order files
---
.../production_order/production_order.py | 648 ------------------
1 file changed, 648 deletions(-)
delete mode 100644 erpnext/manufacturing/doctype/production_order/production_order.py
diff --git a/erpnext/manufacturing/doctype/production_order/production_order.py b/erpnext/manufacturing/doctype/production_order/production_order.py
deleted file mode 100644
index 67930629f5..0000000000
--- a/erpnext/manufacturing/doctype/production_order/production_order.py
+++ /dev/null
@@ -1,648 +0,0 @@
-# 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
-import json
-from six import text_type
-from frappe import _
-from frappe.utils import flt, get_datetime, getdate, date_diff, cint, nowdate
-from frappe.model.document import Document
-from erpnext.manufacturing.doctype.bom.bom import validate_bom_no, get_bom_items_as_dict
-from dateutil.relativedelta import relativedelta
-from erpnext.stock.doctype.item.item import validate_end_of_life
-from erpnext.manufacturing.doctype.workstation.workstation import WorkstationHolidayError
-from erpnext.projects.doctype.timesheet.timesheet import OverlapError
-from erpnext.stock.doctype.stock_entry.stock_entry import get_additional_costs
-from erpnext.manufacturing.doctype.manufacturing_settings.manufacturing_settings import get_mins_between_operations
-from erpnext.stock.stock_balance import get_planned_qty, update_bin_qty
-from frappe.utils.csvutils import getlink
-from erpnext.stock.utils import get_bin, validate_warehouse_company, get_latest_stock_qty
-from erpnext.utilities.transaction_base import validate_uom_is_integer
-
-class OverProductionError(frappe.ValidationError): pass
-class StockOverProductionError(frappe.ValidationError): pass
-class OperationTooLongError(frappe.ValidationError): pass
-class ItemHasVariantError(frappe.ValidationError): pass
-
-form_grid_templates = {
- "operations": "templates/form_grid/production_order_grid.html"
-}
-
-class ProductionOrder(Document):
- def validate(self):
- self.validate_production_item()
- if self.bom_no:
- validate_bom_no(self.production_item, self.bom_no)
-
- self.validate_sales_order()
- self.set_default_warehouse()
- self.validate_warehouse_belongs_to_company()
- self.calculate_operating_cost()
- self.validate_qty()
- self.validate_operation_time()
- self.status = self.get_status()
-
- validate_uom_is_integer(self, "stock_uom", ["qty", "produced_qty"])
-
- self.set_required_items(reset_only_qty = len(self.get("required_items")))
-
- def validate_sales_order(self):
- if self.sales_order:
- so = frappe.db.sql("""
- select so.name, so_item.delivery_date, so.project
- from `tabSales Order` so
- inner join `tabSales Order Item` so_item on so_item.parent = so.name
- left join `tabProduct Bundle Item` pk_item on so_item.item_code = pk_item.parent
- where so.name=%s and so.docstatus = 1 and (
- so_item.item_code=%s or
- pk_item.item_code=%s )
- """, (self.sales_order, self.production_item, self.production_item), as_dict=1)
-
- if not so:
- so = frappe.db.sql("""
- select
- so.name, so_item.delivery_date, so.project
- from
- `tabSales Order` so, `tabSales Order Item` so_item, `tabPacked Item` packed_item
- where so.name=%s
- and so.name=so_item.parent
- and so.name=packed_item.parent
- and so_item.item_code = packed_item.parent_item
- and so.docstatus = 1 and packed_item.item_code=%s
- """, (self.sales_order, self.production_item), as_dict=1)
-
- if len(so):
- if not self.expected_delivery_date:
- self.expected_delivery_date = so[0].delivery_date
-
- if so[0].project:
- self.project = so[0].project
-
- if not self.material_request:
- self.validate_production_order_against_so()
- else:
- frappe.throw(_("Sales Order {0} is not valid").format(self.sales_order))
-
- def set_default_warehouse(self):
- if not self.wip_warehouse:
- self.wip_warehouse = frappe.db.get_single_value("Manufacturing Settings", "default_wip_warehouse")
- if not self.fg_warehouse:
- self.fg_warehouse = frappe.db.get_single_value("Manufacturing Settings", "default_fg_warehouse")
-
- def validate_warehouse_belongs_to_company(self):
- warehouses = [self.fg_warehouse, self.wip_warehouse]
- for d in self.get("required_items"):
- if d.source_warehouse not in warehouses:
- warehouses.append(d.source_warehouse)
-
- for wh in warehouses:
- validate_warehouse_company(wh, self.company)
-
- def calculate_operating_cost(self):
- self.planned_operating_cost, self.actual_operating_cost = 0.0, 0.0
- for d in self.get("operations"):
- d.planned_operating_cost = flt(d.hour_rate) * (flt(d.time_in_mins) / 60.0)
- d.actual_operating_cost = flt(d.hour_rate) * (flt(d.actual_operation_time) / 60.0)
-
- self.planned_operating_cost += flt(d.planned_operating_cost)
- self.actual_operating_cost += flt(d.actual_operating_cost)
-
- variable_cost = self.actual_operating_cost if self.actual_operating_cost \
- else self.planned_operating_cost
- self.total_operating_cost = flt(self.additional_operating_cost) + flt(variable_cost)
-
- def validate_production_order_against_so(self):
- # already ordered qty
- ordered_qty_against_so = frappe.db.sql("""select sum(qty) from `tabProduction Order`
- where production_item = %s and sales_order = %s and docstatus < 2 and name != %s""",
- (self.production_item, self.sales_order, self.name))[0][0]
-
- total_qty = flt(ordered_qty_against_so) + flt(self.qty)
-
- # get qty from Sales Order Item table
- so_item_qty = frappe.db.sql("""select sum(stock_qty) from `tabSales Order Item`
- where parent = %s and item_code = %s""",
- (self.sales_order, self.production_item))[0][0]
- # get qty from Packing Item table
- dnpi_qty = frappe.db.sql("""select sum(qty) from `tabPacked Item`
- where parent = %s and parenttype = 'Sales Order' and item_code = %s""",
- (self.sales_order, self.production_item))[0][0]
- # total qty in SO
- so_qty = flt(so_item_qty) + flt(dnpi_qty)
-
- 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)
-
- def update_status(self, status=None):
- '''Update status of production order if unknown'''
- if status != "Stopped":
- status = self.get_status(status)
-
- if status != self.status:
- self.db_set("status", status)
-
- self.update_required_items()
-
- return status
-
- def get_status(self, status=None):
- '''Return the status based on stock entries against this production order'''
- if not status:
- status = self.status
-
- if self.docstatus==0:
- status = 'Draft'
- elif self.docstatus==1:
- if status != 'Stopped':
- stock_entries = frappe._dict(frappe.db.sql("""select purpose, sum(fg_completed_qty)
- from `tabStock Entry` where production_order=%s and docstatus=1
- group by purpose""", self.name))
-
- status = "Not Started"
- if stock_entries:
- status = "In Process"
- produced_qty = stock_entries.get("Manufacture")
- if flt(produced_qty) == flt(self.qty):
- status = "Completed"
- else:
- status = 'Cancelled'
-
- return status
-
- def update_production_order_qty(self):
- """Update **Manufactured Qty** and **Material Transferred for Qty** in Production Order
- based on Stock Entry"""
-
- for purpose, fieldname in (("Manufacture", "produced_qty"),
- ("Material Transfer for Manufacture", "material_transferred_for_manufacturing")):
- qty = flt(frappe.db.sql("""select sum(fg_completed_qty)
- from `tabStock Entry` where production_order=%s and docstatus=1
- and purpose=%s""", (self.name, purpose))[0][0])
-
- if qty > self.qty:
- frappe.throw(_("{0} ({1}) cannot be greater than planned quanitity ({2}) in Production Order {3}").format(\
- self.meta.get_label(fieldname), qty, self.qty, self.name), StockOverProductionError)
-
- self.db_set(fieldname, qty)
-
- def before_submit(self):
- self.make_time_logs()
-
- def on_submit(self):
- if not self.wip_warehouse:
- frappe.throw(_("Work-in-Progress Warehouse is required before Submit"))
- if not self.fg_warehouse:
- frappe.throw(_("For Warehouse is required before Submit"))
-
- self.update_reserved_qty_for_production()
- self.update_completed_qty_in_material_request()
- self.update_planned_qty()
-
- def on_cancel(self):
- self.validate_cancel()
-
- frappe.db.set(self,'status', 'Cancelled')
- self.delete_timesheet()
- self.update_completed_qty_in_material_request()
- self.update_planned_qty()
- self.update_reserved_qty_for_production()
-
- def validate_cancel(self):
- if self.status == "Stopped":
- frappe.throw(_("Stopped Production Order cannot be cancelled, Unstop it first to cancel"))
-
- # Check whether any stock entry exists against this Production Order
- stock_entry = frappe.db.sql("""select name from `tabStock Entry`
- where production_order = %s and docstatus = 1""", self.name)
- if stock_entry:
- frappe.throw(_("Cannot cancel because submitted Stock Entry {0} exists").format(stock_entry[0][0]))
-
- def update_planned_qty(self):
- update_bin_qty(self.production_item, self.fg_warehouse, {
- "planned_qty": get_planned_qty(self.production_item, self.fg_warehouse)
- })
-
- if self.material_request:
- mr_obj = frappe.get_doc("Material Request", self.material_request)
- mr_obj.update_requested_qty([self.material_request_item])
-
- def update_completed_qty_in_material_request(self):
- if self.material_request:
- frappe.get_doc("Material Request", self.material_request).update_completed_qty([self.material_request_item])
-
- 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
- operation, description, workstation, idx,
- 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()
-
- def calculate_time(self):
- bom_qty = frappe.db.get_value("BOM", self.bom_no, "quantity")
-
- for d in self.get("operations"):
- d.time_in_mins = flt(d.time_in_mins) / flt(bom_qty) * flt(self.qty)
-
- self.calculate_operating_cost()
-
- def get_holidays(self, workstation):
- holiday_list = frappe.db.get_value("Workstation", workstation, "holiday_list")
-
- holidays = {}
-
- if holiday_list not in holidays:
- holiday_list_days = [getdate(d[0]) for d in frappe.get_all("Holiday", fields=["holiday_date"],
- filters={"parent": holiday_list}, order_by="holiday_date", limit_page_length=0, as_list=1)]
-
- holidays[holiday_list] = holiday_list_days
-
- return holidays[holiday_list]
-
- def make_time_logs(self, open_new=False):
- """Capacity Planning. Plan time logs based on earliest availablity of workstation after
- Planned Start Date. Time logs will be created and remain in Draft mode and must be submitted
- before manufacturing entry can be made."""
-
- if not self.operations:
- return
-
- timesheets = []
- plan_days = frappe.db.get_single_value("Manufacturing Settings", "capacity_planning_for_days") or 30
-
- timesheet = make_timesheet(self.name, self.company)
- timesheet.set('time_logs', [])
-
- for i, d in enumerate(self.operations):
-
- if d.status != 'Completed':
- self.set_start_end_time_for_workstation(d, i)
-
- args = self.get_operations_data(d)
-
- add_timesheet_detail(timesheet, args)
- original_start_time = d.planned_start_time
-
- # validate operating hours if workstation [not mandatory] is specified
- try:
- timesheet.validate_time_logs()
- except OverlapError:
- if frappe.message_log: frappe.message_log.pop()
- timesheet.schedule_for_production_order(d.idx)
- except WorkstationHolidayError:
- if frappe.message_log: frappe.message_log.pop()
- timesheet.schedule_for_production_order(d.idx)
-
- from_time, to_time = self.get_start_end_time(timesheet, d.name)
-
- if date_diff(from_time, original_start_time) > cint(plan_days):
- frappe.throw(_("Unable to find Time Slot in the next {0} days for Operation {1}").format(plan_days, d.operation))
- break
-
- d.planned_start_time = from_time
- d.planned_end_time = to_time
- d.db_update()
-
- if timesheet and open_new:
- return timesheet
-
- if timesheet and timesheet.get("time_logs"):
- timesheet.save()
- timesheets.append(getlink("Timesheet", timesheet.name))
-
- self.planned_end_date = self.operations[-1].planned_end_time
- if timesheets:
- frappe.local.message_log = []
- frappe.msgprint(_("Timesheet created:") + "\n" + "\n".join(timesheets))
-
- def get_operations_data(self, data):
- return {
- 'from_time': get_datetime(data.planned_start_time),
- 'hours': data.time_in_mins / 60.0,
- 'to_time': get_datetime(data.planned_end_time),
- 'project': self.project,
- 'operation': data.operation,
- 'operation_id': data.name,
- 'workstation': data.workstation,
- 'completed_qty': flt(self.qty) - flt(data.completed_qty)
- }
-
- def set_start_end_time_for_workstation(self, data, index):
- """Set start and end time for given operation. If first operation, set start as
- `planned_start_date`, else add time diff to end time of earlier operation."""
-
- if index == 0:
- data.planned_start_time = self.planned_start_date
- else:
- data.planned_start_time = get_datetime(self.operations[index-1].planned_end_time)\
- + get_mins_between_operations()
-
- data.planned_end_time = get_datetime(data.planned_start_time) + relativedelta(minutes = data.time_in_mins)
-
- if data.planned_start_time == data.planned_end_time:
- frappe.throw(_("Capacity Planning Error"))
-
- def get_start_end_time(self, timesheet, operation_id):
- for data in timesheet.time_logs:
- if data.operation_id == operation_id:
- return data.from_time, data.to_time
-
- def check_operation_fits_in_working_hours(self, d):
- """Raises expection if operation is longer than working hours in the given workstation."""
- from erpnext.manufacturing.doctype.workstation.workstation import check_if_within_operating_hours
- check_if_within_operating_hours(d.workstation, d.operation, d.planned_start_time, d.planned_end_time)
-
- def update_operation_status(self):
- for d in self.get("operations"):
- if not d.completed_qty:
- d.status = "Pending"
- elif flt(d.completed_qty) < flt(self.qty):
- d.status = "Work in Progress"
- elif flt(d.completed_qty) == flt(self.qty):
- d.status = "Completed"
- else:
- frappe.throw(_("Completed Qty can not be greater than 'Qty to Manufacture'"))
-
- def set_actual_dates(self):
- self.actual_start_date = None
- self.actual_end_date = None
- if self.get("operations"):
- actual_start_dates = [d.actual_start_time for d in self.get("operations") if d.actual_start_time]
- if actual_start_dates:
- self.actual_start_date = min(actual_start_dates)
-
- actual_end_dates = [d.actual_end_time for d in self.get("operations") if d.actual_end_time]
- if actual_end_dates:
- self.actual_end_date = max(actual_end_dates)
-
- def delete_timesheet(self):
- for timesheet in frappe.get_all("Timesheet", ["name"], {"production_order": self.name}):
- frappe.delete_doc("Timesheet", timesheet.name)
-
- def validate_production_item(self):
- if frappe.db.get_value("Item", self.production_item, "has_variants"):
- frappe.throw(_("Production Order cannot be raised against a Item Template"), ItemHasVariantError)
-
- if self.production_item:
- validate_end_of_life(self.production_item)
-
- def validate_qty(self):
- if not self.qty > 0:
- frappe.throw(_("Quantity to Manufacture must be greater than 0."))
-
- def validate_operation_time(self):
- for d in self.operations:
- if not d.time_in_mins > 0:
- frappe.throw(_("Operation Time must be greater than 0 for Operation {0}".format(d.operation)))
-
- def update_required_items(self):
- '''
- update bin reserved_qty_for_production
- called from Stock Entry for production, after submit, cancel
- '''
- if self.docstatus==1:
- # calculate transferred qty based on submitted stock entries
- self.update_transaferred_qty_for_required_items()
-
- # update in bin
- self.update_reserved_qty_for_production()
-
- def update_reserved_qty_for_production(self, items=None):
- '''update reserved_qty_for_production in bins'''
- for d in self.required_items:
- 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)
-
- def set_required_items(self, reset_only_qty=False):
- '''set required_items for production to keep track of reserved qty'''
- if not reset_only_qty:
- self.required_items = []
-
- if self.bom_no and self.qty:
- item_dict = get_bom_items_as_dict(self.bom_no, self.company, qty=self.qty,
- fetch_exploded = self.use_multi_level_bom)
-
- if reset_only_qty:
- for d in self.get("required_items"):
- if item_dict.get(d.item_code):
- d.required_qty = item_dict.get(d.item_code).get("qty")
- else:
- for item in sorted(item_dict.values(), key=lambda d: d['idx']):
- self.append('required_items', {
- 'item_code': item.item_code,
- 'item_name': item.item_name,
- 'description': item.description,
- '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):
- '''update transferred qty from submitted stock entries for that item against
- the production order'''
-
- for d in self.required_items:
- transferred_qty = frappe.db.sql('''select sum(qty)
- from `tabStock Entry` entry, `tabStock Entry Detail` detail
- where
- entry.production_order = %s
- and entry.purpose = "Material Transfer for Manufacture"
- and entry.docstatus = 1
- and detail.parent = entry.name
- and detail.item_code = %s''', (self.name, d.item_code))[0][0]
-
- d.db_set('transferred_qty', flt(transferred_qty), update_modified = False)
-
-
-@frappe.whitelist()
-def get_item_details(item, project = None):
- res = frappe.db.sql("""
- select stock_uom, description
- 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 {}
-
- res = res[0]
-
- filters = {"item": item, "is_default": 1}
-
- if project:
- filters = {"item": item, "project": project}
-
- res["bom_no"] = frappe.db.get_value("BOM", filters = filters)
-
- if not res["bom_no"]:
- variant_of= frappe.db.get_value("Item", item, "variant_of")
-
- if variant_of:
- res["bom_no"] = frappe.db.get_value("BOM", filters={"item": variant_of, "is_default": 1})
-
- if not res["bom_no"]:
- if project:
- res = get_item_details(item)
- frappe.msgprint(_("Default BOM not found for Item {0} and Project {1}").format(item, project), alert=1)
- else:
- frappe.throw(_("Default BOM for {0} not found").format(item))
-
- res['project'] = project or frappe.db.get_value('BOM', res['bom_no'], 'project')
- res.update(check_if_scrap_warehouse_mandatory(res["bom_no"]))
-
- return res
-
-@frappe.whitelist()
-def check_if_scrap_warehouse_mandatory(bom_no):
- res = {"set_scrap_wh_mandatory": False }
- if bom_no:
- bom = frappe.get_doc("BOM", bom_no)
-
- if len(bom.scrap_items) > 0:
- res["set_scrap_wh_mandatory"] = True
-
- return res
-
-@frappe.whitelist()
-def set_production_order_ops(name):
- po = frappe.get_doc('Production Order', name)
- po.set_production_order_operations()
- po.save()
-
-@frappe.whitelist()
-def make_stock_entry(production_order_id, purpose, qty=None):
- production_order = frappe.get_doc("Production Order", production_order_id)
- if not frappe.db.get_value("Warehouse", production_order.wip_warehouse, "is_group") \
- and not production_order.skip_transfer:
- wip_warehouse = production_order.wip_warehouse
- else:
- wip_warehouse = None
-
- stock_entry = frappe.new_doc("Stock Entry")
- stock_entry.purpose = purpose
- stock_entry.production_order = production_order_id
- stock_entry.company = production_order.company
- stock_entry.from_bom = 1
- stock_entry.bom_no = production_order.bom_no
- stock_entry.use_multi_level_bom = production_order.use_multi_level_bom
- stock_entry.fg_completed_qty = qty or (flt(production_order.qty) - flt(production_order.produced_qty))
- stock_entry.set_stock_entry_type()
-
- if purpose=="Material Transfer for Manufacture":
- stock_entry.to_warehouse = wip_warehouse
- stock_entry.project = production_order.project
- else:
- stock_entry.from_warehouse = wip_warehouse
- stock_entry.to_warehouse = production_order.fg_warehouse
- additional_costs = get_additional_costs(production_order, fg_qty=stock_entry.fg_completed_qty)
- stock_entry.project = production_order.project
- stock_entry.set("additional_costs", additional_costs)
-
- stock_entry.get_items()
- return stock_entry.as_dict()
-
-@frappe.whitelist()
-def make_timesheet(production_order, company):
- timesheet = frappe.new_doc("Timesheet")
- timesheet.employee = ""
- timesheet.production_order = production_order
- timesheet.company = company
- return timesheet
-
-@frappe.whitelist()
-def add_timesheet_detail(timesheet, args):
- if isinstance(timesheet, text_type):
- timesheet = frappe.get_doc('Timesheet', timesheet)
-
- if isinstance(args, text_type):
- args = json.loads(args)
-
- timesheet.append('time_logs', args)
- return timesheet
-
-@frappe.whitelist()
-def get_default_warehouse():
- wip_warehouse = frappe.db.get_single_value("Manufacturing Settings",
- "default_wip_warehouse")
- fg_warehouse = frappe.db.get_single_value("Manufacturing Settings",
- "default_fg_warehouse")
- return {"wip_warehouse": wip_warehouse, "fg_warehouse": fg_warehouse}
-
-@frappe.whitelist()
-def make_new_timesheet(source_name, target_doc=None):
- po = frappe.get_doc('Production Order', source_name)
- ts = po.make_time_logs(open_new=True)
-
- if not ts or not ts.get('time_logs'):
- frappe.throw(_("Already completed"))
-
- return ts
-
-@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
-
-@frappe.whitelist()
-def query_sales_order(production_item):
- out = frappe.db.sql_list("""
- select distinct so.name from `tabSales Order` so, `tabSales Order Item` so_item
- where so_item.parent=so.name and so_item.item_code=%s and so.docstatus=1
- union
- select distinct so.name from `tabSales Order` so, `tabPacked Item` pi_item
- where pi_item.parent=so.name and pi_item.item_code=%s and so.docstatus=1
- """, (production_item, production_item))
-
- return out
From 8e67a3a8a84e22844c05f750fa309b703c84c8a6 Mon Sep 17 00:00:00 2001
From: Saurabh
Date: Sat, 7 Sep 2019 12:29:29 +0530
Subject: [PATCH 438/484] fix: check if 'All Item Group' exists before settings
it as parent_item_group (#18956)
* fix: check if 'All Item Group' exists before settings it as parent_item_group
* feat: get cached value to avoid db call on each insert
---
erpnext/setup/doctype/item_group/item_group.py | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/erpnext/setup/doctype/item_group/item_group.py b/erpnext/setup/doctype/item_group/item_group.py
index bb357d8bf8..b309b504e0 100644
--- a/erpnext/setup/doctype/item_group/item_group.py
+++ b/erpnext/setup/doctype/item_group/item_group.py
@@ -4,6 +4,7 @@
from __future__ import unicode_literals
import frappe
import copy
+from frappe import _
from frappe.utils import nowdate, cint, cstr
from frappe.utils.nestedset import NestedSet
from frappe.website.website_generator import WebsiteGenerator
@@ -28,7 +29,8 @@ class ItemGroup(NestedSet, WebsiteGenerator):
super(ItemGroup, self).validate()
if not self.parent_item_group and not frappe.flags.in_test:
- self.parent_item_group = 'All Item Groups'
+ if frappe.db.exists("Item Group", _('All Item Groups'), cache=True):
+ self.parent_item_group = _('All Item Groups')
self.make_route()
From 3b366c30a83e2e5e6e65d076e8b15fc11955e7e1 Mon Sep 17 00:00:00 2001
From: Nabin Hait
Date: Sat, 7 Sep 2019 12:31:07 +0530
Subject: [PATCH 439/484] feat: Added default Leave Approver in Employee
(#18953)
---
erpnext/hr/doctype/employee/employee.json | 10 +++++++++-
.../doctype/leave_application/leave_application.py | 14 ++++++++------
2 files changed, 17 insertions(+), 7 deletions(-)
diff --git a/erpnext/hr/doctype/employee/employee.json b/erpnext/hr/doctype/employee/employee.json
index 5202218ed3..ee0b2a265a 100644
--- a/erpnext/hr/doctype/employee/employee.json
+++ b/erpnext/hr/doctype/employee/employee.json
@@ -7,6 +7,7 @@
"doctype": "DocType",
"document_type": "Setup",
"editable_grid": 1,
+ "engine": "InnoDB",
"field_order": [
"basic_information",
"employee",
@@ -54,6 +55,7 @@
"column_break_44",
"holiday_list",
"default_shift",
+ "leave_approver",
"salary_information",
"salary_mode",
"bank_name",
@@ -767,12 +769,18 @@
"fieldtype": "Link",
"label": "Default Shift",
"options": "Shift Type"
+ },
+ {
+ "fieldname": "leave_approver",
+ "fieldtype": "Link",
+ "label": "Leave Approver",
+ "options": "User"
}
],
"icon": "fa fa-user",
"idx": 24,
"image_field": "image",
- "modified": "2019-06-01 16:05:55.132180",
+ "modified": "2019-09-06 15:54:36.735147",
"modified_by": "Administrator",
"module": "HR",
"name": "Employee",
diff --git a/erpnext/hr/doctype/leave_application/leave_application.py b/erpnext/hr/doctype/leave_application/leave_application.py
index 0aa8849e87..d4da9c1ee6 100755
--- a/erpnext/hr/doctype/leave_application/leave_application.py
+++ b/erpnext/hr/doctype/leave_application/leave_application.py
@@ -745,10 +745,12 @@ def get_approved_leaves_for_period(employee, leave_type, from_date, to_date):
return leave_days
@frappe.whitelist()
-def get_leave_approver(employee, department=None):
- if not department:
- department = frappe.db.get_value('Employee', employee, 'department')
+def get_leave_approver(employee):
+ leave_approver, department = frappe.db.get_value("Employee",
+ employee, ["leave_approver", "department"])
- if department:
- return frappe.db.get_value('Department Approver', {'parent': department,
- 'parentfield': 'leave_approvers', 'idx': 1}, 'approver')
\ No newline at end of file
+ if not leave_approver and department:
+ leave_approver = frappe.db.get_value('Department Approver', {'parent': department,
+ 'parentfield': 'leave_approvers', 'idx': 1}, 'approver')
+
+ return leave_approver
\ No newline at end of file
From 21a4f82f6995ae152fc850ce06a094b733b37108 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Sat, 7 Sep 2019 20:21:56 +0530
Subject: [PATCH 440/484] fix: Re-arrange filters
---
.../employee_leave_balance_summary.js | 44 +++++++++----------
1 file changed, 22 insertions(+), 22 deletions(-)
diff --git a/erpnext/hr/report/employee_leave_balance_summary/employee_leave_balance_summary.js b/erpnext/hr/report/employee_leave_balance_summary/employee_leave_balance_summary.js
index a05db33050..838f4ad147 100644
--- a/erpnext/hr/report/employee_leave_balance_summary/employee_leave_balance_summary.js
+++ b/erpnext/hr/report/employee_leave_balance_summary/employee_leave_balance_summary.js
@@ -2,35 +2,35 @@
// For license information, please see license.txt
/* eslint-disable */
-frappe.query_reports["Employee Leave Balance Summary"] = {
- "filters": [
+frappe.query_reports['Employee Leave Balance Summary'] = {
+ filters: [
{
- "fieldname":"from_date",
- "label": __("From Date"),
- "fieldtype": "Date",
- "reqd": 1,
- "default": frappe.defaults.get_default("year_start_date")
+ fieldname:'company',
+ label: __('Company'),
+ fieldtype: 'Link',
+ options: 'Company',
+ reqd: 1,
+ default: frappe.defaults.get_user_default('Company')
},
{
- "fieldname":"to_date",
- "label": __("To Date"),
- "fieldtype": "Date",
- "reqd": 1,
- "default": frappe.defaults.get_default("year_end_date")
+ fieldname:'employee',
+ label: __('Employee'),
+ fieldtype: 'Link',
+ options: 'Employee',
},
{
- "fieldname":"company",
- "label": __("Company"),
- "fieldtype": "Link",
- "options": "Company",
- "reqd": 1,
- "default": frappe.defaults.get_user_default("Company")
+ fieldname:'from_date',
+ label: __('From Date'),
+ fieldtype: 'Date',
+ reqd: 1,
+ default: frappe.defaults.get_default('year_start_date')
},
{
- "fieldname":"employee",
- "label": __("Employee"),
- "fieldtype": "Link",
- "options": "Employee",
+ fieldname:'to_date',
+ label: __('To Date'),
+ fieldtype: 'Date',
+ reqd: 1,
+ default: frappe.defaults.get_default('year_end_date')
}
]
};
From c5588a9b930ff4ed2d4a5a0bc6d57044df9f1e71 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Sat, 7 Sep 2019 21:26:43 +0530
Subject: [PATCH 441/484] fix: Column value and data indentation
---
.../employee_leave_balance_summary.py | 65 ++++++++++++++-----
1 file changed, 49 insertions(+), 16 deletions(-)
diff --git a/erpnext/hr/report/employee_leave_balance_summary/employee_leave_balance_summary.py b/erpnext/hr/report/employee_leave_balance_summary/employee_leave_balance_summary.py
index 5512f7aa25..f52a34866a 100644
--- a/erpnext/hr/report/employee_leave_balance_summary/employee_leave_balance_summary.py
+++ b/erpnext/hr/report/employee_leave_balance_summary/employee_leave_balance_summary.py
@@ -5,35 +5,59 @@ from __future__ import unicode_literals
import frappe
from frappe.utils import flt
from frappe import _
-from erpnext.hr.doctype.leave_application.leave_application \
- import get_leave_balance_on, get_leaves_for_period
+from erpnext.hr.doctype.leave_application.leave_application import get_leaves_for_period
-from erpnext.hr.report.employee_leave_balance.employee_leave_balance \
- import get_total_allocated_leaves
+from ..employee_leave_balance.employee_leave_balance import get_total_allocated_leaves
def execute(filters=None):
+ if filters.to_date <= filters.from_date:
+ frappe.throw(_('From date can not be greater than than To date'))
+
columns = get_columns()
data = get_data(filters)
return columns, data
def get_columns():
- columns = []
- columns.append(_('Leave Type') )
- columns.append(_('Employee'))
- columns.append(_('Employee Name'))
- columns.append(_('Opening Balance') + ':Float:160')
- columns.append(_('Leaves Taken') + ':Float:160')
- columns.append(_('Closing Balance') + ':Float:160')
+ columns = [{
+ 'label': _('Leave Type'),
+ 'fieldtype': 'Link',
+ 'fieldname': 'leave_type',
+ 'width': 300,
+ 'options': 'Leave Type'
+ }, {
+ 'label': _('Employee'),
+ 'fieldtype': 'Link',
+ 'fieldname': 'employee',
+ 'width': 100,
+ 'options': 'Employee'
+ }, {
+ 'label': _('Employee Name'),
+ 'fieldtype': 'Data',
+ 'fieldname': 'employee_name',
+ 'width': 100,
+ }, {
+ 'label': _('Opening Balance'),
+ 'fieldtype': 'float',
+ 'fieldname': 'opening_balance',
+ 'width': 160,
+ }, {
+ 'label': _('Leaves Taken'),
+ 'fieldtype': 'float',
+ 'fieldname': 'leaves_taken',
+ 'width': 160,
+ }, {
+ 'label': _('Closing Balance'),
+ 'fieldtype': 'float',
+ 'fieldname': 'closing_balance',
+ 'width': 160,
+ }]
return columns
def get_data(filters):
leave_types = frappe.db.sql_list("SELECT `name` FROM `tabLeave Type` ORDER BY `name` ASC")
- if filters.to_date <= filters.from_date:
- frappe.throw(_('From date can not be greater than than To date'))
-
conditions = {
'status': 'Active',
}
@@ -48,8 +72,14 @@ def get_data(filters):
data = []
for leave_type in leave_types:
+ data.append({
+ 'leave_type': leave_type
+ })
for employee in active_employees:
- row = [leave_type, employee.name, employee.employee_name]
+ row = frappe._dict({
+ 'employee': employee.name,
+ 'employee_name': employee.employee_name
+ })
leaves_taken = get_leaves_for_period(employee.name, leave_type,
filters.from_date, filters.to_date) * -1
@@ -57,7 +87,10 @@ def get_data(filters):
opening = get_total_allocated_leaves(employee.name, leave_type, filters.from_date, filters.to_date)
closing = flt(opening) - flt(leaves_taken)
- row += [opening, leaves_taken, closing]
+ row.opening_balance = opening
+ row.leaves_taken = leaves_taken
+ row.closing_balance = closing
+ row.indent = 1
data.append(row)
return data
From 366451fc62ab5055c2e0ad30ced26839bb15ffd8 Mon Sep 17 00:00:00 2001
From: deepeshgarg007
Date: Sun, 8 Sep 2019 09:51:15 +0530
Subject: [PATCH 442/484] fix: Minor fix in GSTR-1
---
erpnext/regional/report/gstr_1/gstr_1.py | 11 +++++------
1 file changed, 5 insertions(+), 6 deletions(-)
diff --git a/erpnext/regional/report/gstr_1/gstr_1.py b/erpnext/regional/report/gstr_1/gstr_1.py
index c397133f33..43e232bf72 100644
--- a/erpnext/regional/report/gstr_1/gstr_1.py
+++ b/erpnext/regional/report/gstr_1/gstr_1.py
@@ -163,15 +163,14 @@ class Gstr1Report(object):
if not b2c_limit:
frappe.throw(_("Please set B2C Limit in GST Settings."))
- if self.filters.get("type_of_business") == "B2C Large" and customers:
+ if self.filters.get("type_of_business") == "B2C Large":
conditions += """ and SUBSTR(place_of_supply, 1, 2) != SUBSTR(company_gstin, 1, 2)
- and grand_total > {0} and is_return != 1 and gst_category ='Unregistered' """.\
- format(flt(b2c_limit), ", ".join([frappe.db.escape(c.name) for c in customers]))
- elif self.filters.get("type_of_business") == "B2C Small" and customers:
+ and grand_total > {0} and is_return != 1 and gst_category ='Unregistered' """.format(flt(b2c_limit))
+
+ elif self.filters.get("type_of_business") == "B2C Small":
conditions += """ and (
SUBSTR(place_of_supply, 1, 2) = SUBSTR(company_gstin, 1, 2)
- or grand_total <= {0}) and is_return != 1 and gst_category ='Unregistered' """.\
- format(flt(b2c_limit), ", ".join([frappe.db.escape(c.name) for c in customers]))
+ or grand_total <= {0}) and is_return != 1 and gst_category ='Unregistered' """.format(flt(b2c_limit))
elif self.filters.get("type_of_business") == "CDNR":
conditions += """ and is_return = 1 """
From 594918bd3a18b339ea52df33f64d10d82b9b398a Mon Sep 17 00:00:00 2001
From: Faris Ansari
Date: Sun, 8 Sep 2019 13:13:05 +0530
Subject: [PATCH 443/484] fix: Include Item variant patch in patches.txt
(#18961)
---
erpnext/patches.txt | 3 ++-
.../v12_0/add_variant_of_in_item_attribute_table.py | 10 +++++-----
2 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 2af12698c5..2f74d54dd2 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -632,4 +632,5 @@ execute:frappe.reload_doc('desk', 'doctype','dashboard_chart')
erpnext.patches.v12_0.add_default_dashboards
erpnext.patches.v12_0.remove_bank_remittance_custom_fields
erpnext.patches.v12_0.generate_leave_ledger_entries
-erpnext.patches.v12_0.move_credit_limit_to_customer_credit_limit
\ No newline at end of file
+erpnext.patches.v12_0.move_credit_limit_to_customer_credit_limit
+erpnext.patches.v12_0.add_variant_of_in_item_attribute_table
diff --git a/erpnext/patches/v12_0/add_variant_of_in_item_attribute_table.py b/erpnext/patches/v12_0/add_variant_of_in_item_attribute_table.py
index bc6119067c..bb13078b13 100644
--- a/erpnext/patches/v12_0/add_variant_of_in_item_attribute_table.py
+++ b/erpnext/patches/v12_0/add_variant_of_in_item_attribute_table.py
@@ -1,8 +1,8 @@
import frappe
def execute():
- frappe.db.sql('''
- UPDATE `tabItem Variant Attribute` t1
- INNER JOIN `tabItem` t2 ON t2.name = t1.parent
- SET t1.variant_of = t2.variant_of
- ''')
+ frappe.db.sql('''
+ UPDATE `tabItem Variant Attribute` t1
+ INNER JOIN `tabItem` t2 ON t2.name = t1.parent
+ SET t1.variant_of = t2.variant_of
+ ''')
From 5ae40a950091482dac63eb9552d42bd7931ee332 Mon Sep 17 00:00:00 2001
From: Suraj Shetty <13928957+surajshetty3416@users.noreply.github.com>
Date: Sun, 8 Sep 2019 15:16:35 +0530
Subject: [PATCH 444/484] fix: Use absolute import instead of relative import
Co-Authored-By: Mangesh-Khairnar
---
.../employee_leave_balance_summary.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/hr/report/employee_leave_balance_summary/employee_leave_balance_summary.py b/erpnext/hr/report/employee_leave_balance_summary/employee_leave_balance_summary.py
index f52a34866a..64a5c1c13a 100644
--- a/erpnext/hr/report/employee_leave_balance_summary/employee_leave_balance_summary.py
+++ b/erpnext/hr/report/employee_leave_balance_summary/employee_leave_balance_summary.py
@@ -7,7 +7,7 @@ from frappe.utils import flt
from frappe import _
from erpnext.hr.doctype.leave_application.leave_application import get_leaves_for_period
-from ..employee_leave_balance.employee_leave_balance import get_total_allocated_leaves
+from erpnext.hr.report.employee_leave_balance.employee_leave_balance import get_total_allocated_leaves
def execute(filters=None):
if filters.to_date <= filters.from_date:
From e352fb754bb2064782522b557981f46426338b62 Mon Sep 17 00:00:00 2001
From: Faris Ansari
Date: Sun, 8 Sep 2019 21:25:33 +0530
Subject: [PATCH 445/484] fix: Reload doctype in variants patch (#18962)
---
erpnext/patches/v12_0/add_variant_of_in_item_attribute_table.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/erpnext/patches/v12_0/add_variant_of_in_item_attribute_table.py b/erpnext/patches/v12_0/add_variant_of_in_item_attribute_table.py
index bb13078b13..893f7a4909 100644
--- a/erpnext/patches/v12_0/add_variant_of_in_item_attribute_table.py
+++ b/erpnext/patches/v12_0/add_variant_of_in_item_attribute_table.py
@@ -1,6 +1,7 @@
import frappe
def execute():
+ frappe.reload_doc('stock', 'doctype', 'item_variant_attribute')
frappe.db.sql('''
UPDATE `tabItem Variant Attribute` t1
INNER JOIN `tabItem` t2 ON t2.name = t1.parent
From cdcff6c26d56abead76e609a119a52b286c5cc24 Mon Sep 17 00:00:00 2001
From: rohitwaghchaure
Date: Mon, 9 Sep 2019 10:15:01 +0530
Subject: [PATCH 446/484] Multiple port from v11 hotfix (#18954)
* fix: circular dependency during asset cancellation
* fix: ImponibileImporto for On Previous Row Total
* fix: PrezzoUnitario decimal issue
---
erpnext/assets/doctype/asset/asset.py | 6 ------
erpnext/regional/italy/e-invoice.xml | 14 +++++++-------
erpnext/regional/italy/utils.py | 9 +++++++--
3 files changed, 14 insertions(+), 15 deletions(-)
diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py
index ab37e91538..8f208e2cdb 100644
--- a/erpnext/assets/doctype/asset/asset.py
+++ b/erpnext/assets/doctype/asset/asset.py
@@ -292,12 +292,6 @@ class Asset(AccountsController):
if self.status not in ("Submitted", "Partially Depreciated", "Fully Depreciated"):
frappe.throw(_("Asset cannot be cancelled, as it is already {0}").format(self.status))
- if self.purchase_invoice:
- frappe.throw(_("Please cancel Purchase Invoice {0} first").format(self.purchase_invoice))
-
- if self.purchase_receipt:
- frappe.throw(_("Please cancel Purchase Receipt {0} first").format(self.purchase_receipt))
-
def delete_depreciation_entries(self):
for d in self.get("schedules"):
if d.journal_entry:
diff --git a/erpnext/regional/italy/e-invoice.xml b/erpnext/regional/italy/e-invoice.xml
index 9a588d1666..9978dc0da2 100644
--- a/erpnext/regional/italy/e-invoice.xml
+++ b/erpnext/regional/italy/e-invoice.xml
@@ -1,5 +1,5 @@
-{%- macro format_float(value) -%}
-{{ "%.2f" % value|abs }}
+{%- macro format_float(value, precision=2) -%}
+{{ value|round(frappe.utils.cint(precision)) }}
{%- endmacro -%}
{%- macro render_address(address) %}
@@ -182,10 +182,10 @@
{{ html2text(item.description or '') or item.item_name }}
{{ format_float(item.qty) }}
{{ item.stock_uom }}
- {{ format_float(item.price_list_rate or item.rate) }}
+ {{ format_float(item.price_list_rate or item.rate, item_meta.get_field("rate").precision) }}
{{ render_discount_or_margin(item) }}
- {{ format_float(item.amount) }}
- {{ format_float(item.tax_rate) }}
+ {{ format_float(item.amount, item_meta.get_field("amount").precision) }}
+ {{ format_float(item.tax_rate, item_meta.get_field("tax_rate").precision) }}
{%- if item.tax_exemption_reason %}
{{ item.tax_exemption_reason.split("-")[0] }}
{%- endif %}
@@ -197,8 +197,8 @@
{%- if data.tax_exemption_reason %}
{{ data.tax_exemption_reason.split("-")[0] }}
{%- endif %}
- {{ format_float(data.taxable_amount) }}
- {{ format_float(data.tax_amount) }}
+ {{ format_float(data.taxable_amount, item_meta.get_field("tax_amount").precision) }}
+ {{ format_float(data.tax_amount, item_meta.get_field("tax_amount").precision) }}
{{ doc.vat_collectability.split("-")[0] }}
{%- if data.tax_exemption_law %}
{{ data.tax_exemption_law }}
diff --git a/erpnext/regional/italy/utils.py b/erpnext/regional/italy/utils.py
index 407677f976..12f5762f44 100644
--- a/erpnext/regional/italy/utils.py
+++ b/erpnext/regional/italy/utils.py
@@ -151,7 +151,8 @@ def get_invoice_summary(items, taxes):
tax_rate=tax.rate,
tax_amount=(reference_row.tax_amount * tax.rate) / 100,
net_amount=reference_row.tax_amount,
- taxable_amount=reference_row.tax_amount,
+ taxable_amount=(reference_row.tax_amount if tax.charge_type == 'On Previous Row Amount'
+ else reference_row.total),
item_tax_rate={tax.account_head: tax.rate},
charges=True
)
@@ -278,7 +279,11 @@ def prepare_and_attach_invoice(doc, replace=False):
progressive_name, progressive_number = get_progressive_name_and_number(doc, replace)
invoice = prepare_invoice(doc, progressive_number)
- invoice_xml = frappe.render_template('erpnext/regional/italy/e-invoice.xml', context={"doc": invoice}, is_path=True)
+ item_meta = frappe.get_meta("Sales Invoice Item")
+
+ invoice_xml = frappe.render_template('erpnext/regional/italy/e-invoice.xml',
+ context={"doc": invoice, "item_meta": item_meta}, is_path=True)
+
invoice_xml = invoice_xml.replace("&", "&")
xml_filename = progressive_name + ".xml"
From ffc4f8f2a5a0bac78a5aee75683c607fb55fc775 Mon Sep 17 00:00:00 2001
From: MorezMartin
Date: Mon, 9 Sep 2019 06:46:23 +0200
Subject: [PATCH 447/484] feat: [stock -> packed_items] Enable modification of
Description on packed items (#18907)
* Change packed item
* Remove description field on update_packed_items
* add possibility to modify description on packed items
---
.../doctype/packed_item/packed_item.json | 836 ++++--------------
.../stock/doctype/packed_item/packed_item.py | 10 +-
2 files changed, 182 insertions(+), 664 deletions(-)
diff --git a/erpnext/stock/doctype/packed_item/packed_item.json b/erpnext/stock/doctype/packed_item/packed_item.json
index 6c8b2b1d05..b089e759a0 100644
--- a/erpnext/stock/doctype/packed_item/packed_item.json
+++ b/erpnext/stock/doctype/packed_item/packed_item.json
@@ -1,685 +1,203 @@
{
- "allow_copy": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "beta": 0,
- "creation": "2013-02-22 01:28:00",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "editable_grid": 1,
- "engine": "InnoDB",
+ "creation": "2013-02-22 01:28:00",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "parent_item",
+ "item_code",
+ "item_name",
+ "column_break_5",
+ "description",
+ "section_break_6",
+ "warehouse",
+ "target_warehouse",
+ "column_break_9",
+ "qty",
+ "section_break_9",
+ "serial_no",
+ "column_break_11",
+ "batch_no",
+ "section_break_13",
+ "actual_qty",
+ "projected_qty",
+ "column_break_16",
+ "uom",
+ "page_break",
+ "prevdoc_doctype",
+ "parent_detail_docname"
+ ],
"fields": [
{
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "parent_item",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Parent Item",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "parent_item",
- "oldfieldtype": "Link",
- "options": "Item",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "fieldname": "parent_item",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Parent Item",
+ "oldfieldname": "parent_item",
+ "oldfieldtype": "Link",
+ "options": "Item",
+ "read_only": 1
+ },
{
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "item_code",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 1,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Item Code",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "item_code",
- "oldfieldtype": "Link",
- "options": "Item",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "fieldname": "item_code",
+ "fieldtype": "Link",
+ "in_global_search": 1,
+ "in_list_view": 1,
+ "label": "Item Code",
+ "oldfieldname": "item_code",
+ "oldfieldtype": "Link",
+ "options": "Item",
+ "read_only": 1
+ },
{
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "item_name",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Item Name",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "item_name",
- "oldfieldtype": "Data",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "fieldname": "item_name",
+ "fieldtype": "Data",
+ "label": "Item Name",
+ "oldfieldname": "item_name",
+ "oldfieldtype": "Data",
+ "read_only": 1
+ },
{
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_5",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 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
- },
+ "fieldname": "column_break_5",
+ "fieldtype": "Column Break"
+ },
{
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "description",
- "fieldtype": "Text Editor",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Description",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "description",
- "oldfieldtype": "Text",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "print_width": "300px",
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0,
+ "fieldname": "description",
+ "fieldtype": "Text Editor",
+ "in_list_view": 1,
+ "label": "Description",
+ "oldfieldname": "description",
+ "oldfieldtype": "Text",
+ "print_width": "300px",
"width": "300px"
- },
+ },
{
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "section_break_6",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 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
- },
+ "fieldname": "section_break_6",
+ "fieldtype": "Section Break"
+ },
{
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "warehouse",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "From Warehouse",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "warehouse",
- "oldfieldtype": "Link",
- "options": "Warehouse",
- "permlevel": 0,
- "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
- },
+ "fieldname": "warehouse",
+ "fieldtype": "Link",
+ "label": "From Warehouse",
+ "oldfieldname": "warehouse",
+ "oldfieldtype": "Link",
+ "options": "Warehouse"
+ },
{
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "target_warehouse",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "To Warehouse (Optional)",
- "length": 0,
- "no_copy": 0,
- "options": "Warehouse",
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "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
- },
+ "fieldname": "target_warehouse",
+ "fieldtype": "Link",
+ "label": "To Warehouse (Optional)",
+ "options": "Warehouse",
+ "print_hide": 1
+ },
{
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_9",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 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
- },
+ "fieldname": "column_break_9",
+ "fieldtype": "Column Break"
+ },
{
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "qty",
- "fieldtype": "Float",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Qty",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "qty",
- "oldfieldtype": "Currency",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "fieldname": "qty",
+ "fieldtype": "Float",
+ "in_list_view": 1,
+ "label": "Qty",
+ "oldfieldname": "qty",
+ "oldfieldtype": "Currency",
+ "read_only": 1
+ },
{
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "section_break_9",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 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
- },
+ "fieldname": "section_break_9",
+ "fieldtype": "Section Break"
+ },
{
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "serial_no",
- "fieldtype": "Text",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Serial No",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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
- },
+ "fieldname": "serial_no",
+ "fieldtype": "Text",
+ "label": "Serial No"
+ },
{
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_11",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 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
- },
+ "fieldname": "column_break_11",
+ "fieldtype": "Column Break"
+ },
{
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "batch_no",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Batch No",
- "length": 0,
- "no_copy": 0,
- "options": "Batch",
- "permlevel": 0,
- "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
- },
+ "fieldname": "batch_no",
+ "fieldtype": "Link",
+ "label": "Batch No",
+ "options": "Batch"
+ },
{
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "section_break_13",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 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
- },
+ "fieldname": "section_break_13",
+ "fieldtype": "Section Break"
+ },
{
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "actual_qty",
- "fieldtype": "Float",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Actual Qty",
- "length": 0,
- "no_copy": 1,
- "oldfieldname": "actual_qty",
- "oldfieldtype": "Currency",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "allow_on_submit": 1,
+ "fieldname": "actual_qty",
+ "fieldtype": "Float",
+ "label": "Actual Qty",
+ "no_copy": 1,
+ "oldfieldname": "actual_qty",
+ "oldfieldtype": "Currency",
+ "read_only": 1
+ },
{
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "projected_qty",
- "fieldtype": "Float",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Projected Qty",
- "length": 0,
- "no_copy": 1,
- "oldfieldname": "projected_qty",
- "oldfieldtype": "Currency",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "allow_on_submit": 1,
+ "fieldname": "projected_qty",
+ "fieldtype": "Float",
+ "label": "Projected Qty",
+ "no_copy": 1,
+ "oldfieldname": "projected_qty",
+ "oldfieldtype": "Currency",
+ "read_only": 1
+ },
{
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_16",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 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
- },
+ "fieldname": "column_break_16",
+ "fieldtype": "Column Break"
+ },
{
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "uom",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "UOM",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "uom",
- "oldfieldtype": "Link",
- "options": "UOM",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "fieldname": "uom",
+ "fieldtype": "Link",
+ "label": "UOM",
+ "oldfieldname": "uom",
+ "oldfieldtype": "Link",
+ "options": "UOM",
+ "read_only": 1
+ },
{
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "page_break",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Page Break",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "page_break",
- "oldfieldtype": "Check",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "allow_on_submit": 1,
+ "default": "0",
+ "fieldname": "page_break",
+ "fieldtype": "Check",
+ "label": "Page Break",
+ "oldfieldname": "page_break",
+ "oldfieldtype": "Check",
+ "read_only": 1
+ },
{
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "prevdoc_doctype",
- "fieldtype": "Data",
- "hidden": 1,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Prevdoc DocType",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "prevdoc_doctype",
- "oldfieldtype": "Data",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "fieldname": "prevdoc_doctype",
+ "fieldtype": "Data",
+ "hidden": 1,
+ "label": "Prevdoc DocType",
+ "oldfieldname": "prevdoc_doctype",
+ "oldfieldtype": "Data",
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "parent_detail_docname",
- "fieldtype": "Data",
- "hidden": 1,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Parent Detail docname",
- "length": 0,
- "no_copy": 1,
- "oldfieldname": "parent_detail_docname",
- "oldfieldtype": "Data",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
+ "fieldname": "parent_detail_docname",
+ "fieldtype": "Data",
+ "hidden": 1,
+ "label": "Parent Detail docname",
+ "no_copy": 1,
+ "oldfieldname": "parent_detail_docname",
+ "oldfieldtype": "Data",
+ "print_hide": 1,
+ "read_only": 1
}
- ],
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 1,
- "image_view": 0,
- "in_create": 0,
-
- "is_submittable": 0,
- "issingle": 0,
- "istable": 1,
- "max_attachments": 0,
- "modified": "2017-02-20 13:27:37.569945",
- "modified_by": "Administrator",
- "module": "Stock",
- "name": "Packed Item",
- "owner": "Administrator",
- "permissions": [],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
- "track_changes": 1,
- "track_seen": 0
-}
\ No newline at end of file
+ ],
+ "idx": 1,
+ "istable": 1,
+ "modified": "2019-08-27 18:17:37.167512",
+ "modified_by": "Administrator",
+ "module": "Stock",
+ "name": "Packed Item",
+ "owner": "Administrator",
+ "permissions": [],
+ "track_changes": 1
+}
diff --git a/erpnext/stock/doctype/packed_item/packed_item.py b/erpnext/stock/doctype/packed_item/packed_item.py
index cf72527205..2fd651612c 100644
--- a/erpnext/stock/doctype/packed_item/packed_item.py
+++ b/erpnext/stock/doctype/packed_item/packed_item.py
@@ -30,14 +30,14 @@ def get_bin_qty(item, warehouse):
where item_code = %s and warehouse = %s""", (item, warehouse), as_dict = 1)
return det and det[0] or frappe._dict()
-def update_packing_list_item(doc, packing_item_code, qty, main_item_row, description):
+def update_packing_list_item(doc, packing_item_code, qty, main_item_row, description):
item = get_packing_item_details(packing_item_code, doc.company)
# check if exists
exists = 0
for d in doc.get("packed_items"):
if d.parent_item == main_item_row.item_code and d.item_code == packing_item_code and\
- d.parent_detail_docname == main_item_row.name and d.description == description:
+ d.parent_detail_docname == main_item_row.name:
pi, exists = d, 1
break
@@ -48,10 +48,10 @@ def update_packing_list_item(doc, packing_item_code, qty, main_item_row, descrip
pi.item_code = packing_item_code
pi.item_name = item.item_name
pi.parent_detail_docname = main_item_row.name
- pi.description = item.description
pi.uom = item.stock_uom
pi.qty = flt(qty)
- pi.description = description
+ if description and not pi.description:
+ pi.description = description
if not pi.warehouse:
pi.warehouse = (main_item_row.warehouse if ((doc.get('is_pos')
or not item.default_warehouse) and main_item_row.warehouse) else item.default_warehouse)
@@ -112,4 +112,4 @@ def get_items_from_product_bundle(args):
return items
def on_doctype_update():
- frappe.db.add_index("Packed Item", ["item_code", "warehouse"])
\ No newline at end of file
+ frappe.db.add_index("Packed Item", ["item_code", "warehouse"])
From fb7c7b53ba00c3ee9b1aff720a2f3e052aa42538 Mon Sep 17 00:00:00 2001
From: Nabin Hait
Date: Mon, 9 Sep 2019 12:08:50 +0530
Subject: [PATCH 448/484] feat: Added input field for max carry forwarded
leaves
---
.../leave_allocation/leave_allocation.py | 35 +-
.../leave_allocation/test_leave_allocation.py | 27 +-
.../hr/doctype/leave_period/leave_period.py | 1 -
erpnext/hr/doctype/leave_type/leave_type.json | 713 ++----------------
.../doctype/stock_entry/stock_entry.json | 3 +-
5 files changed, 109 insertions(+), 670 deletions(-)
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.py b/erpnext/hr/doctype/leave_allocation/leave_allocation.py
index 296a52c2c7..73bf01759e 100755
--- a/erpnext/hr/doctype/leave_allocation/leave_allocation.py
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.py
@@ -34,10 +34,11 @@ class LeaveAllocation(Document):
if max_leaves_allowed > 0:
leave_allocated = 0
if leave_period:
- leave_allocated = get_leave_allocation_for_period(self.employee, self.leave_type, leave_period[0].from_date, leave_period[0].to_date)
+ leave_allocated = get_leave_allocation_for_period(self.employee, self.leave_type,
+ leave_period[0].from_date, leave_period[0].to_date)
leave_allocated += self.new_leaves_allocated
if leave_allocated > max_leaves_allowed:
- frappe.throw(_("Total allocated leaves are more days than maximum allocation of {0} leave type for employee {1} in the period")\
+ frappe.throw(_("Total allocated leaves are more days than maximum allocation of {0} leave type for employee {1} in the period")
.format(self.leave_type, self.employee))
def on_submit(self):
@@ -96,27 +97,31 @@ class LeaveAllocation(Document):
self.total_leaves_allocated = flt(self.unused_leaves) + flt(self.new_leaves_allocated)
+ self.carry_forward_based_on_max_allowed_leaves()
+
if self.carry_forward:
- self.maintain_carry_forwarded_leaves()
self.set_carry_forwarded_leaves_in_previous_allocation()
- if not self.total_leaves_allocated and not frappe.db.get_value("Leave Type", self.leave_type, "is_earned_leave") and not frappe.db.get_value("Leave Type", self.leave_type, "is_compensatory"):
- frappe.throw(_("Total leaves allocated is mandatory for Leave Type {0}").format(self.leave_type))
+ if not self.total_leaves_allocated \
+ and not frappe.db.get_value("Leave Type", self.leave_type, "is_earned_leave") \
+ and not frappe.db.get_value("Leave Type", self.leave_type, "is_compensatory"):
+ frappe.throw(_("Total leaves allocated is mandatory for Leave Type {0}")
+ .format(self.leave_type))
- def maintain_carry_forwarded_leaves(self):
- ''' Reduce the carry forwarded leaves to be within the maximum allowed leaves '''
-
+ def carry_forward_based_on_max_allowed_leaves(self):
max_leaves_allowed = frappe.db.get_value("Leave Type", self.leave_type, "max_leaves_allowed")
- if self.new_leaves_allocated <= max_leaves_allowed <= self.total_leaves_allocated:
- self.unused_leaves = max_leaves_allowed - flt(self.new_leaves_allocated)
+ if max_leaves_allowed and self.total_leaves_allocated > flt(max_leaves_allowed):
self.total_leaves_allocated = flt(max_leaves_allowed)
+ self.unused_leaves = max_leaves_allowed - flt(self.new_leaves_allocated)
def set_carry_forwarded_leaves_in_previous_allocation(self, on_cancel=False):
''' Set carry forwarded leaves in previous allocation '''
previous_allocation = get_previous_allocation(self.from_date, self.leave_type, self.employee)
if on_cancel:
self.unused_leaves = 0.0
- frappe.db.set_value("Leave Allocation", previous_allocation.name, 'carry_forwarded_leaves_count', self.unused_leaves)
+ if previous_allocation:
+ frappe.db.set_value("Leave Allocation", previous_allocation.name,
+ 'carry_forwarded_leaves_count', self.unused_leaves)
def validate_total_leaves_allocated(self):
# Adding a day to include To Date in the difference
@@ -186,7 +191,13 @@ def get_carry_forwarded_leaves(employee, leave_type, date, carry_forward=None):
previous_allocation = get_previous_allocation(date, leave_type, employee)
if carry_forward and previous_allocation:
validate_carry_forward(leave_type)
- unused_leaves = get_unused_leaves(employee, leave_type, previous_allocation.from_date, previous_allocation.to_date)
+ unused_leaves = get_unused_leaves(employee, leave_type,
+ previous_allocation.from_date, previous_allocation.to_date)
+ if unused_leaves:
+ max_carry_forwarded_leaves = frappe.db.get_value("Leave Type",
+ leave_type, "maximum_carry_forwarded_leaves")
+ if max_carry_forwarded_leaves and unused_leaves > flt(max_carry_forwarded_leaves):
+ unused_leaves = flt(max_carry_forwarded_leaves)
return unused_leaves
diff --git a/erpnext/hr/doctype/leave_allocation/test_leave_allocation.py b/erpnext/hr/doctype/leave_allocation/test_leave_allocation.py
index bdba8c9f8f..26f077a649 100644
--- a/erpnext/hr/doctype/leave_allocation/test_leave_allocation.py
+++ b/erpnext/hr/doctype/leave_allocation/test_leave_allocation.py
@@ -73,9 +73,11 @@ class TestLeaveAllocation(unittest.TestCase):
frappe.db.sql("delete from `tabLeave Allocation`")
frappe.db.sql("delete from `tabLeave Ledger Entry`")
leave_type = create_leave_type(leave_type_name="_Test_CF_leave", is_carry_forward=1)
- leave_type.submit()
+ leave_type.maximum_carry_forwarded_leaves = 10
+ leave_type.max_leaves_allowed = 30
+ leave_type.save()
- # initial leave allocation
+ # initial leave allocation = 15
leave_allocation = create_leave_allocation(
leave_type="_Test_CF_leave",
from_date=add_months(nowdate(), -12),
@@ -83,13 +85,26 @@ class TestLeaveAllocation(unittest.TestCase):
carry_forward=0)
leave_allocation.submit()
- # leave allocation with carry forward from previous allocation
+ # carry forwarded leaves considering maximum_carry_forwarded_leaves
+ # new_leaves = 15, carry_forwarded = 10
leave_allocation_1 = create_leave_allocation(
leave_type="_Test_CF_leave",
carry_forward=1)
leave_allocation_1.submit()
- self.assertEquals(leave_allocation.total_leaves_allocated, leave_allocation_1.unused_leaves)
+ self.assertEquals(leave_allocation_1.unused_leaves, 10)
+
+ leave_allocation_1.cancel()
+
+ # carry forwarded leaves considering max_leave_allowed
+ # max_leave_allowed = 30, new_leaves = 25, carry_forwarded = 5
+ leave_allocation_2 = create_leave_allocation(
+ leave_type="_Test_CF_leave",
+ carry_forward=1,
+ new_leaves_allocated=25)
+ leave_allocation_2.submit()
+
+ self.assertEquals(leave_allocation_2.unused_leaves, 5)
def test_carry_forward_leaves_expiry(self):
frappe.db.sql("delete from `tabLeave Allocation`")
@@ -98,7 +113,7 @@ class TestLeaveAllocation(unittest.TestCase):
leave_type_name="_Test_CF_leave_expiry",
is_carry_forward=1,
expire_carry_forwarded_leaves_after_days=90)
- leave_type.submit()
+ leave_type.save()
# initial leave allocation
leave_allocation = create_leave_allocation(
@@ -156,7 +171,7 @@ def create_leave_allocation(**args):
"employee_name": args.employee_name or employee.employee_name,
"leave_type": args.leave_type or "_Test Leave Type",
"from_date": args.from_date or nowdate(),
- "new_leaves_allocated": args.new_leaves_created or 15,
+ "new_leaves_allocated": args.new_leaves_allocated or 15,
"carry_forward": args.carry_forward or 0,
"to_date": args.to_date or add_months(nowdate(), 12)
})
diff --git a/erpnext/hr/doctype/leave_period/leave_period.py b/erpnext/hr/doctype/leave_period/leave_period.py
index a8566c4ffb..0973ac7198 100644
--- a/erpnext/hr/doctype/leave_period/leave_period.py
+++ b/erpnext/hr/doctype/leave_period/leave_period.py
@@ -8,7 +8,6 @@ from frappe import _
from frappe.utils import getdate, cstr, add_days, date_diff, getdate, ceil
from frappe.model.document import Document
from erpnext.hr.utils import validate_overlap, get_employee_leave_policy
-from erpnext.hr.doctype.leave_allocation.leave_allocation import get_carry_forwarded_leaves
from frappe.utils.background_jobs import enqueue
from six import iteritems
diff --git a/erpnext/hr/doctype/leave_type/leave_type.json b/erpnext/hr/doctype/leave_type/leave_type.json
index 2f15e3b3c1..550d536c8d 100644
--- a/erpnext/hr/doctype/leave_type/leave_type.json
+++ b/erpnext/hr/doctype/leave_type/leave_type.json
@@ -1,801 +1,214 @@
{
- "allow_copy": 0,
- "allow_events_in_timeline": 0,
- "allow_guest_to_view": 0,
"allow_import": 1,
"allow_rename": 1,
"autoname": "field:leave_type_name",
- "beta": 0,
"creation": "2013-02-21 09:55:58",
- "custom": 0,
- "docstatus": 0,
"doctype": "DocType",
"document_type": "Setup",
- "editable_grid": 0,
+ "engine": "InnoDB",
+ "field_order": [
+ "leave_type_name",
+ "max_leaves_allowed",
+ "applicable_after",
+ "max_continuous_days_allowed",
+ "column_break_3",
+ "is_carry_forward",
+ "is_lwp",
+ "is_optional_leave",
+ "allow_negative",
+ "include_holiday",
+ "is_compensatory",
+ "carry_forward_section",
+ "maximum_carry_forwarded_leaves",
+ "expire_carry_forwarded_leaves_after_days",
+ "encashment",
+ "allow_encashment",
+ "encashment_threshold_days",
+ "earning_component",
+ "earned_leave",
+ "is_earned_leave",
+ "earned_leave_frequency",
+ "rounding"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "leave_type_name",
"fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
"in_list_view": 1,
- "in_standard_filter": 0,
"label": "Leave Type Name",
- "length": 0,
- "no_copy": 0,
"oldfieldname": "leave_type_name",
"oldfieldtype": "Data",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
"reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
"unique": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
- "fetch_if_empty": 0,
"fieldname": "max_leaves_allowed",
"fieldtype": "Int",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Max Leaves Allowed",
- "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,
- "translatable": 0,
- "unique": 0
+ "label": "Max Leaves Allowed"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "applicable_after",
"fieldtype": "Int",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Applicable After (Working Days)",
- "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,
- "translatable": 0,
- "unique": 0
+ "label": "Applicable After (Working Days)"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "max_continuous_days_allowed",
"fieldtype": "Int",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
"in_list_view": 1,
- "in_standard_filter": 0,
"label": "Maximum Continuous Days Applicable",
- "length": 0,
- "no_copy": 0,
"oldfieldname": "max_days_allowed",
- "oldfieldtype": "Data",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
+ "oldfieldtype": "Data"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "column_break_3",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 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,
- "translatable": 0,
- "unique": 0
+ "fieldtype": "Column Break"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
+ "default": "0",
"fieldname": "is_carry_forward",
"fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
"in_list_view": 1,
- "in_standard_filter": 0,
"label": "Is Carry Forward",
- "length": 0,
- "no_copy": 0,
"oldfieldname": "is_carry_forward",
- "oldfieldtype": "Check",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
+ "oldfieldtype": "Check"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
- "fetch_if_empty": 0,
+ "default": "0",
"fieldname": "is_lwp",
"fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Is Leave Without Pay",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
+ "label": "Is Leave Without Pay"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
+ "default": "0",
"fieldname": "is_optional_leave",
"fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Is Optional Leave",
- "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,
- "translatable": 0,
- "unique": 0
+ "label": "Is Optional Leave"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
+ "default": "0",
"fieldname": "allow_negative",
"fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Allow Negative Balance",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
+ "label": "Allow Negative Balance"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
+ "default": "0",
"fieldname": "include_holiday",
"fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Include holidays within leaves as leaves",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
+ "label": "Include holidays within leaves as leaves"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
+ "default": "0",
"fieldname": "is_compensatory",
"fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Is Compensatory",
- "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,
- "translatable": 0,
- "unique": 0
+ "label": "Is Compensatory"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
"collapsible": 1,
- "columns": 0,
"depends_on": "eval: doc.is_carry_forward == 1",
- "fetch_if_empty": 0,
"fieldname": "carry_forward_section",
"fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Carry Forward",
- "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,
- "translatable": 0,
- "unique": 0
+ "label": "Carry Forward"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
"description": "Calculated in days",
- "fetch_if_empty": 0,
"fieldname": "expire_carry_forwarded_leaves_after_days",
"fieldtype": "Int",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Expire Carry Forwarded Leaves (Days)",
- "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,
- "translatable": 0,
- "unique": 0
+ "label": "Expire Carry Forwarded Leaves (Days)"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
"collapsible": 1,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "encashment",
"fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Encashment",
- "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,
- "translatable": 0,
- "unique": 0
+ "label": "Encashment"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
+ "default": "0",
"fieldname": "allow_encashment",
"fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Allow Encashment",
- "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,
- "translatable": 0,
- "unique": 0
+ "label": "Allow Encashment"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"depends_on": "allow_encashment",
- "fetch_if_empty": 0,
"fieldname": "encashment_threshold_days",
"fieldtype": "Int",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Encashment Threshold Days",
- "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,
- "translatable": 0,
- "unique": 0
+ "label": "Encashment Threshold Days"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"depends_on": "allow_encashment",
- "fetch_if_empty": 0,
"fieldname": "earning_component",
"fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Earning Component",
- "length": 0,
- "no_copy": 0,
- "options": "Salary Component",
- "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,
- "translatable": 0,
- "unique": 0
+ "options": "Salary Component"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
"collapsible": 1,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "earned_leave",
"fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Earned Leave",
- "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,
- "translatable": 0,
- "unique": 0
+ "label": "Earned Leave"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
+ "default": "0",
"fieldname": "is_earned_leave",
"fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Is Earned Leave",
- "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,
- "translatable": 0,
- "unique": 0
+ "label": "Is Earned Leave"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"depends_on": "is_earned_leave",
- "fetch_if_empty": 0,
"fieldname": "earned_leave_frequency",
"fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Earned Leave Frequency",
- "length": 0,
- "no_copy": 0,
- "options": "Monthly\nQuarterly\nHalf-Yearly\nYearly",
- "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,
- "translatable": 0,
- "unique": 0
+ "options": "Monthly\nQuarterly\nHalf-Yearly\nYearly"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"default": "0.5",
"depends_on": "is_earned_leave",
- "fetch_if_empty": 0,
"fieldname": "rounding",
"fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Rounding",
- "length": 0,
- "no_copy": 0,
- "options": "0.5\n1.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,
- "translatable": 0,
- "unique": 0
+ "options": "0.5\n1.0"
+ },
+ {
+ "depends_on": "is_carry_forward",
+ "fieldname": "maximum_carry_forwarded_leaves",
+ "fieldtype": "Float",
+ "label": "Maximum Carry Forwarded Leaves"
}
],
- "has_web_view": 0,
- "hide_toolbar": 0,
"icon": "fa fa-flag",
"idx": 1,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2019-08-02 15:38:39.334283",
+ "modified": "2019-09-06 18:48:48.946074",
"modified_by": "Administrator",
"module": "HR",
"name": "Leave Type",
"owner": "Administrator",
"permissions": [
{
- "amend": 0,
- "cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "HR User",
- "set_user_permissions": 0,
"share": 1,
- "submit": 0,
"write": 1
},
{
- "amend": 0,
- "cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "HR Manager",
- "set_user_permissions": 0,
"share": 1,
- "submit": 0,
"write": 1
},
{
- "amend": 0,
- "cancel": 0,
- "create": 0,
- "delete": 0,
- "email": 0,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 0,
"read": 1,
- "report": 0,
- "role": "Employee",
- "set_user_permissions": 0,
- "share": 0,
- "submit": 0,
- "write": 0
+ "role": "Employee"
}
],
- "quick_entry": 0,
- "read_only": 0,
- "show_name_in_global_search": 0,
- "track_changes": 0,
- "track_seen": 0,
- "track_views": 0
+ "sort_field": "modified",
+ "sort_order": "DESC"
}
\ No newline at end of file
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.json b/erpnext/stock/doctype/stock_entry/stock_entry.json
index f9e6d29104..7bcefa03e4 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.json
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.json
@@ -355,6 +355,7 @@
"label": "Scan Barcode"
},
{
+ "allow_bulk_edit": 1,
"fieldname": "items",
"fieldtype": "Table",
"label": "Items",
@@ -626,7 +627,7 @@
"icon": "fa fa-file-text",
"idx": 1,
"is_submittable": 1,
- "modified": "2019-08-22 17:11:42.074154",
+ "modified": "2019-09-09 11:40:05.762003",
"modified_by": "Administrator",
"module": "Stock",
"name": "Stock Entry",
From 5f59c2ae75df90c92567a7c47c169b643b678cf3 Mon Sep 17 00:00:00 2001
From: Shivam Mishra
Date: Mon, 9 Sep 2019 13:20:53 +0530
Subject: [PATCH 449/484] fix: reload account timeline before creating
dashboards (#18934)
* fix: sync account balance timeline.json before running patch
* fix: reload account timeline before creating dashboards
---
.../setup/setup_wizard/operations/install_fixtures.py | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/erpnext/setup/setup_wizard/operations/install_fixtures.py b/erpnext/setup/setup_wizard/operations/install_fixtures.py
index 7123021d1e..6dbb89062e 100644
--- a/erpnext/setup/setup_wizard/operations/install_fixtures.py
+++ b/erpnext/setup/setup_wizard/operations/install_fixtures.py
@@ -502,8 +502,17 @@ def install_defaults(args=None):
def add_dashboards():
from erpnext.setup.setup_wizard.data.dashboard_charts import get_default_dashboards
+ from frappe.modules.import_file import import_file_by_path
+
dashboard_data = get_default_dashboards()
+ # create account balance timeline before creating dashbaord charts
+ doctype = "dashboard_chart_source"
+ docname = "account_balance_timeline"
+ folder = os.path.dirname(frappe.get_module("erpnext.accounts").__file__)
+ doc_path = os.path.join(folder, doctype, docname, docname) + ".json"
+ import_file_by_path(doc_path, force=0, for_sync=True)
+
make_records(dashboard_data["Charts"])
make_records(dashboard_data["Dashboards"])
From f43825e4dd1ccde0314a9f56363925c74ae3addd Mon Sep 17 00:00:00 2001
From: Suraj Shetty <13928957+surajshetty3416@users.noreply.github.com>
Date: Mon, 9 Sep 2019 13:23:01 +0530
Subject: [PATCH 450/484] fix: convert dict to list for iteration (#18963)
---
.../doctype/amazon_mws_settings/amazon_mws_api.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/erpnext_integrations/doctype/amazon_mws_settings/amazon_mws_api.py b/erpnext/erpnext_integrations/doctype/amazon_mws_settings/amazon_mws_api.py
index fd364e87fb..cc4ccc5f4d 100755
--- a/erpnext/erpnext_integrations/doctype/amazon_mws_settings/amazon_mws_api.py
+++ b/erpnext/erpnext_integrations/doctype/amazon_mws_settings/amazon_mws_api.py
@@ -71,7 +71,7 @@ def remove_empty(d):
Helper function that removes all keys from a dictionary (d),
that have an empty value.
"""
- for key in d.keys():
+ for key in list(d):
if not d[key]:
del d[key]
return d
From 632fc6af79e3ddb47c8bfab92b2415f35cb4284e Mon Sep 17 00:00:00 2001
From: Nabin Hait
Date: Mon, 9 Sep 2019 13:32:18 +0530
Subject: [PATCH 451/484] feat: Added input field for max carry forwarded
leaves
---
erpnext/hr/doctype/leave_allocation/leave_allocation.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.py b/erpnext/hr/doctype/leave_allocation/leave_allocation.py
index 73bf01759e..874ae7a1bc 100755
--- a/erpnext/hr/doctype/leave_allocation/leave_allocation.py
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.py
@@ -97,7 +97,7 @@ class LeaveAllocation(Document):
self.total_leaves_allocated = flt(self.unused_leaves) + flt(self.new_leaves_allocated)
- self.carry_forward_based_on_max_allowed_leaves()
+ self.limit_carry_forward_based_on_max_allowed_leaves()
if self.carry_forward:
self.set_carry_forwarded_leaves_in_previous_allocation()
@@ -108,7 +108,7 @@ class LeaveAllocation(Document):
frappe.throw(_("Total leaves allocated is mandatory for Leave Type {0}")
.format(self.leave_type))
- def carry_forward_based_on_max_allowed_leaves(self):
+ def limit_carry_forward_based_on_max_allowed_leaves(self):
max_leaves_allowed = frappe.db.get_value("Leave Type", self.leave_type, "max_leaves_allowed")
if max_leaves_allowed and self.total_leaves_allocated > flt(max_leaves_allowed):
self.total_leaves_allocated = flt(max_leaves_allowed)
From 32eccb8fb212f5ba77c2dfd9101621efa596e795 Mon Sep 17 00:00:00 2001
From: Faris Ansari
Date: Mon, 9 Sep 2019 14:29:01 +0530
Subject: [PATCH 452/484] fix: Rename duplicate label Image to Website Image
(#18912)
---
erpnext/stock/doctype/item/item.json | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/erpnext/stock/doctype/item/item.json b/erpnext/stock/doctype/item/item.json
index 383fb61f51..46efd4ee26 100644
--- a/erpnext/stock/doctype/item/item.json
+++ b/erpnext/stock/doctype/item/item.json
@@ -904,7 +904,7 @@
"description": "Item Image (if not slideshow)",
"fieldname": "website_image",
"fieldtype": "Attach",
- "label": "Image"
+ "label": "Website Image"
},
{
"fieldname": "thumbnail",
@@ -1040,7 +1040,7 @@
"idx": 2,
"image_field": "image",
"max_attachments": 1,
- "modified": "2019-07-12 12:18:13.977931",
+ "modified": "2019-09-03 18:34:13.977931",
"modified_by": "Administrator",
"module": "Stock",
"name": "Item",
From 89d3bc0b54d4b449458cd07bc71d6e5fbb43bdcf Mon Sep 17 00:00:00 2001
From: Anurag Mishra
Date: Mon, 9 Sep 2019 15:58:25 +0530
Subject: [PATCH 453/484] fix: sales invoice return print format overideing the
meta default print format
---
erpnext/accounts/doctype/sales_invoice/sales_invoice.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
index 74e9186e37..3c85210663 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
@@ -158,7 +158,7 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
cur_frm.meta._default_print_format = cur_frm.meta.default_print_format;
cur_frm.meta.default_print_format = cur_frm.pos_print_format;
}
- } else if(cur_frm.doc.is_return) {
+ } else if(cur_frm.doc.is_return && !cur_frm.meta.default_print_format) {
if(cur_frm.return_print_format) {
cur_frm.meta._default_print_format = cur_frm.meta.default_print_format;
cur_frm.meta.default_print_format = cur_frm.return_print_format;
From d312d11062879a3d7d2e0003236fd5b96c689c40 Mon Sep 17 00:00:00 2001
From: rohitwaghchaure
Date: Tue, 10 Sep 2019 10:47:36 +0530
Subject: [PATCH 454/484] fix: port from hotfix (#18974)
* fix: '>' not supported between instances of 'int' and 'str'
* fix: not able to save item because price list has disabled
---
erpnext/stock/doctype/item_price/item_price.py | 14 ++++++++++----
.../stock/doctype/packing_slip/packing_slip.json | 8 ++++----
erpnext/stock/doctype/packing_slip/packing_slip.py | 1 -
3 files changed, 14 insertions(+), 9 deletions(-)
diff --git a/erpnext/stock/doctype/item_price/item_price.py b/erpnext/stock/doctype/item_price/item_price.py
index 30675b54b3..4c496cb59a 100644
--- a/erpnext/stock/doctype/item_price/item_price.py
+++ b/erpnext/stock/doctype/item_price/item_price.py
@@ -32,10 +32,16 @@ class ItemPrice(Document):
def update_price_list_details(self):
if self.price_list:
- self.buying, self.selling, self.currency = \
- frappe.db.get_value("Price List",
- {"name": self.price_list, "enabled": 1},
- ["buying", "selling", "currency"])
+ price_list_details = frappe.db.get_value("Price List",
+ {"name": self.price_list, "enabled": 1},
+ ["buying", "selling", "currency"])
+
+ if not price_list_details:
+ link = frappe.utils.get_link_to_form('Price List', self.price_list)
+ frappe.throw("The price list {0} does not exists or disabled".
+ format(link))
+
+ self.buying, self.selling, self.currency = price_list_details
def update_item_details(self):
if self.item_code:
diff --git a/erpnext/stock/doctype/packing_slip/packing_slip.json b/erpnext/stock/doctype/packing_slip/packing_slip.json
index 0ed039a391..ec8d57c965 100644
--- a/erpnext/stock/doctype/packing_slip/packing_slip.json
+++ b/erpnext/stock/doctype/packing_slip/packing_slip.json
@@ -74,7 +74,7 @@
{
"description": "Identification of the package for the delivery (for print)",
"fieldname": "from_case_no",
- "fieldtype": "Data",
+ "fieldtype": "Int",
"in_list_view": 1,
"label": "From Package No.",
"no_copy": 1,
@@ -88,7 +88,7 @@
{
"description": "If more than one package of the same type (for print)",
"fieldname": "to_case_no",
- "fieldtype": "Data",
+ "fieldtype": "Int",
"in_list_view": 1,
"label": "To Package No.",
"no_copy": 1,
@@ -180,7 +180,7 @@
"icon": "fa fa-suitcase",
"idx": 1,
"is_submittable": 1,
- "modified": "2019-05-31 04:45:08.082862",
+ "modified": "2019-09-09 04:45:08.082862",
"modified_by": "Administrator",
"module": "Stock",
"name": "Packing Slip",
@@ -261,4 +261,4 @@
"show_name_in_global_search": 1,
"sort_field": "modified",
"sort_order": "DESC"
- }
\ No newline at end of file
+ }
diff --git a/erpnext/stock/doctype/packing_slip/packing_slip.py b/erpnext/stock/doctype/packing_slip/packing_slip.py
index 4139a19abf..7a5ae317c2 100644
--- a/erpnext/stock/doctype/packing_slip/packing_slip.py
+++ b/erpnext/stock/doctype/packing_slip/packing_slip.py
@@ -53,7 +53,6 @@ class PackingSlip(Document):
frappe.msgprint(_("'To Case No.' cannot be less than 'From Case No.'"),
raise_exception=1)
-
res = frappe.db.sql("""SELECT name FROM `tabPacking Slip`
WHERE delivery_note = %(delivery_note)s AND docstatus = 1 AND
((from_case_no BETWEEN %(from_case_no)s AND %(to_case_no)s)
From 1853a834536d4beb525f7ec9dfe692e365cfe7c7 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Tue, 10 Sep 2019 13:21:01 +0530
Subject: [PATCH 455/484] fix(packing-slip): add a descriptive message (#18981)
---
erpnext/stock/doctype/packing_slip/packing_slip.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/erpnext/stock/doctype/packing_slip/packing_slip.js b/erpnext/stock/doctype/packing_slip/packing_slip.js
index 9f6b9ff191..bd14e5f616 100644
--- a/erpnext/stock/doctype/packing_slip/packing_slip.js
+++ b/erpnext/stock/doctype/packing_slip/packing_slip.js
@@ -10,7 +10,7 @@ cur_frm.fields_dict['delivery_note'].get_query = function(doc, cdt, cdn) {
cur_frm.fields_dict['items'].grid.get_field('item_code').get_query = function(doc, cdt, cdn) {
if(!doc.delivery_note) {
- frappe.throw(__("Please Delivery Note first"))
+ frappe.throw(__("Please select a Delivery Note"));
} else {
return {
query: "erpnext.stock.doctype.packing_slip.packing_slip.item_details",
@@ -125,4 +125,4 @@ cur_frm.pformat.gross_weight_pkg= function(doc){
return '' + make_row('Gross Weight', doc.gross_weight_pkg) + '
'
}
-// TODO: validate gross weight field
\ No newline at end of file
+// TODO: validate gross weight field
From 0254217314f5fb24931d699366645142f8bc410a Mon Sep 17 00:00:00 2001
From: Suraj Shetty <13928957+surajshetty3416@users.noreply.github.com>
Date: Tue, 10 Sep 2019 14:07:05 +0530
Subject: [PATCH 456/484] fix: Make address fields mandatory (#18979)
---
erpnext/public/js/utils/customer_quick_entry.js | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/erpnext/public/js/utils/customer_quick_entry.js b/erpnext/public/js/utils/customer_quick_entry.js
index f454ba057b..ac9a7828cb 100644
--- a/erpnext/public/js/utils/customer_quick_entry.js
+++ b/erpnext/public/js/utils/customer_quick_entry.js
@@ -37,7 +37,8 @@ frappe.ui.form.CustomerQuickEntryForm = frappe.ui.form.QuickEntryForm.extend({
{
label: __("Address Line 1"),
fieldname: "address_line1",
- fieldtype: "Data"
+ fieldtype: "Data",
+ reqd: 1
},
{
label: __("Address Line 2"),
@@ -55,7 +56,8 @@ frappe.ui.form.CustomerQuickEntryForm = frappe.ui.form.QuickEntryForm.extend({
{
label: __("City"),
fieldname: "city",
- fieldtype: "Data"
+ fieldtype: "Data",
+ reqd: 1,
},
{
label: __("State"),
@@ -66,7 +68,8 @@ frappe.ui.form.CustomerQuickEntryForm = frappe.ui.form.QuickEntryForm.extend({
label: __("Country"),
fieldname: "country",
fieldtype: "Link",
- options: "Country"
+ options: "Country",
+ reqd: 1
},
{
label: __("Customer POS Id"),
From 88e8688a4bfd3eb3f067454dec0949224ef666f9 Mon Sep 17 00:00:00 2001
From: Nabin Hait
Date: Tue, 10 Sep 2019 14:07:45 +0530
Subject: [PATCH 457/484] fix: set raw material's batch based on main item's
batch only if RM has batch no (#18977)
---
erpnext/controllers/buying_controller.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py
index a7dc4c738e..084f84b1f9 100644
--- a/erpnext/controllers/buying_controller.py
+++ b/erpnext/controllers/buying_controller.py
@@ -337,7 +337,7 @@ class BuyingController(StockController):
if self.doctype in ["Purchase Receipt", "Purchase Invoice"]:
rm.consumed_qty = required_qty
rm.description = bom_item.description
- if item.batch_no and not rm.batch_no:
+ if item.batch_no and frappe.db.get_value("Item", rm.rm_item_code, "has_batch_no") and not rm.batch_no:
rm.batch_no = item.batch_no
# get raw materials rate
From e851346b4c0ed398fb4ff83f3512a743b8c9f056 Mon Sep 17 00:00:00 2001
From: Shivam Mishra
Date: Tue, 10 Sep 2019 14:08:31 +0530
Subject: [PATCH 458/484] fix: dont make dashboards if company is not set
(#18975)
* fix: dont make dashboardss if company is not set
* fix: function call
* Update dashboard_charts.py
---
.../setup/setup_wizard/data/dashboard_charts.py | 14 ++++++++++++--
.../setup_wizard/operations/install_fixtures.py | 5 +++++
2 files changed, 17 insertions(+), 2 deletions(-)
diff --git a/erpnext/setup/setup_wizard/data/dashboard_charts.py b/erpnext/setup/setup_wizard/data/dashboard_charts.py
index 41cfcb529e..bb8c1319bf 100644
--- a/erpnext/setup/setup_wizard/data/dashboard_charts.py
+++ b/erpnext/setup/setup_wizard/data/dashboard_charts.py
@@ -3,8 +3,18 @@ from frappe import _
import frappe
import json
+def get_company_for_dashboards():
+ company = frappe.defaults.get_defaults().company
+ if company:
+ return company
+ else:
+ company_list = frappe.get_list("Company")
+ if company_list:
+ return company_list[0].name
+ return None
+
def get_default_dashboards():
- company = frappe.get_doc("Company", frappe.defaults.get_defaults().company)
+ company = frappe.get_doc("Company", get_company_for_dashboards())
income_account = company.default_income_account or get_account("Income Account", company.name)
expense_account = company.default_expense_account or get_account("Expense Account", company.name)
bank_account = company.default_bank_account or get_account("Bank", company.name)
@@ -104,4 +114,4 @@ def get_default_dashboards():
def get_account(account_type, company):
accounts = frappe.get_list("Account", filters={"account_type": account_type, "company": company})
if accounts:
- return accounts[0].name
\ No newline at end of file
+ return accounts[0].name
diff --git a/erpnext/setup/setup_wizard/operations/install_fixtures.py b/erpnext/setup/setup_wizard/operations/install_fixtures.py
index 6dbb89062e..b65716536d 100644
--- a/erpnext/setup/setup_wizard/operations/install_fixtures.py
+++ b/erpnext/setup/setup_wizard/operations/install_fixtures.py
@@ -501,6 +501,11 @@ def install_defaults(args=None):
make_records(records)
def add_dashboards():
+ from erpnext.setup.setup_wizard.data.dashboard_charts import get_company_for_dashboards
+
+ if not get_company_for_dashboards():
+ return
+
from erpnext.setup.setup_wizard.data.dashboard_charts import get_default_dashboards
from frappe.modules.import_file import import_file_by_path
From bcda12f4bb90990d50ad84062535f78f73cf91b8 Mon Sep 17 00:00:00 2001
From: Sammish Thundiyil
Date: Tue, 10 Sep 2019 11:41:02 +0300
Subject: [PATCH 459/484] modified:
erpnext/accounts/doctype/mode_of_payment/mode_of_payment.json (#18829)
---
.../mode_of_payment/mode_of_payment.json | 221 +++++-------------
1 file changed, 62 insertions(+), 159 deletions(-)
diff --git a/erpnext/accounts/doctype/mode_of_payment/mode_of_payment.json b/erpnext/accounts/doctype/mode_of_payment/mode_of_payment.json
index 9609e3d08b..f3df1f0bc9 100644
--- a/erpnext/accounts/doctype/mode_of_payment/mode_of_payment.json
+++ b/erpnext/accounts/doctype/mode_of_payment/mode_of_payment.json
@@ -1,171 +1,74 @@
{
- "allow_copy": 0,
- "allow_import": 1,
- "allow_rename": 1,
- "autoname": "field:mode_of_payment",
- "beta": 0,
- "creation": "2012-12-04 17:49:20",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "Setup",
- "editable_grid": 0,
- "engine": "InnoDB",
+ "allow_import": 1,
+ "allow_rename": 1,
+ "autoname": "field:mode_of_payment",
+ "creation": "2012-12-04 17:49:20",
+ "doctype": "DocType",
+ "document_type": "Setup",
+ "engine": "InnoDB",
+ "field_order": [
+ "mode_of_payment",
+ "enabled",
+ "type",
+ "accounts"
+ ],
"fields": [
{
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "mode_of_payment",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Mode of Payment",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "mode_of_payment",
- "oldfieldtype": "Data",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "fieldname": "mode_of_payment",
+ "fieldtype": "Data",
+ "in_list_view": 1,
+ "label": "Mode of Payment",
+ "oldfieldname": "mode_of_payment",
+ "oldfieldtype": "Data",
+ "reqd": 1,
+ "unique": 1
+ },
{
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "type",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 1,
- "label": "Type",
- "length": 0,
- "no_copy": 0,
- "options": "Cash\nBank\nGeneral",
- "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
- },
+ "fieldname": "type",
+ "fieldtype": "Select",
+ "in_standard_filter": 1,
+ "label": "Type",
+ "options": "Cash\nBank\nGeneral"
+ },
{
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "accounts",
- "fieldtype": "Table",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Accounts",
- "length": 0,
- "no_copy": 0,
- "options": "Mode of Payment Account",
- "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
+ "fieldname": "accounts",
+ "fieldtype": "Table",
+ "label": "Accounts",
+ "options": "Mode of Payment Account"
+ },
+ {
+ "default": "1",
+ "fieldname": "enabled",
+ "fieldtype": "Check",
+ "label": "Enabled"
}
- ],
- "hide_heading": 0,
- "hide_toolbar": 0,
- "icon": "fa fa-credit-card",
- "idx": 1,
- "image_view": 0,
- "in_create": 0,
-
- "is_submittable": 0,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2017-02-17 16:31:34.207683",
- "modified_by": "Administrator",
- "module": "Accounts",
- "name": "Mode of Payment",
- "owner": "harshada@webnotestech.com",
+ ],
+ "icon": "fa fa-credit-card",
+ "idx": 1,
+ "modified": "2019-08-14 14:58:42.079115",
+ "modified_by": "sammish.thundiyil@gmail.com",
+ "module": "Accounts",
+ "name": "Mode of Payment",
+ "owner": "harshada@webnotestech.com",
"permissions": [
{
- "amend": 0,
- "apply_user_permissions": 0,
- "cancel": 0,
- "create": 1,
- "delete": 0,
- "email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Accounts Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
+ "create": 1,
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Accounts Manager",
+ "share": 1,
"write": 1
- },
+ },
{
- "amend": 0,
- "apply_user_permissions": 0,
- "cancel": 0,
- "create": 0,
- "delete": 0,
- "email": 0,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 0,
- "read": 1,
- "report": 1,
- "role": "Accounts User",
- "set_user_permissions": 0,
- "share": 0,
- "submit": 0,
- "write": 0
+ "read": 1,
+ "report": 1,
+ "role": "Accounts User"
}
- ],
- "quick_entry": 1,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 1,
- "sort_order": "ASC",
- "track_changes": 0,
- "track_seen": 0
+ ],
+ "quick_entry": 1,
+ "show_name_in_global_search": 1,
+ "sort_field": "modified",
+ "sort_order": "ASC"
}
\ No newline at end of file
From a2fd1f22daf9805fe7cf967c5b241e4cfc37b752 Mon Sep 17 00:00:00 2001
From: Sahil Khan
Date: Tue, 10 Sep 2019 14:58:39 +0550
Subject: [PATCH 460/484] bumped to version 12.1.2
---
erpnext/__init__.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/__init__.py b/erpnext/__init__.py
index 106384ade0..cd1545c7e8 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__ = '12.1.1'
+__version__ = '12.1.2'
def get_default_company(user=None):
'''Get default company for user'''
From a035428d43e0bce3a8dce8a8ccaaf5ed6867c52f Mon Sep 17 00:00:00 2001
From: Nabin Hait
Date: Tue, 10 Sep 2019 14:50:55 +0530
Subject: [PATCH 461/484] fix: handling of key does not exists error
---
.../chart_of_accounts_importer/chart_of_accounts_importer.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/accounts/doctype/chart_of_accounts_importer/chart_of_accounts_importer.py b/erpnext/accounts/doctype/chart_of_accounts_importer/chart_of_accounts_importer.py
index 4683c7ae46..9bf5887b38 100644
--- a/erpnext/accounts/doctype/chart_of_accounts_importer/chart_of_accounts_importer.py
+++ b/erpnext/accounts/doctype/chart_of_accounts_importer/chart_of_accounts_importer.py
@@ -150,7 +150,7 @@ def validate_accounts(file_name):
accounts_dict = {}
for account in accounts:
accounts_dict.setdefault(account["account_name"], account)
- if account["parent_account"] and accounts_dict[account["parent_account"]]:
+ if account["parent_account"] and accounts_dict.get(account["parent_account"]):
accounts_dict[account["parent_account"]]["is_group"] = 1
message = validate_root(accounts_dict)
From 358a01a226b914658a2199a236002f2e80006122 Mon Sep 17 00:00:00 2001
From: rohitwaghchaure
Date: Tue, 10 Sep 2019 19:18:30 +0530
Subject: [PATCH 462/484] fix: Quotation Trends report not working for filter
group by customer (#18989)
---
erpnext/controllers/trends.py | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/erpnext/controllers/trends.py b/erpnext/controllers/trends.py
index 0404a1e6b0..da44325a9e 100644
--- a/erpnext/controllers/trends.py
+++ b/erpnext/controllers/trends.py
@@ -54,6 +54,9 @@ def get_data(filters, conditions):
if conditions.get('trans') in ['Sales Order', 'Purchase Order']:
cond += " and t1.status != 'Closed'"
+ if conditions.get('trans') == 'Quotation' and filters.get("group_by") == 'Customer':
+ cond += " and t1.quotation_to = 'Customer'"
+
year_start_date, year_end_date = frappe.db.get_value("Fiscal Year",
filters.get('fiscal_year'), ["year_start_date", "year_end_date"])
@@ -64,7 +67,7 @@ def get_data(filters, conditions):
if filters.get("group_by") == 'Item':
sel_col = 't2.item_code'
elif filters.get("group_by") == 'Customer':
- sel_col = 't1.customer'
+ sel_col = 't1.party_name' if conditions.get('trans') == 'Quotation' else 't1.customer'
elif filters.get("group_by") == 'Supplier':
sel_col = 't1.supplier'
@@ -225,7 +228,7 @@ def based_wise_columns_query(based_on, trans):
elif based_on == "Customer":
based_on_details["based_on_cols"] = ["Customer:Link/Customer:120", "Territory:Link/Territory:120"]
based_on_details["based_on_select"] = "t1.customer_name, t1.territory, "
- based_on_details["based_on_group_by"] = 't1.customer'
+ based_on_details["based_on_group_by"] = 't1.party_name' if trans == 'Quotation' else 't1.customer'
based_on_details["addl_tables"] = ''
elif based_on == "Customer Group":
From e919388ee69a7b1e23321ccfbf094f1a181039b5 Mon Sep 17 00:00:00 2001
From: Saurabh
Date: Wed, 11 Sep 2019 10:07:50 +0530
Subject: [PATCH 463/484] fix: do not cache value while creating item group, in
setup wizard it will raise link validation error (#18992)
---
erpnext/setup/doctype/item_group/item_group.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/setup/doctype/item_group/item_group.py b/erpnext/setup/doctype/item_group/item_group.py
index b309b504e0..5603f17a54 100644
--- a/erpnext/setup/doctype/item_group/item_group.py
+++ b/erpnext/setup/doctype/item_group/item_group.py
@@ -29,7 +29,7 @@ class ItemGroup(NestedSet, WebsiteGenerator):
super(ItemGroup, self).validate()
if not self.parent_item_group and not frappe.flags.in_test:
- if frappe.db.exists("Item Group", _('All Item Groups'), cache=True):
+ if frappe.db.exists("Item Group", _('All Item Groups')):
self.parent_item_group = _('All Item Groups')
self.make_route()
From bb736248a29151f736543c09889a1fa6d5894e09 Mon Sep 17 00:00:00 2001
From: rohitwaghchaure
Date: Wed, 11 Sep 2019 10:20:49 +0530
Subject: [PATCH 464/484] fix: incorrect qty calculation in the production plan
fopr the sub assembely work orders (#18970)
---
erpnext/manufacturing/doctype/bom/bom.py | 2 ++
.../doctype/production_plan/production_plan.py | 12 ++++++------
2 files changed, 8 insertions(+), 6 deletions(-)
diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py
index 22c2f694f5..8eb4c9c28c 100644
--- a/erpnext/manufacturing/doctype/bom/bom.py
+++ b/erpnext/manufacturing/doctype/bom/bom.py
@@ -716,6 +716,8 @@ def get_children(doctype, parent=None, is_root=False, **filters):
next(item for item in items if item.get('name')
== bom_item.get('item_code'))
)
+
+ bom_item.parent_bom_qty = bom_doc.quantity
bom_item.expandable = 0 if bom_item.value in ('', None) else 1
return bom_items
diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.py b/erpnext/manufacturing/doctype/production_plan/production_plan.py
index 048ce0d6ef..b51420ffdb 100644
--- a/erpnext/manufacturing/doctype/production_plan/production_plan.py
+++ b/erpnext/manufacturing/doctype/production_plan/production_plan.py
@@ -301,7 +301,6 @@ class ProductionPlan(Document):
wo_list.extend(work_orders)
frappe.flags.mute_messages = False
-
if wo_list:
wo_list = ["""%s """ % \
(p, p) for p in wo_list]
@@ -309,15 +308,16 @@ class ProductionPlan(Document):
else :
msgprint(_("No Work Orders created"))
+
def make_work_order_for_sub_assembly_items(self, item):
work_orders = []
bom_data = {}
- get_sub_assembly_items(item.get("bom_no"), bom_data)
+ get_sub_assembly_items(item.get("bom_no"), bom_data, item.get("qty"))
for key, data in bom_data.items():
data.update({
- 'qty': data.get("stock_qty") * item.get("qty"),
+ 'qty': data.get("stock_qty"),
'production_plan': self.name,
'company': self.company,
'fg_warehouse': item.get("fg_warehouse"),
@@ -708,7 +708,7 @@ def get_item_data(item_code):
"description": item_details.get("description")
}
-def get_sub_assembly_items(bom_no, bom_data):
+def get_sub_assembly_items(bom_no, bom_data, qty):
data = get_children('BOM', parent = bom_no)
for d in data:
if d.expandable:
@@ -725,6 +725,6 @@ def get_sub_assembly_items(bom_no, bom_data):
})
bom_item = bom_data.get(key)
- bom_item["stock_qty"] += d.stock_qty
+ bom_item["stock_qty"] += ((d.stock_qty * qty) / d.parent_bom_qty)
- get_sub_assembly_items(bom_item.get("bom_no"), bom_data)
+ get_sub_assembly_items(bom_item.get("bom_no"), bom_data, bom_item["stock_qty"])
From 7bcb24efbf922b6151bc2e3d11343ba8038c9acf Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Wed, 11 Sep 2019 10:49:33 +0530
Subject: [PATCH 465/484] fix(purchase-invoice): Update paid amount on creation
of debit note (#18830)
* fix(purchase-invoice): set paid amount for purchase return
* fix(purchase-invoice): remove payment schedule on creation of debit note
---
erpnext/controllers/accounts_controller.py | 31 ++++++++++---------
.../controllers/sales_and_purchase_return.py | 2 ++
.../public/js/controllers/taxes_and_totals.js | 6 ++++
3 files changed, 24 insertions(+), 15 deletions(-)
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index f6d4eee518..37548ea9b8 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -89,7 +89,7 @@ class AccountsController(TransactionBase):
self.validate_currency()
if self.doctype == 'Purchase Invoice':
- self.validate_paid_amount()
+ self.calculate_paid_amount()
if self.doctype in ['Purchase Invoice', 'Sales Invoice']:
pos_check_field = "is_pos" if self.doctype=="Sales Invoice" else "is_paid"
@@ -135,22 +135,23 @@ class AccountsController(TransactionBase):
else:
df.set("print_hide", 1)
- def validate_paid_amount(self):
+ def calculate_paid_amount(self):
if hasattr(self, "is_pos") or hasattr(self, "is_paid"):
is_paid = self.get("is_pos") or self.get("is_paid")
- if cint(is_paid) == 1:
- if flt(self.paid_amount) == 0 and flt(self.outstanding_amount) > 0:
- if self.cash_bank_account:
- self.paid_amount = flt(flt(self.outstanding_amount), self.precision("paid_amount"))
- self.base_paid_amount = flt(self.paid_amount * self.conversion_rate,
- self.precision("base_paid_amount"))
- else:
- # show message that the amount is not paid
- self.paid_amount = 0
- frappe.throw(
- _("Note: Payment Entry will not be created since 'Cash or Bank Account' was not specified"))
- else:
- frappe.db.set(self, 'paid_amount', 0)
+
+ if is_paid:
+ if not self.cash_bank_account:
+ # show message that the amount is not paid
+ frappe.throw(_("Note: Payment Entry will not be created since 'Cash or Bank Account' was not specified"))
+
+ if cint(self.is_return) and self.grand_total > self.paid_amount:
+ self.paid_amount = flt(flt(self.grand_total), self.precision("paid_amount"))
+
+ elif not flt(self.paid_amount) and flt(self.outstanding_amount) > 0:
+ self.paid_amount = flt(flt(self.outstanding_amount), self.precision("paid_amount"))
+
+ self.base_paid_amount = flt(self.paid_amount * self.conversion_rate,
+ self.precision("base_paid_amount"))
def set_missing_values(self, for_validate=False):
if frappe.flags.in_test:
diff --git a/erpnext/controllers/sales_and_purchase_return.py b/erpnext/controllers/sales_and_purchase_return.py
index b713958b1b..859529204b 100644
--- a/erpnext/controllers/sales_and_purchase_return.py
+++ b/erpnext/controllers/sales_and_purchase_return.py
@@ -246,6 +246,8 @@ def make_return_doc(doctype, source_name, target_doc=None):
elif doc.doctype == 'Purchase Invoice':
doc.paid_amount = -1 * source.paid_amount
doc.base_paid_amount = -1 * source.base_paid_amount
+ doc.payment_terms_template = ''
+ doc.payment_schedule = []
if doc.get("is_return") and hasattr(doc, "packed_items"):
for d in doc.get("packed_items"):
diff --git a/erpnext/public/js/controllers/taxes_and_totals.js b/erpnext/public/js/controllers/taxes_and_totals.js
index 7cf2181e42..2ece711040 100644
--- a/erpnext/public/js/controllers/taxes_and_totals.js
+++ b/erpnext/public/js/controllers/taxes_and_totals.js
@@ -44,6 +44,12 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
this.calculate_contribution();
}
+ // Update paid amount on return/debit note creation
+ if(this.frm.doc.doctype === "Purchase Invoice" && this.frm.doc.is_return
+ && (this.frm.doc.grand_total > this.frm.doc.paid_amount)) {
+ this.frm.doc.paid_amount = flt(this.frm.doc.grand_total, precision("grand_total"));
+ }
+
this.frm.refresh_fields();
},
From ff09b412f4bba0526585d1501a9a41d53ab50fc2 Mon Sep 17 00:00:00 2001
From: Nabin Hait
Date: Wed, 11 Sep 2019 12:43:27 +0530
Subject: [PATCH 466/484] feat: Allowed multiple payment requests against a
reference document (#18988)
---
.../payment_request/payment_request.py | 51 +++++++++++++++----
.../payment_request/test_payment_request.py | 26 ++++++++--
2 files changed, 63 insertions(+), 14 deletions(-)
diff --git a/erpnext/accounts/doctype/payment_request/payment_request.py b/erpnext/accounts/doctype/payment_request/payment_request.py
index 73758bea85..eda59abf04 100644
--- a/erpnext/accounts/doctype/payment_request/payment_request.py
+++ b/erpnext/accounts/doctype/payment_request/payment_request.py
@@ -20,7 +20,7 @@ class PaymentRequest(Document):
if self.get("__islocal"):
self.status = 'Draft'
self.validate_reference_document()
- self.validate_payment_request()
+ self.validate_payment_request_amount()
self.validate_currency()
self.validate_subscription_details()
@@ -28,10 +28,19 @@ class PaymentRequest(Document):
if not self.reference_doctype or not self.reference_name:
frappe.throw(_("To create a Payment Request reference document is required"))
- def validate_payment_request(self):
- if frappe.db.get_value("Payment Request", {"reference_name": self.reference_name,
- "name": ("!=", self.name), "status": ("not in", ["Initiated", "Paid"]), "docstatus": 1}, "name"):
- frappe.throw(_("Payment Request already exists {0}".format(self.reference_name)))
+ def validate_payment_request_amount(self):
+ existing_payment_request_amount = \
+ get_existing_payment_request_amount(self.reference_doctype, self.reference_name)
+
+ if existing_payment_request_amount:
+ ref_doc = frappe.get_doc(self.reference_doctype, self.reference_name)
+ if (hasattr(ref_doc, "order_type") \
+ and getattr(ref_doc, "order_type") != "Shopping Cart"):
+ ref_amount = get_amount(ref_doc)
+
+ if existing_payment_request_amount + flt(self.grand_total)> ref_amount:
+ frappe.throw(_("Total Payment Request amount cannot be greater than {0} amount"
+ .format(self.reference_doctype)))
def validate_currency(self):
ref_doc = frappe.get_doc(self.reference_doctype, self.reference_name)
@@ -271,7 +280,7 @@ def make_payment_request(**args):
args = frappe._dict(args)
ref_doc = frappe.get_doc(args.dt, args.dn)
- grand_total = get_amount(ref_doc, args.dt)
+ grand_total = get_amount(ref_doc)
if args.loyalty_points and args.dt == "Sales Order":
from erpnext.accounts.doctype.loyalty_program.loyalty_program import validate_loyalty_points
loyalty_amount = validate_loyalty_points(ref_doc, int(args.loyalty_points))
@@ -281,17 +290,25 @@ def make_payment_request(**args):
gateway_account = get_gateway_details(args) or frappe._dict()
- existing_payment_request = frappe.db.get_value("Payment Request",
- {"reference_doctype": args.dt, "reference_name": args.dn, "docstatus": ["!=", 2]})
-
bank_account = (get_party_bank_account(args.get('party_type'), args.get('party'))
if args.get('party_type') else '')
+ existing_payment_request = None
+ if args.order_type == "Shopping Cart":
+ existing_payment_request = frappe.db.get_value("Payment Request",
+ {"reference_doctype": args.dt, "reference_name": args.dn, "docstatus": ("!=", 2)})
+
if existing_payment_request:
frappe.db.set_value("Payment Request", existing_payment_request, "grand_total", grand_total, update_modified=False)
pr = frappe.get_doc("Payment Request", existing_payment_request)
-
else:
+ if args.order_type != "Shopping Cart":
+ existing_payment_request_amount = \
+ get_existing_payment_request_amount(args.dt, args.dn)
+
+ if existing_payment_request_amount:
+ grand_total -= existing_payment_request_amount
+
pr = frappe.new_doc("Payment Request")
pr.update({
"payment_gateway_account": gateway_account.get("name"),
@@ -327,8 +344,9 @@ def make_payment_request(**args):
return pr.as_dict()
-def get_amount(ref_doc, dt):
+def get_amount(ref_doc):
"""get amount based on doctype"""
+ dt = ref_doc.doctype
if dt in ["Sales Order", "Purchase Order"]:
grand_total = flt(ref_doc.grand_total) - flt(ref_doc.advance_paid)
@@ -347,6 +365,17 @@ def get_amount(ref_doc, dt):
else:
frappe.throw(_("Payment Entry is already created"))
+def get_existing_payment_request_amount(ref_dt, ref_dn):
+ existing_payment_request_amount = frappe.db.sql("""
+ select sum(grand_total)
+ from `tabPayment Request`
+ where
+ reference_doctype = %s
+ and reference_name = %s
+ and docstatus = 1
+ """, (ref_dt, ref_dn))
+ return flt(existing_payment_request_amount[0][0]) if existing_payment_request_amount else 0
+
def get_gateway_details(args):
"""return gateway and payment account of default payment gateway"""
if args.get("payment_gateway"):
diff --git a/erpnext/accounts/doctype/payment_request/test_payment_request.py b/erpnext/accounts/doctype/payment_request/test_payment_request.py
index bfd6d54824..188ab0aecf 100644
--- a/erpnext/accounts/doctype/payment_request/test_payment_request.py
+++ b/erpnext/accounts/doctype/payment_request/test_payment_request.py
@@ -37,12 +37,12 @@ class TestPaymentRequest(unittest.TestCase):
def setUp(self):
if not frappe.db.get_value("Payment Gateway", payment_gateway["gateway"], "name"):
frappe.get_doc(payment_gateway).insert(ignore_permissions=True)
-
+
for method in payment_method:
- if not frappe.db.get_value("Payment Gateway Account", {"payment_gateway": method["payment_gateway"],
+ if not frappe.db.get_value("Payment Gateway Account", {"payment_gateway": method["payment_gateway"],
"currency": method["currency"]}, "name"):
frappe.get_doc(method).insert(ignore_permissions=True)
-
+
def test_payment_request_linkings(self):
so_inr = make_sales_order(currency="INR")
pr = make_payment_request(dt="Sales Order", dn=so_inr.name, recipient_id="saurabh@erpnext.com")
@@ -100,3 +100,23 @@ class TestPaymentRequest(unittest.TestCase):
self.assertEqual(expected_gle[gle.account][1], gle.debit)
self.assertEqual(expected_gle[gle.account][2], gle.credit)
self.assertEqual(expected_gle[gle.account][3], gle.against_voucher)
+
+ def test_multiple_payment_entries_against_sales_order(self):
+ # Make Sales Order, grand_total = 1000
+ so = make_sales_order()
+
+ # Payment Request amount = 200
+ pr1 = make_payment_request(dt="Sales Order", dn=so.name,
+ recipient_id="nabin@erpnext.com", return_doc=1)
+ pr1.grand_total = 200
+ pr1.submit()
+
+ # Make a 2nd Payment Request
+ pr2 = make_payment_request(dt="Sales Order", dn=so.name,
+ recipient_id="nabin@erpnext.com", return_doc=1)
+
+ self.assertEqual(pr2.grand_total, 800)
+
+ # Try to make Payment Request more than SO amount, should give validation
+ pr2.grand_total = 900
+ self.assertRaises(frappe.ValidationError, pr2.save)
\ No newline at end of file
From 1d1858a8b09fcc0a98ba4c5d8968568ce86e3eda Mon Sep 17 00:00:00 2001
From: Nabin Hait
Date: Wed, 11 Sep 2019 18:39:49 +0530
Subject: [PATCH 467/484] Show draft future payments as well
---
.../report/accounts_receivable/accounts_receivable.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
index b2bf3f90a7..a7279f75f1 100755
--- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
+++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
@@ -365,7 +365,7 @@ class ReceivablePayableReport(object):
on
(ref.parent = payment_entry.name)
where
- payment_entry.docstatus = 1
+ payment_entry.docstatus < 2
and payment_entry.posting_date > %s
and payment_entry.party_type = %s
""", (self.filters.report_date, self.party_type), as_dict=1)
@@ -390,7 +390,7 @@ class ReceivablePayableReport(object):
on
(jea.parent = je.name)
where
- je.docstatus = 1
+ je.docstatus < 2
and je.posting_date > %s
and jea.party_type = %s
and jea.reference_name is not null and jea.reference_name != ''
From cd38ba483338e3679a0198e0d9aed1c29dd7f182 Mon Sep 17 00:00:00 2001
From: Fisher Yu <12823863+szufisher@users.noreply.github.com>
Date: Wed, 11 Sep 2019 21:40:39 +0800
Subject: [PATCH 468/484] fix: several bugs and improvement ideas for education
module #18599 (#18600)
* Update student_report_generation_tool.py
bug fix
* Update student_applicant.json
* Update program_course.json
* Update course_activity.json
---
.../doctype/course_activity/course_activity.json | 4 ++--
.../doctype/program_course/program_course.json | 11 ++++++++++-
.../doctype/student_applicant/student_applicant.json | 3 +--
.../student_report_generation_tool.py | 4 ++--
4 files changed, 15 insertions(+), 7 deletions(-)
diff --git a/erpnext/education/doctype/course_activity/course_activity.json b/erpnext/education/doctype/course_activity/course_activity.json
index 99ae9aee56..3e23c90da0 100644
--- a/erpnext/education/doctype/course_activity/course_activity.json
+++ b/erpnext/education/doctype/course_activity/course_activity.json
@@ -30,7 +30,7 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
- "label": "Enrollment",
+ "label": "Course Enrollment",
"length": 0,
"no_copy": 0,
"options": "Course Enrollment",
@@ -298,4 +298,4 @@
"track_changes": 1,
"track_seen": 0,
"track_views": 0
-}
\ No newline at end of file
+}
diff --git a/erpnext/education/doctype/program_course/program_course.json b/erpnext/education/doctype/program_course/program_course.json
index 3465040415..a24e88a861 100644
--- a/erpnext/education/doctype/program_course/program_course.json
+++ b/erpnext/education/doctype/program_course/program_course.json
@@ -5,6 +5,7 @@
"engine": "InnoDB",
"field_order": [
"course",
+ "course_name",
"required"
],
"fields": [
@@ -16,6 +17,14 @@
"label": "Course",
"options": "Course",
"reqd": 1
+ },
+ {
+ "fieldname": "course_name",
+ "fieldtype": "Data",
+ "in_list_view": 1,
+ "label": "Course Name",
+ "fetch_from": "course.course_name",
+ "read_only":1
},
{
"default": "0",
@@ -36,4 +45,4 @@
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
-}
\ No newline at end of file
+}
diff --git a/erpnext/education/doctype/student_applicant/student_applicant.json b/erpnext/education/doctype/student_applicant/student_applicant.json
index 71134e0907..e5d0bd37de 100644
--- a/erpnext/education/doctype/student_applicant/student_applicant.json
+++ b/erpnext/education/doctype/student_applicant/student_applicant.json
@@ -705,7 +705,6 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
- "default": "INDIAN",
"fieldname": "nationality",
"fieldtype": "Data",
"hidden": 0,
@@ -1231,4 +1230,4 @@
"track_changes": 0,
"track_seen": 0,
"track_views": 0
-}
\ No newline at end of file
+}
diff --git a/erpnext/education/doctype/student_report_generation_tool/student_report_generation_tool.py b/erpnext/education/doctype/student_report_generation_tool/student_report_generation_tool.py
index 16933dcfe0..c0a73596ac 100644
--- a/erpnext/education/doctype/student_report_generation_tool/student_report_generation_tool.py
+++ b/erpnext/education/doctype/student_report_generation_tool/student_report_generation_tool.py
@@ -55,7 +55,7 @@ def preview_report_card(doc):
"courses": courses,
"assessment_groups": assessment_groups,
"course_criteria": course_criteria,
- "letterhead": letterhead.content,
+ "letterhead": letterhead and letterhead.get('content', None),
"add_letterhead": doc.add_letterhead if doc.add_letterhead else 0
})
final_template = frappe.render_template(base_template_path, {"body": html, "title": "Report Card"})
@@ -89,4 +89,4 @@ def get_attendance_count(student, academic_year, academic_term=None):
attendance["Present"] = 0
return attendance
else:
- frappe.throw(_("Provide the academic year and set the starting and ending date."))
\ No newline at end of file
+ frappe.throw(_("Provide the academic year and set the starting and ending date."))
From e3ef56804cc7364dcd281f145970cff9200588da Mon Sep 17 00:00:00 2001
From: Himanshu
Date: Wed, 11 Sep 2019 19:20:20 +0530
Subject: [PATCH 469/484] fix(Issue): track split from in issue (#18994)
* fix: track split from in issue
* fix: rename field name
* fix: remove first_mins to response
---
erpnext/support/doctype/issue/issue.js | 2 +-
erpnext/support/doctype/issue/issue.json | 774 ++++++++++++-----------
erpnext/support/doctype/issue/issue.py | 11 +
3 files changed, 403 insertions(+), 384 deletions(-)
diff --git a/erpnext/support/doctype/issue/issue.js b/erpnext/support/doctype/issue/issue.js
index aec9db9d4a..bad40cc37f 100644
--- a/erpnext/support/doctype/issue/issue.js
+++ b/erpnext/support/doctype/issue/issue.js
@@ -107,7 +107,7 @@ frappe.ui.form.on("Issue", {
}, () => {
reset_sla.enable_primary_action();
frm.refresh();
- frappe.msgprint(__("Service Level Agreement Reset."));
+ frappe.msgprint(__("Service Level Agreement was reset."));
});
}
});
diff --git a/erpnext/support/doctype/issue/issue.json b/erpnext/support/doctype/issue/issue.json
index 1e5d5f9ea7..222554bda1 100644
--- a/erpnext/support/doctype/issue/issue.json
+++ b/erpnext/support/doctype/issue/issue.json
@@ -1,384 +1,392 @@
{
- "allow_import": 1,
- "allow_rename": 1,
- "autoname": "naming_series:",
- "creation": "2013-02-01 10:36:25",
- "doctype": "DocType",
- "document_type": "Setup",
- "engine": "InnoDB",
- "field_order": [
- "subject_section",
- "naming_series",
- "subject",
- "customer",
- "raised_by",
- "cb00",
- "status",
- "priority",
- "issue_type",
- "sb_details",
- "description",
- "service_level_section",
- "service_level_agreement",
- "response_by",
- "response_by_variance",
- "reset_service_level_agreement",
- "cb",
- "agreement_fulfilled",
- "resolution_by",
- "resolution_by_variance",
- "service_level_agreement_creation",
- "response",
- "mins_to_first_response",
- "first_responded_on",
- "additional_info",
- "lead",
- "contact",
- "email_account",
- "column_break_16",
- "customer_name",
- "project",
- "company",
- "section_break_19",
- "resolution_details",
- "column_break1",
- "opening_date",
- "opening_time",
- "resolution_date",
- "content_type",
- "attachment",
- "via_customer_portal"
- ],
- "fields": [
- {
- "fieldname": "subject_section",
- "fieldtype": "Section Break",
- "label": "Subject",
- "options": "fa fa-flag"
- },
- {
- "fieldname": "naming_series",
- "fieldtype": "Select",
- "label": "Series",
- "no_copy": 1,
- "options": "ISS-.YYYY.-",
- "print_hide": 1,
- "set_only_once": 1
- },
- {
- "bold": 1,
- "fieldname": "subject",
- "fieldtype": "Data",
- "in_global_search": 1,
- "in_standard_filter": 1,
- "label": "Subject",
- "reqd": 1
- },
- {
- "fieldname": "customer",
- "fieldtype": "Link",
- "in_global_search": 1,
- "label": "Customer",
- "oldfieldname": "customer",
- "oldfieldtype": "Link",
- "options": "Customer",
- "print_hide": 1,
- "search_index": 1
- },
- {
- "bold": 1,
- "depends_on": "eval:doc.__islocal",
- "fieldname": "raised_by",
- "fieldtype": "Data",
- "in_global_search": 1,
- "in_list_view": 1,
- "label": "Raised By (Email)",
- "oldfieldname": "raised_by",
- "oldfieldtype": "Data",
- "options": "Email"
- },
- {
- "fieldname": "cb00",
- "fieldtype": "Column Break"
- },
- {
- "default": "Open",
- "fieldname": "status",
- "fieldtype": "Select",
- "in_list_view": 1,
- "in_standard_filter": 1,
- "label": "Status",
- "no_copy": 1,
- "oldfieldname": "status",
- "oldfieldtype": "Select",
- "options": "Open\nReplied\nHold\nClosed",
- "search_index": 1
- },
- {
- "default": "Medium",
- "fieldname": "priority",
- "fieldtype": "Link",
- "in_standard_filter": 1,
- "label": "Priority",
- "options": "Issue Priority"
- },
- {
- "fieldname": "issue_type",
- "fieldtype": "Link",
- "label": "Issue Type",
- "options": "Issue Type"
- },
- {
- "collapsible": 1,
- "collapsible_depends_on": "eval:doc.status!=\"Closed\"",
- "fieldname": "sb_details",
- "fieldtype": "Section Break",
- "label": "Details"
- },
- {
- "bold": 1,
- "fieldname": "description",
- "fieldtype": "Text Editor",
- "in_global_search": 1,
- "label": "Description",
- "oldfieldname": "problem_description",
- "oldfieldtype": "Text"
- },
- {
- "collapsible": 1,
- "fieldname": "service_level_section",
- "fieldtype": "Section Break",
- "label": "Service Level"
- },
- {
- "fieldname": "service_level_agreement",
- "fieldtype": "Link",
- "label": "Service Level Agreement",
- "options": "Service Level Agreement"
- },
- {
- "fieldname": "response_by",
- "fieldtype": "Datetime",
- "label": "Response By",
- "read_only": 1
- },
- {
- "collapsible": 1,
- "fieldname": "cb",
- "fieldtype": "Column Break",
- "options": "fa fa-pushpin",
- "read_only": 1
- },
- {
- "fieldname": "resolution_by",
- "fieldtype": "Datetime",
- "label": "Resolution By",
- "read_only": 1
- },
- {
- "collapsible": 1,
- "fieldname": "response",
- "fieldtype": "Section Break",
- "label": "Response"
- },
- {
- "bold": 1,
- "fieldname": "mins_to_first_response",
- "fieldtype": "Float",
- "label": "Mins to First Response",
- "read_only": 1
- },
- {
- "fieldname": "first_responded_on",
- "fieldtype": "Datetime",
- "label": "First Responded On"
- },
- {
- "collapsible": 1,
- "fieldname": "additional_info",
- "fieldtype": "Section Break",
- "label": "Reference",
- "options": "fa fa-pushpin",
- "read_only": 1
- },
- {
- "fieldname": "lead",
- "fieldtype": "Link",
- "label": "Lead",
- "options": "Lead"
- },
- {
- "fieldname": "contact",
- "fieldtype": "Link",
- "label": "Contact",
- "options": "Contact"
- },
- {
- "fieldname": "email_account",
- "fieldtype": "Link",
- "label": "Email Account",
- "options": "Email Account"
- },
- {
- "fieldname": "column_break_16",
- "fieldtype": "Column Break"
- },
- {
- "bold": 1,
- "fieldname": "customer_name",
- "fieldtype": "Data",
- "label": "Customer Name",
- "oldfieldname": "customer_name",
- "oldfieldtype": "Data",
- "read_only": 1
- },
- {
- "fieldname": "project",
- "fieldtype": "Link",
- "label": "Project",
- "options": "Project"
- },
- {
- "fieldname": "company",
- "fieldtype": "Link",
- "label": "Company",
- "options": "Company",
- "print_hide": 1
- },
- {
- "collapsible": 1,
- "fieldname": "section_break_19",
- "fieldtype": "Section Break",
- "label": "Resolution"
- },
- {
- "depends_on": "eval:!doc.__islocal",
- "fieldname": "resolution_details",
- "fieldtype": "Text Editor",
- "label": "Resolution Details",
- "no_copy": 1,
- "oldfieldname": "resolution_details",
- "oldfieldtype": "Text"
- },
- {
- "depends_on": "eval:!doc.__islocal",
- "fieldname": "column_break1",
- "fieldtype": "Column Break",
- "oldfieldtype": "Column Break",
- "read_only": 1
- },
- {
- "default": "Today",
- "fieldname": "opening_date",
- "fieldtype": "Date",
- "label": "Opening Date",
- "no_copy": 1,
- "oldfieldname": "opening_date",
- "oldfieldtype": "Date",
- "read_only": 1
- },
- {
- "fieldname": "opening_time",
- "fieldtype": "Time",
- "label": "Opening Time",
- "no_copy": 1,
- "oldfieldname": "opening_time",
- "oldfieldtype": "Time",
- "read_only": 1
- },
- {
- "depends_on": "eval:!doc.__islocal",
- "fieldname": "resolution_date",
- "fieldtype": "Datetime",
- "label": "Resolution Date",
- "no_copy": 1,
- "oldfieldname": "resolution_date",
- "oldfieldtype": "Date",
- "read_only": 1
- },
- {
- "fieldname": "content_type",
- "fieldtype": "Data",
- "hidden": 1,
- "label": "Content Type"
- },
- {
- "fieldname": "attachment",
- "fieldtype": "Attach",
- "hidden": 1,
- "label": "Attachment"
- },
- {
- "default": "0",
- "fieldname": "via_customer_portal",
- "fieldtype": "Check",
- "label": "Via Customer Portal"
- },
- {
- "default": "Ongoing",
- "depends_on": "eval: doc.service_level_agreement",
- "fieldname": "agreement_fulfilled",
- "fieldtype": "Select",
- "label": "Service Level Agreement Fulfilled",
- "options": "Ongoing\nFulfilled\nFailed",
- "read_only": 1
- },
- {
- "depends_on": "eval: doc.service_level_agreement",
- "description": "in hours",
- "fieldname": "response_by_variance",
- "fieldtype": "Float",
- "label": "Response By Variance",
- "read_only": 1
- },
- {
- "depends_on": "eval: doc.service_level_agreement",
- "description": "in hours",
- "fieldname": "resolution_by_variance",
- "fieldtype": "Float",
- "label": "Resolution By Variance",
- "read_only": 1
- },
- {
- "fieldname": "service_level_agreement_creation",
- "fieldtype": "Datetime",
- "hidden": 1,
- "label": "Service Level Agreement Creation",
- "read_only": 1
- },
- {
- "depends_on": "eval: doc.service_level_agreement",
- "fieldname": "reset_service_level_agreement",
- "fieldtype": "Button",
- "label": "Reset Service Level Agreement"
- }
- ],
- "icon": "fa fa-ticket",
- "idx": 7,
- "modified": "2019-07-11 23:57:22.015881",
- "modified_by": "Administrator",
- "module": "Support",
- "name": "Issue",
- "owner": "Administrator",
- "permissions": [
- {
- "create": 1,
- "delete": 1,
- "email": 1,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Support Team",
- "share": 1,
- "write": 1
- }
- ],
- "quick_entry": 1,
- "search_fields": "status,customer,subject,raised_by",
- "sort_field": "modified",
- "sort_order": "ASC",
- "timeline_field": "customer",
- "title_field": "subject",
- "track_changes": 1,
- "track_seen": 1
- }
\ No newline at end of file
+ "allow_import": 1,
+ "allow_rename": 1,
+ "autoname": "naming_series:",
+ "creation": "2013-02-01 10:36:25",
+ "doctype": "DocType",
+ "document_type": "Setup",
+ "engine": "InnoDB",
+ "field_order": [
+ "subject_section",
+ "naming_series",
+ "subject",
+ "customer",
+ "raised_by",
+ "cb00",
+ "status",
+ "priority",
+ "issue_type",
+ "issue_split_from",
+ "sb_details",
+ "description",
+ "service_level_section",
+ "service_level_agreement",
+ "response_by",
+ "response_by_variance",
+ "reset_service_level_agreement",
+ "cb",
+ "agreement_fulfilled",
+ "resolution_by",
+ "resolution_by_variance",
+ "service_level_agreement_creation",
+ "response",
+ "mins_to_first_response",
+ "first_responded_on",
+ "additional_info",
+ "lead",
+ "contact",
+ "email_account",
+ "column_break_16",
+ "customer_name",
+ "project",
+ "company",
+ "section_break_19",
+ "resolution_details",
+ "column_break1",
+ "opening_date",
+ "opening_time",
+ "resolution_date",
+ "content_type",
+ "attachment",
+ "via_customer_portal"
+ ],
+ "fields": [
+ {
+ "fieldname": "subject_section",
+ "fieldtype": "Section Break",
+ "label": "Subject",
+ "options": "fa fa-flag"
+ },
+ {
+ "fieldname": "naming_series",
+ "fieldtype": "Select",
+ "label": "Series",
+ "no_copy": 1,
+ "options": "ISS-.YYYY.-",
+ "print_hide": 1,
+ "set_only_once": 1
+ },
+ {
+ "bold": 1,
+ "fieldname": "subject",
+ "fieldtype": "Data",
+ "in_global_search": 1,
+ "in_standard_filter": 1,
+ "label": "Subject",
+ "reqd": 1
+ },
+ {
+ "fieldname": "customer",
+ "fieldtype": "Link",
+ "in_global_search": 1,
+ "label": "Customer",
+ "oldfieldname": "customer",
+ "oldfieldtype": "Link",
+ "options": "Customer",
+ "print_hide": 1,
+ "search_index": 1
+ },
+ {
+ "bold": 1,
+ "depends_on": "eval:doc.__islocal",
+ "fieldname": "raised_by",
+ "fieldtype": "Data",
+ "in_global_search": 1,
+ "in_list_view": 1,
+ "label": "Raised By (Email)",
+ "oldfieldname": "raised_by",
+ "oldfieldtype": "Data",
+ "options": "Email"
+ },
+ {
+ "fieldname": "cb00",
+ "fieldtype": "Column Break"
+ },
+ {
+ "default": "Open",
+ "fieldname": "status",
+ "fieldtype": "Select",
+ "in_list_view": 1,
+ "in_standard_filter": 1,
+ "label": "Status",
+ "no_copy": 1,
+ "oldfieldname": "status",
+ "oldfieldtype": "Select",
+ "options": "Open\nReplied\nHold\nClosed",
+ "search_index": 1
+ },
+ {
+ "default": "Medium",
+ "fieldname": "priority",
+ "fieldtype": "Link",
+ "in_standard_filter": 1,
+ "label": "Priority",
+ "options": "Issue Priority"
+ },
+ {
+ "fieldname": "issue_type",
+ "fieldtype": "Link",
+ "label": "Issue Type",
+ "options": "Issue Type"
+ },
+ {
+ "collapsible": 1,
+ "collapsible_depends_on": "eval:doc.status!=\"Closed\"",
+ "fieldname": "sb_details",
+ "fieldtype": "Section Break",
+ "label": "Details"
+ },
+ {
+ "bold": 1,
+ "fieldname": "description",
+ "fieldtype": "Text Editor",
+ "in_global_search": 1,
+ "label": "Description",
+ "oldfieldname": "problem_description",
+ "oldfieldtype": "Text"
+ },
+ {
+ "collapsible": 1,
+ "fieldname": "service_level_section",
+ "fieldtype": "Section Break",
+ "label": "Service Level"
+ },
+ {
+ "fieldname": "service_level_agreement",
+ "fieldtype": "Link",
+ "label": "Service Level Agreement",
+ "options": "Service Level Agreement"
+ },
+ {
+ "fieldname": "response_by",
+ "fieldtype": "Datetime",
+ "label": "Response By",
+ "read_only": 1
+ },
+ {
+ "collapsible": 1,
+ "fieldname": "cb",
+ "fieldtype": "Column Break",
+ "options": "fa fa-pushpin",
+ "read_only": 1
+ },
+ {
+ "fieldname": "resolution_by",
+ "fieldtype": "Datetime",
+ "label": "Resolution By",
+ "read_only": 1
+ },
+ {
+ "collapsible": 1,
+ "fieldname": "response",
+ "fieldtype": "Section Break",
+ "label": "Response"
+ },
+ {
+ "bold": 1,
+ "fieldname": "mins_to_first_response",
+ "fieldtype": "Float",
+ "label": "Mins to First Response",
+ "read_only": 1
+ },
+ {
+ "fieldname": "first_responded_on",
+ "fieldtype": "Datetime",
+ "label": "First Responded On"
+ },
+ {
+ "collapsible": 1,
+ "fieldname": "additional_info",
+ "fieldtype": "Section Break",
+ "label": "Reference",
+ "options": "fa fa-pushpin",
+ "read_only": 1
+ },
+ {
+ "fieldname": "lead",
+ "fieldtype": "Link",
+ "label": "Lead",
+ "options": "Lead"
+ },
+ {
+ "fieldname": "contact",
+ "fieldtype": "Link",
+ "label": "Contact",
+ "options": "Contact"
+ },
+ {
+ "fieldname": "email_account",
+ "fieldtype": "Link",
+ "label": "Email Account",
+ "options": "Email Account"
+ },
+ {
+ "fieldname": "column_break_16",
+ "fieldtype": "Column Break"
+ },
+ {
+ "bold": 1,
+ "fieldname": "customer_name",
+ "fieldtype": "Data",
+ "label": "Customer Name",
+ "oldfieldname": "customer_name",
+ "oldfieldtype": "Data",
+ "read_only": 1
+ },
+ {
+ "fieldname": "project",
+ "fieldtype": "Link",
+ "label": "Project",
+ "options": "Project"
+ },
+ {
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "label": "Company",
+ "options": "Company",
+ "print_hide": 1
+ },
+ {
+ "collapsible": 1,
+ "fieldname": "section_break_19",
+ "fieldtype": "Section Break",
+ "label": "Resolution"
+ },
+ {
+ "depends_on": "eval:!doc.__islocal",
+ "fieldname": "resolution_details",
+ "fieldtype": "Text Editor",
+ "label": "Resolution Details",
+ "no_copy": 1,
+ "oldfieldname": "resolution_details",
+ "oldfieldtype": "Text"
+ },
+ {
+ "depends_on": "eval:!doc.__islocal",
+ "fieldname": "column_break1",
+ "fieldtype": "Column Break",
+ "oldfieldtype": "Column Break",
+ "read_only": 1
+ },
+ {
+ "default": "Today",
+ "fieldname": "opening_date",
+ "fieldtype": "Date",
+ "label": "Opening Date",
+ "no_copy": 1,
+ "oldfieldname": "opening_date",
+ "oldfieldtype": "Date",
+ "read_only": 1
+ },
+ {
+ "fieldname": "opening_time",
+ "fieldtype": "Time",
+ "label": "Opening Time",
+ "no_copy": 1,
+ "oldfieldname": "opening_time",
+ "oldfieldtype": "Time",
+ "read_only": 1
+ },
+ {
+ "depends_on": "eval:!doc.__islocal",
+ "fieldname": "resolution_date",
+ "fieldtype": "Datetime",
+ "label": "Resolution Date",
+ "no_copy": 1,
+ "oldfieldname": "resolution_date",
+ "oldfieldtype": "Date",
+ "read_only": 1
+ },
+ {
+ "fieldname": "content_type",
+ "fieldtype": "Data",
+ "hidden": 1,
+ "label": "Content Type"
+ },
+ {
+ "fieldname": "attachment",
+ "fieldtype": "Attach",
+ "hidden": 1,
+ "label": "Attachment"
+ },
+ {
+ "default": "0",
+ "fieldname": "via_customer_portal",
+ "fieldtype": "Check",
+ "label": "Via Customer Portal"
+ },
+ {
+ "default": "Ongoing",
+ "depends_on": "eval: doc.service_level_agreement",
+ "fieldname": "agreement_fulfilled",
+ "fieldtype": "Select",
+ "label": "Service Level Agreement Fulfilled",
+ "options": "Ongoing\nFulfilled\nFailed",
+ "read_only": 1
+ },
+ {
+ "depends_on": "eval: doc.service_level_agreement",
+ "description": "in hours",
+ "fieldname": "response_by_variance",
+ "fieldtype": "Float",
+ "label": "Response By Variance",
+ "read_only": 1
+ },
+ {
+ "depends_on": "eval: doc.service_level_agreement",
+ "description": "in hours",
+ "fieldname": "resolution_by_variance",
+ "fieldtype": "Float",
+ "label": "Resolution By Variance",
+ "read_only": 1
+ },
+ {
+ "fieldname": "service_level_agreement_creation",
+ "fieldtype": "Datetime",
+ "hidden": 1,
+ "label": "Service Level Agreement Creation",
+ "read_only": 1
+ },
+ {
+ "depends_on": "eval: doc.service_level_agreement",
+ "fieldname": "reset_service_level_agreement",
+ "fieldtype": "Button",
+ "label": "Reset Service Level Agreement"
+ },
+ {
+ "fieldname": "issue_split_from",
+ "fieldtype": "Link",
+ "label": "Issue Split From",
+ "options": "Issue",
+ "read_only": 1
+ }
+ ],
+ "icon": "fa fa-ticket",
+ "idx": 7,
+ "modified": "2019-09-11 09:03:57.465623",
+ "modified_by": "himanshu@erpnext.com",
+ "module": "Support",
+ "name": "Issue",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Support Team",
+ "share": 1,
+ "write": 1
+ }
+ ],
+ "quick_entry": 1,
+ "search_fields": "status,customer,subject,raised_by",
+ "sort_field": "modified",
+ "sort_order": "ASC",
+ "timeline_field": "customer",
+ "title_field": "subject",
+ "track_changes": 1,
+ "track_seen": 1
+}
\ No newline at end of file
diff --git a/erpnext/support/doctype/issue/issue.py b/erpnext/support/doctype/issue/issue.py
index 58e2076858..b748e3fa46 100644
--- a/erpnext/support/doctype/issue/issue.py
+++ b/erpnext/support/doctype/issue/issue.py
@@ -117,6 +117,9 @@ class Issue(Document):
replicated_issue = deepcopy(self)
replicated_issue.subject = subject
+ replicated_issue.issue_split_from = self.name
+ replicated_issue.mins_to_first_response = 0
+ replicated_issue.first_responded_on = None
replicated_issue.creation = now_datetime()
# Reset SLA
@@ -144,6 +147,14 @@ class Issue(Document):
doc.reference_name = replicated_issue.name
doc.save(ignore_permissions=True)
+ frappe.get_doc({
+ "doctype": "Comment",
+ "comment_type": "Info",
+ "reference_doctype": "Issue",
+ "reference_name": replicated_issue.name,
+ "content": " - Split the Issue from {1} ".format(self.name, frappe.bold(self.name)),
+ }).insert(ignore_permissions=True)
+
return replicated_issue.name
def before_insert(self):
From b1604a24ed9374dce718aad94a4a849c720beb81 Mon Sep 17 00:00:00 2001
From: sahil28297 <37302950+sahil28297@users.noreply.github.com>
Date: Thu, 12 Sep 2019 11:20:55 +0530
Subject: [PATCH 470/484] fix(add_to_cart): show add_to_card button only if
specific conditions are satisfied (#19007)
---
erpnext/templates/generators/item/item_add_to_cart.html | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/erpnext/templates/generators/item/item_add_to_cart.html b/erpnext/templates/generators/item/item_add_to_cart.html
index f4a31a7e73..2a70d8dbe9 100644
--- a/erpnext/templates/generators/item/item_add_to_cart.html
+++ b/erpnext/templates/generators/item/item_add_to_cart.html
@@ -27,6 +27,7 @@
{% endif %}
{% endif %}
+ {% if product_info.price and (cart_settings.allow_items_not_in_stock or product_info.in_stock) %}
+ {% endif %}
@@ -64,4 +66,4 @@
});
-{% endif %}
\ No newline at end of file
+{% endif %}
From 504e52ff4653c6ba992354bfa82fea15cdedb6c9 Mon Sep 17 00:00:00 2001
From: Sammish Thundiyil
Date: Thu, 12 Sep 2019 11:18:42 +0300
Subject: [PATCH 471/484] refactor: cost center (#19011)
* modified: erpnext/accounts/doctype/cost_center/cost_center.json
* fix: removed unique property from cost_center_name
---
.../doctype/cost_center/cost_center.json | 584 +++++-------------
1 file changed, 149 insertions(+), 435 deletions(-)
diff --git a/erpnext/accounts/doctype/cost_center/cost_center.json b/erpnext/accounts/doctype/cost_center/cost_center.json
index 4da21f11fe..ff55c21497 100644
--- a/erpnext/accounts/doctype/cost_center/cost_center.json
+++ b/erpnext/accounts/doctype/cost_center/cost_center.json
@@ -1,457 +1,171 @@
{
- "allow_copy": 1,
- "allow_guest_to_view": 0,
- "allow_import": 1,
- "allow_rename": 1,
- "autoname": "field:cost_center_name",
- "beta": 0,
- "creation": "2013-01-23 19:57:17",
- "custom": 0,
- "description": "Track separate Income and Expense for product verticals or divisions.",
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "Setup",
- "editable_grid": 0,
+ "allow_copy": 1,
+ "allow_import": 1,
+ "allow_rename": 1,
+ "autoname": "field:cost_center_name",
+ "creation": "2013-01-23 19:57:17",
+ "description": "Track separate Income and Expense for product verticals or divisions.",
+ "doctype": "DocType",
+ "document_type": "Setup",
+ "engine": "InnoDB",
+ "field_order": [
+ "sb0",
+ "cost_center_name",
+ "cost_center_number",
+ "parent_cost_center",
+ "company",
+ "cb0",
+ "is_group",
+ "enabled",
+ "lft",
+ "rgt",
+ "old_parent"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "sb0",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "sb0",
+ "fieldtype": "Section Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "cost_center_name",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Cost Center Name",
- "length": 0,
- "no_copy": 1,
- "oldfieldname": "cost_center_name",
- "oldfieldtype": "Data",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "cost_center_name",
+ "fieldtype": "Data",
+ "in_list_view": 1,
+ "label": "Cost Center Name",
+ "no_copy": 1,
+ "oldfieldname": "cost_center_name",
+ "oldfieldtype": "Data",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "cost_center_number",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 1,
- "label": "Cost Center Number",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "cost_center_number",
+ "fieldtype": "Data",
+ "in_list_view": 1,
+ "in_standard_filter": 1,
+ "label": "Cost Center Number",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "parent_cost_center",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 1,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Parent Cost Center",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "parent_cost_center",
- "oldfieldtype": "Link",
- "options": "Cost Center",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "parent_cost_center",
+ "fieldtype": "Link",
+ "ignore_user_permissions": 1,
+ "in_list_view": 1,
+ "label": "Parent Cost Center",
+ "oldfieldname": "parent_cost_center",
+ "oldfieldtype": "Link",
+ "options": "Cost Center",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "company",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 1,
- "label": "Company",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "company_name",
- "oldfieldtype": "Link",
- "options": "Company",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 1,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "in_standard_filter": 1,
+ "label": "Company",
+ "oldfieldname": "company_name",
+ "oldfieldtype": "Link",
+ "options": "Company",
+ "remember_last_selected_value": 1,
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "cb0",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0,
+ "fieldname": "cb0",
+ "fieldtype": "Column Break",
"width": "50%"
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "0",
- "fieldname": "is_group",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Is Group",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "default": "0",
+ "fieldname": "is_group",
+ "fieldtype": "Check",
+ "label": "Is Group"
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "lft",
- "fieldtype": "Int",
- "hidden": 1,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "lft",
- "length": 0,
- "no_copy": 1,
- "oldfieldname": "lft",
- "oldfieldtype": "Int",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 1,
- "reqd": 0,
- "search_index": 1,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "lft",
+ "fieldtype": "Int",
+ "hidden": 1,
+ "label": "lft",
+ "no_copy": 1,
+ "oldfieldname": "lft",
+ "oldfieldtype": "Int",
+ "print_hide": 1,
+ "report_hide": 1,
+ "search_index": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "rgt",
- "fieldtype": "Int",
- "hidden": 1,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "rgt",
- "length": 0,
- "no_copy": 1,
- "oldfieldname": "rgt",
- "oldfieldtype": "Int",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 1,
- "reqd": 0,
- "search_index": 1,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "rgt",
+ "fieldtype": "Int",
+ "hidden": 1,
+ "label": "rgt",
+ "no_copy": 1,
+ "oldfieldname": "rgt",
+ "oldfieldtype": "Int",
+ "print_hide": 1,
+ "report_hide": 1,
+ "search_index": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "old_parent",
- "fieldtype": "Link",
- "hidden": 1,
- "ignore_user_permissions": 1,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "old_parent",
- "length": 0,
- "no_copy": 1,
- "oldfieldname": "old_parent",
- "oldfieldtype": "Data",
- "options": "Cost Center",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 1,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "fieldname": "old_parent",
+ "fieldtype": "Link",
+ "hidden": 1,
+ "ignore_user_permissions": 1,
+ "label": "old_parent",
+ "no_copy": 1,
+ "oldfieldname": "old_parent",
+ "oldfieldtype": "Data",
+ "options": "Cost Center",
+ "print_hide": 1,
+ "report_hide": 1
+ },
+ {
+ "default": "0",
+ "fieldname": "enabled",
+ "fieldtype": "Check",
+ "label": "Enabled"
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "icon": "fa fa-money",
- "idx": 1,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "menu_index": 0,
- "modified": "2018-04-26 15:26:25.325778",
- "modified_by": "Administrator",
- "module": "Accounts",
- "name": "Cost Center",
- "owner": "Administrator",
+ ],
+ "icon": "fa fa-money",
+ "idx": 1,
+ "modified": "2019-08-22 15:05:05.559862",
+ "modified_by": "sammish.thundiyil@gmail.com",
+ "module": "Accounts",
+ "name": "Cost Center",
+ "owner": "Administrator",
"permissions": [
{
- "amend": 0,
- "cancel": 0,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Accounts Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Accounts Manager",
+ "share": 1,
"write": 1
- },
+ },
{
- "amend": 0,
- "cancel": 0,
- "create": 0,
- "delete": 0,
- "email": 0,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 0,
- "read": 1,
- "report": 1,
- "role": "Auditor",
- "set_user_permissions": 0,
- "share": 0,
- "submit": 0,
- "write": 0
- },
+ "export": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Auditor"
+ },
{
- "amend": 0,
- "cancel": 0,
- "create": 0,
- "delete": 0,
- "email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Accounts User",
- "set_user_permissions": 0,
- "share": 0,
- "submit": 0,
- "write": 0
- },
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Accounts User"
+ },
{
- "amend": 0,
- "cancel": 0,
- "create": 0,
- "delete": 0,
- "email": 0,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 0,
- "read": 1,
- "report": 0,
- "role": "Sales User",
- "set_user_permissions": 0,
- "share": 0,
- "submit": 0,
- "write": 0
- },
+ "read": 1,
+ "role": "Sales User"
+ },
{
- "amend": 0,
- "cancel": 0,
- "create": 0,
- "delete": 0,
- "email": 0,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 0,
- "read": 1,
- "report": 0,
- "role": "Purchase User",
- "set_user_permissions": 0,
- "share": 0,
- "submit": 0,
- "write": 0
+ "read": 1,
+ "role": "Purchase User"
}
- ],
- "quick_entry": 1,
- "read_only": 0,
- "read_only_onload": 0,
- "search_fields": "parent_cost_center, is_group",
- "show_name_in_global_search": 1,
- "sort_order": "ASC",
- "track_changes": 0,
- "track_seen": 0
-}
\ No newline at end of file
+ ],
+ "quick_entry": 1,
+ "search_fields": "parent_cost_center, is_group",
+ "show_name_in_global_search": 1,
+ "sort_field": "modified",
+ "sort_order": "ASC"
+}
From a3095c987a7987ba5d4a6bd0f9f9a7c95bbe7f9f Mon Sep 17 00:00:00 2001
From: Shivam Mishra
Date: Thu, 12 Sep 2019 17:28:38 +0530
Subject: [PATCH 472/484] fix: optimized query (#19026)
Co-authored-by: nabinhait
Co-authored-by: sahil28297
---
erpnext/stock/doctype/stock_entry/stock_entry.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py
index e5a2102e44..0825557f18 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.py
@@ -1173,7 +1173,7 @@ class StockEntry(StockController):
frappe.db.sql("""UPDATE `tabPurchase Order Item Supplied` pos
SET pos.supplied_qty = (SELECT ifnull(sum(transfer_qty), 0) FROM `tabStock Entry Detail` sed
WHERE pos.name = sed.po_detail and sed.docstatus = 1)
- WHERE pos.docstatus = 1""")
+ WHERE pos.docstatus = 1 and pos.parent = %s""", self.purchase_order)
#Update reserved sub contracted quantity in bin based on Supplied Item Details and
for d in self.get("items"):
From a5dfe0725fd48b8d25ab27ef65c19fa7b98a7bc2 Mon Sep 17 00:00:00 2001
From: Nabin Hait
Date: Thu, 12 Sep 2019 19:17:24 +0530
Subject: [PATCH 473/484] fix: payment against shareholder (#19019)
---
erpnext/accounts/doctype/payment_entry/payment_entry.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py
index 536a6ed2c5..3529900d56 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.py
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py
@@ -126,7 +126,7 @@ class PaymentEntry(AccountsController):
if not self.party:
frappe.throw(_("Party is mandatory"))
- _party_name = "title" if self.party_type == "Student" else self.party_type.lower() + "_name"
+ _party_name = "title" if self.party_type in ("Student", "Shareholder") else self.party_type.lower() + "_name"
self.party_name = frappe.db.get_value(self.party_type, self.party, _party_name)
if self.party:
From 3b0ec48b0cd8e8cb2be4694b13f29f22063b4585 Mon Sep 17 00:00:00 2001
From: Suraj Shetty <13928957+surajshetty3416@users.noreply.github.com>
Date: Thu, 12 Sep 2019 19:18:44 +0530
Subject: [PATCH 474/484] fix: Naming series check to avoid duplicate entry
error (#19015)
* fix: Naming series check to avoid duplicate key error
* fix: Check for existence of naming series
---
erpnext/setup/doctype/naming_series/naming_series.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/setup/doctype/naming_series/naming_series.py b/erpnext/setup/doctype/naming_series/naming_series.py
index cb7ad38014..b2cffbbf0d 100644
--- a/erpnext/setup/doctype/naming_series/naming_series.py
+++ b/erpnext/setup/doctype/naming_series/naming_series.py
@@ -151,7 +151,7 @@ class NamingSeries(Document):
def insert_series(self, series):
"""insert series if missing"""
- if not frappe.db.get_value('Series', series, 'name', order_by="name"):
+ if frappe.db.get_value('Series', series, 'name', order_by="name") == None:
frappe.db.sql("insert into tabSeries (name, current) values (%s, 0)", (series))
def update_series_start(self):
From d51f7af9ab7978393be9553e6271fe64f2751794 Mon Sep 17 00:00:00 2001
From: Himanshu
Date: Thu, 12 Sep 2019 19:19:17 +0530
Subject: [PATCH 475/484] fix: add contact phone to sales order (#19012)
---
.../doctype/sales_order/sales_order.json | 5726 ++++-------------
1 file changed, 1255 insertions(+), 4471 deletions(-)
diff --git a/erpnext/selling/doctype/sales_order/sales_order.json b/erpnext/selling/doctype/sales_order/sales_order.json
index 2481f31ffd..e537495d94 100644
--- a/erpnext/selling/doctype/sales_order/sales_order.json
+++ b/erpnext/selling/doctype/sales_order/sales_order.json
@@ -1,4472 +1,1256 @@
{
- "allow_copy": 0,
- "allow_events_in_timeline": 0,
- "allow_guest_to_view": 0,
- "allow_import": 1,
- "allow_rename": 0,
- "autoname": "naming_series:",
- "beta": 0,
- "creation": "2013-06-18 12:39:59",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "Document",
- "editable_grid": 1,
- "engine": "InnoDB",
- "fields": [
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "customer_section",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "",
- "length": 0,
- "no_copy": 0,
- "options": "fa fa-user",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "column_break0",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "oldfieldtype": "Column Break",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0,
- "width": "50%"
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "{customer_name}",
- "fetch_if_empty": 0,
- "fieldname": "title",
- "fieldtype": "Data",
- "hidden": 1,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Title",
- "length": 0,
- "no_copy": 1,
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "",
- "fetch_if_empty": 0,
- "fieldname": "naming_series",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Series",
- "length": 0,
- "no_copy": 1,
- "oldfieldname": "naming_series",
- "oldfieldtype": "Select",
- "options": "SAL-ORD-.YYYY.-",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 1,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 1,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "customer",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 1,
- "in_list_view": 0,
- "in_standard_filter": 1,
- "label": "Customer",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "customer",
- "oldfieldtype": "Link",
- "options": "Customer",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 1,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 1,
- "collapsible": 0,
- "columns": 0,
- "fetch_from": "customer.customer_name",
- "fetch_if_empty": 0,
- "fieldname": "customer_name",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 1,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Customer Name",
- "length": 0,
- "no_copy": 0,
- "options": "",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "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,
- "default": "Sales",
- "depends_on": "",
- "fetch_if_empty": 0,
- "fieldname": "order_type",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Order Type",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "order_type",
- "oldfieldtype": "Select",
- "options": "\nSales\nMaintenance\nShopping Cart",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "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,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "column_break1",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "oldfieldtype": "Column Break",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0,
- "width": "50%"
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "amended_from",
- "fieldtype": "Link",
- "hidden": 1,
- "ignore_user_permissions": 1,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Amended From",
- "length": 0,
- "no_copy": 1,
- "oldfieldname": "amended_from",
- "oldfieldtype": "Data",
- "options": "Sales Order",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
- "width": "150px"
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "",
- "fetch_if_empty": 0,
- "fieldname": "company",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 1,
- "label": "Company",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "company",
- "oldfieldtype": "Link",
- "options": "Company",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 1,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
- "width": "150px"
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "Today",
- "fetch_if_empty": 0,
- "fieldname": "transaction_date",
- "fieldtype": "Date",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 1,
- "label": "Date",
- "length": 0,
- "no_copy": 1,
- "oldfieldname": "transaction_date",
- "oldfieldtype": "Date",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 1,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
- "width": "160px"
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "delivery_date",
- "fieldtype": "Date",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Delivery Date",
- "length": 0,
- "no_copy": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
- "description": "",
- "fetch_if_empty": 0,
- "fieldname": "po_no",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Customer's Purchase Order",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "po_no",
- "oldfieldtype": "Data",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0,
- "width": "100px"
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:doc.po_no",
- "description": "",
- "fetch_if_empty": 0,
- "fieldname": "po_date",
- "fieldtype": "Date",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Customer's Purchase Order Date",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "po_date",
- "oldfieldtype": "Date",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0,
- "width": "100px"
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "tax_id",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Tax Id",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
- "width": "100px"
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "collapsible_depends_on": "",
- "columns": 0,
- "depends_on": "customer",
- "fetch_if_empty": 0,
- "fieldname": "contact_info",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Address and Contact",
- "length": 0,
- "no_copy": 0,
- "options": "fa fa-bullhorn",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "customer_address",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Customer Address",
- "length": 0,
- "no_copy": 0,
- "options": "Address",
- "permlevel": 0,
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "address_display",
- "fieldtype": "Small Text",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Address",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "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,
- "fetch_if_empty": 0,
- "fieldname": "contact_person",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Contact Person",
- "length": 0,
- "no_copy": 0,
- "options": "Contact",
- "permlevel": 0,
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "contact_display",
- "fieldtype": "Small Text",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 1,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Contact",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "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,
- "fetch_if_empty": 0,
- "fieldname": "contact_mobile",
- "fieldtype": "Small Text",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Mobile No",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "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,
- "fetch_if_empty": 0,
- "fieldname": "contact_email",
- "fieldtype": "Data",
- "hidden": 1,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Contact Email",
- "length": 0,
- "no_copy": 0,
- "options": "Email",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "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,
- "fetch_if_empty": 0,
- "fieldname": "company_address_display",
- "fieldtype": "Small Text",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "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,
- "fetch_if_empty": 0,
- "fieldname": "company_address",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Company Address",
- "length": 0,
- "no_copy": 0,
- "options": "Address",
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "col_break46",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0,
- "width": "50%"
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "shipping_address_name",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Shipping Address Name",
- "length": 0,
- "no_copy": 0,
- "options": "Address",
- "permlevel": 0,
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "shipping_address",
- "fieldtype": "Small Text",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Shipping Address",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "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,
- "description": "",
- "fetch_if_empty": 0,
- "fieldname": "customer_group",
- "fieldtype": "Link",
- "hidden": 1,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Customer Group",
- "length": 0,
- "no_copy": 0,
- "options": "Customer Group",
- "permlevel": 0,
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "",
- "fetch_if_empty": 0,
- "fieldname": "territory",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Territory",
- "length": 0,
- "no_copy": 0,
- "options": "Territory",
- "permlevel": 0,
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "currency_and_price_list",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Currency and Price List",
- "length": 0,
- "no_copy": 0,
- "options": "fa fa-tag",
- "permlevel": 0,
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "currency",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Currency",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "currency",
- "oldfieldtype": "Select",
- "options": "Currency",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
- "width": "100px"
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "Rate at which customer's currency is converted to company's base currency",
- "fetch_if_empty": 0,
- "fieldname": "conversion_rate",
- "fieldtype": "Float",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Exchange Rate",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "conversion_rate",
- "oldfieldtype": "Currency",
- "permlevel": 0,
- "precision": "9",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
- "width": "100px"
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "column_break2",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0,
- "width": "50%"
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "selling_price_list",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Price List",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "price_list_name",
- "oldfieldtype": "Select",
- "options": "Price List",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
- "width": "100px"
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "price_list_currency",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Price List Currency",
- "length": 0,
- "no_copy": 0,
- "options": "Currency",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "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,
- "columns": 0,
- "description": "Rate at which Price list currency is converted to company's base currency",
- "fetch_if_empty": 0,
- "fieldname": "plc_conversion_rate",
- "fieldtype": "Float",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Price List Exchange Rate",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "9",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "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,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "ignore_pricing_rule",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Ignore Pricing Rule",
- "length": 0,
- "no_copy": 1,
- "permlevel": 1,
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "sec_warehouse",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "set_warehouse",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Set Source Warehouse",
- "length": 0,
- "no_copy": 0,
- "options": "Warehouse",
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "items_section",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "",
- "length": 0,
- "no_copy": 0,
- "oldfieldtype": "Section Break",
- "options": "fa fa-shopping-cart",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "scan_barcode",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Scan Barcode",
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 1,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "items",
- "fieldtype": "Table",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Items",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "sales_order_details",
- "oldfieldtype": "Table",
- "options": "Sales Order Item",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "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,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "pricing_rule_details",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Pricing Rules",
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "pricing_rules",
- "fieldtype": "Table",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Pricing Rule Detail",
- "length": 0,
- "no_copy": 0,
- "options": "Pricing Rule Detail",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "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,
- "fetch_if_empty": 0,
- "fieldname": "section_break_31",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "column_break_33a",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "total_qty",
- "fieldtype": "Float",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Total Quantity",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "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,
- "fetch_if_empty": 0,
- "fieldname": "base_total",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Total (Company Currency)",
- "length": 0,
- "no_copy": 0,
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "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,
- "fetch_if_empty": 0,
- "fieldname": "base_net_total",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Net Total (Company Currency)",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "net_total",
- "oldfieldtype": "Currency",
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
- "width": "150px"
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "column_break_33",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "total",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Total",
- "length": 0,
- "no_copy": 0,
- "options": "currency",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "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,
- "fetch_if_empty": 0,
- "fieldname": "net_total",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Net Total",
- "length": 0,
- "no_copy": 0,
- "options": "currency",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "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,
- "fetch_if_empty": 0,
- "fieldname": "total_net_weight",
- "fieldtype": "Float",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Total Net Weight",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "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,
- "fetch_if_empty": 0,
- "fieldname": "taxes_section",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Taxes and Charges",
- "length": 0,
- "no_copy": 0,
- "oldfieldtype": "Section Break",
- "options": "fa fa-money",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "tax_category",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Tax Category",
- "length": 0,
- "no_copy": 0,
- "options": "Tax Category",
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "column_break_38",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "shipping_rule",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Shipping Rule",
- "length": 0,
- "no_copy": 0,
- "oldfieldtype": "Button",
- "options": "Shipping Rule",
- "permlevel": 0,
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "section_break_40",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "taxes_and_charges",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Sales Taxes and Charges Template",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "charge",
- "oldfieldtype": "Link",
- "options": "Sales Taxes and Charges Template",
- "permlevel": 0,
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "taxes",
- "fieldtype": "Table",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Sales Taxes and Charges",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "other_charges",
- "oldfieldtype": "Table",
- "options": "Sales Taxes and Charges",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "sec_tax_breakup",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Tax Breakup",
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "other_charges_calculation",
- "fieldtype": "Text",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Taxes and Charges Calculation",
- "length": 0,
- "no_copy": 1,
- "oldfieldtype": "HTML",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "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,
- "fetch_if_empty": 0,
- "fieldname": "section_break_43",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "base_total_taxes_and_charges",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Total Taxes and Charges (Company Currency)",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "other_charges_total",
- "oldfieldtype": "Currency",
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
- "width": "150px"
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "column_break_46",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "total_taxes_and_charges",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Total Taxes and Charges",
- "length": 0,
- "no_copy": 0,
- "options": "currency",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "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,
- "fetch_if_empty": 0,
- "fieldname": "loyalty_points_redemption",
- "fieldtype": "Section Break",
- "hidden": 1,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Loyalty Points Redemption",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "loyalty_points",
- "fieldtype": "Int",
- "hidden": 1,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Loyalty Points",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "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,
- "fetch_if_empty": 0,
- "fieldname": "loyalty_amount",
- "fieldtype": "Currency",
- "hidden": 1,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Loyalty Amount",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "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": 1,
- "collapsible_depends_on": "discount_amount",
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "section_break_48",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Additional Discount",
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "Grand Total",
- "fetch_if_empty": 0,
- "fieldname": "apply_discount_on",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Apply Additional Discount On",
- "length": 0,
- "no_copy": 0,
- "options": "\nGrand Total\nNet Total",
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "base_discount_amount",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Additional Discount Amount (Company Currency)",
- "length": 0,
- "no_copy": 0,
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "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,
- "fetch_if_empty": 0,
- "fieldname": "column_break_50",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
- "fetch_if_empty": 0,
- "fieldname": "additional_discount_percentage",
- "fieldtype": "Float",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Additional Discount Percentage",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
- "fetch_if_empty": 0,
- "fieldname": "discount_amount",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Additional Discount Amount",
- "length": 0,
- "no_copy": 0,
- "options": "currency",
- "permlevel": 0,
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "totals",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "",
- "length": 0,
- "no_copy": 0,
- "oldfieldtype": "Section Break",
- "options": "fa fa-money",
- "permlevel": 0,
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "base_grand_total",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Grand Total (Company Currency)",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "grand_total",
- "oldfieldtype": "Currency",
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
- "width": "150px"
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "base_rounding_adjustment",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Rounding Adjustment (Company Currency)",
- "length": 0,
- "no_copy": 1,
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "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,
- "fetch_if_empty": 0,
- "fieldname": "base_rounded_total",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Rounded Total (Company Currency)",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "rounded_total",
- "oldfieldtype": "Currency",
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
- "width": "150px"
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "In Words will be visible once you save the Sales Order.",
- "fetch_if_empty": 0,
- "fieldname": "base_in_words",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "In Words (Company Currency)",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "in_words",
- "oldfieldtype": "Data",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
- "width": "200px"
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "column_break3",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "oldfieldtype": "Column Break",
- "permlevel": 0,
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0,
- "width": "50%"
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "grand_total",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Grand Total",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "grand_total_export",
- "oldfieldtype": "Currency",
- "options": "currency",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
- "width": "150px"
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
- "fetch_if_empty": 0,
- "fieldname": "rounding_adjustment",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Rounding Adjustment",
- "length": 0,
- "no_copy": 1,
- "options": "currency",
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "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": 1,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "rounded_total",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Rounded Total",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "rounded_total_export",
- "oldfieldtype": "Currency",
- "options": "currency",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
- "width": "150px"
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "in_words",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "In Words",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "in_words_export",
- "oldfieldtype": "Data",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
- "width": "200px"
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "advance_paid",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Advance Paid",
- "length": 0,
- "no_copy": 1,
- "options": "party_account_currency",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "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": 1,
- "collapsible_depends_on": "packed_items",
- "columns": 0,
- "description": "",
- "fetch_if_empty": 0,
- "fieldname": "packing_list",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Packing List",
- "length": 0,
- "no_copy": 0,
- "oldfieldtype": "Section Break",
- "options": "fa fa-suitcase",
- "permlevel": 0,
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "packed_items",
- "fieldtype": "Table",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Packed Items",
- "length": 0,
- "no_copy": 0,
- "options": "Packed Item",
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "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,
- "collapsible_depends_on": "",
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "payment_schedule_section",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Payment Terms",
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "payment_terms_template",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Payment Terms Template",
- "length": 0,
- "no_copy": 0,
- "options": "Payment Terms Template",
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "payment_schedule",
- "fieldtype": "Table",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Payment Schedule",
- "length": 0,
- "no_copy": 1,
- "options": "Payment Schedule",
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "collapsible_depends_on": "terms",
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "terms_section_break",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Terms and Conditions",
- "length": 0,
- "no_copy": 0,
- "oldfieldtype": "Section Break",
- "options": "fa fa-legal",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "tc_name",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Terms",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "tc_name",
- "oldfieldtype": "Link",
- "options": "Terms and Conditions",
- "permlevel": 0,
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "terms",
- "fieldtype": "Text Editor",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Terms and Conditions Details",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "terms",
- "oldfieldtype": "Text Editor",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "collapsible_depends_on": "project",
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "more_info",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "More Information",
- "length": 0,
- "no_copy": 0,
- "oldfieldtype": "Section Break",
- "options": "fa fa-file-text",
- "permlevel": 0,
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "inter_company_order_reference",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Inter Company Order Reference",
- "length": 0,
- "no_copy": 0,
- "options": "Purchase Order",
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "Track this Sales Order against any Project",
- "fetch_if_empty": 0,
- "fieldname": "project",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Project",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "project",
- "oldfieldtype": "Link",
- "options": "Project",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "party_account_currency",
- "fieldtype": "Link",
- "hidden": 1,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Party Account Currency",
- "length": 0,
- "no_copy": 1,
- "options": "Currency",
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "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,
- "fetch_if_empty": 0,
- "fieldname": "column_break_77",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "source",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Source",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "source",
- "oldfieldtype": "Select",
- "options": "Lead Source",
- "permlevel": 0,
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
- "fetch_if_empty": 0,
- "fieldname": "campaign",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Campaign",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "campaign",
- "oldfieldtype": "Link",
- "options": "Campaign",
- "permlevel": 0,
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "printing_details",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Printing Details",
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "language",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Print Language",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "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": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "letter_head",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Letter Head",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "letter_head",
- "oldfieldtype": "Select",
- "options": "Letter Head",
- "permlevel": 0,
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "column_break4",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "oldfieldtype": "Column Break",
- "permlevel": 0,
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0,
- "width": "50%"
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "select_print_heading",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Print Heading",
- "length": 0,
- "no_copy": 1,
- "oldfieldname": "select_print_heading",
- "oldfieldtype": "Link",
- "options": "Print Heading",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 1,
- "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": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "group_same_items",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Group same items",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "section_break_78",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Billing and Delivery Status",
- "length": 0,
- "no_copy": 0,
- "oldfieldtype": "Column Break",
- "permlevel": 0,
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0,
- "width": "50%"
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "Draft",
- "fetch_if_empty": 0,
- "fieldname": "status",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Status",
- "length": 0,
- "no_copy": 1,
- "oldfieldname": "status",
- "oldfieldtype": "Select",
- "options": "\nDraft\nOn Hold\nTo Deliver and Bill\nTo Bill\nTo Deliver\nCompleted\nCancelled\nClosed",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 1,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
- "width": "100px"
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "delivery_status",
- "fieldtype": "Select",
- "hidden": 1,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 1,
- "label": "Delivery Status",
- "length": 0,
- "no_copy": 1,
- "options": "Not Delivered\nFully Delivered\nPartly Delivered\nClosed\nNot Applicable",
- "permlevel": 0,
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:!doc.__islocal",
- "description": "% of materials delivered against this Sales Order",
- "fetch_if_empty": 0,
- "fieldname": "per_delivered",
- "fieldtype": "Percent",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "% Delivered",
- "length": 0,
- "no_copy": 1,
- "oldfieldname": "per_delivered",
- "oldfieldtype": "Currency",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
- "width": "100px"
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "column_break_81",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:!doc.__islocal",
- "description": "% of materials billed against this Sales Order",
- "fetch_if_empty": 0,
- "fieldname": "per_billed",
- "fieldtype": "Percent",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "% Amount Billed",
- "length": 0,
- "no_copy": 1,
- "oldfieldname": "per_billed",
- "oldfieldtype": "Currency",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
- "width": "100px"
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
- "fetch_if_empty": 0,
- "fieldname": "billing_status",
- "fieldtype": "Select",
- "hidden": 1,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 1,
- "label": "Billing Status",
- "length": 0,
- "no_copy": 1,
- "options": "Not Billed\nFully Billed\nPartly Billed\nClosed",
- "permlevel": 0,
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "collapsible_depends_on": "commission_rate",
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "sales_team_section_break",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Commission",
- "length": 0,
- "no_copy": 0,
- "oldfieldtype": "Section Break",
- "options": "fa fa-group",
- "permlevel": 0,
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "sales_partner",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Sales Partner",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "sales_partner",
- "oldfieldtype": "Link",
- "options": "Sales Partner",
- "permlevel": 0,
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0,
- "width": "150px"
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "column_break7",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0,
- "width": "50%"
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "commission_rate",
- "fieldtype": "Float",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Commission Rate",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "commission_rate",
- "oldfieldtype": "Currency",
- "permlevel": 0,
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0,
- "width": "100px"
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "total_commission",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Total Commission",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "total_commission",
- "oldfieldtype": "Currency",
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "collapsible_depends_on": "sales_team",
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "section_break1",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Sales Team",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "sales_team",
- "fieldtype": "Table",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Sales Team1",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "sales_team",
- "oldfieldtype": "Table",
- "options": "Sales Team",
- "permlevel": 0,
- "print_hide": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "subscription_section",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Auto Repeat Section",
- "length": 0,
- "no_copy": 1,
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "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": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
- "description": "",
- "fetch_if_empty": 0,
- "fieldname": "from_date",
- "fieldtype": "Date",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "From Date",
- "length": 0,
- "no_copy": 1,
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
- "description": "",
- "fetch_if_empty": 0,
- "fieldname": "to_date",
- "fieldtype": "Date",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "To Date",
- "length": 0,
- "no_copy": 1,
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "column_break_108",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "auto_repeat",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Auto Repeat",
- "length": 0,
- "no_copy": 0,
- "options": "Auto Repeat",
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval: doc.auto_repeat",
- "fetch_if_empty": 0,
- "fieldname": "update_auto_repeat_reference",
- "fieldtype": "Button",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Update Auto Repeat Reference",
- "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,
- "translatable": 0,
- "unique": 0
- }
- ],
- "has_web_view": 0,
- "hide_toolbar": 0,
- "icon": "fa fa-file-text",
- "idx": 105,
- "in_create": 0,
- "is_submittable": 1,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2019-04-18 12:05:23.464968",
- "modified_by": "Administrator",
- "module": "Selling",
- "name": "Sales Order",
- "owner": "Administrator",
- "permissions": [
- {
- "amend": 1,
- "cancel": 1,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Sales User",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 1,
- "write": 1
- },
- {
- "amend": 1,
- "cancel": 1,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 1,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Sales Manager",
- "set_user_permissions": 1,
- "share": 1,
- "submit": 1,
- "write": 1
- },
- {
- "amend": 1,
- "cancel": 1,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Maintenance User",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 1,
- "write": 1
- },
- {
- "amend": 0,
- "cancel": 0,
- "create": 0,
- "delete": 0,
- "email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 0,
- "role": "Accounts User",
- "set_user_permissions": 0,
- "share": 0,
- "submit": 0,
- "write": 0
- },
- {
- "amend": 0,
- "cancel": 0,
- "create": 0,
- "delete": 0,
- "email": 0,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 0,
- "read": 1,
- "report": 1,
- "role": "Stock User",
- "set_user_permissions": 0,
- "share": 0,
- "submit": 0,
- "write": 0
- },
- {
- "amend": 0,
- "cancel": 0,
- "create": 0,
- "delete": 0,
- "email": 0,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 1,
- "print": 0,
- "read": 1,
- "report": 0,
- "role": "Sales Manager",
- "set_user_permissions": 0,
- "share": 0,
- "submit": 0,
- "write": 1
- }
- ],
- "quick_entry": 0,
- "read_only": 0,
- "search_fields": "status,transaction_date,customer,customer_name, territory,order_type,company",
- "show_name_in_global_search": 1,
- "sort_field": "modified",
- "sort_order": "DESC",
- "timeline_field": "customer",
- "title_field": "title",
- "track_changes": 1,
- "track_seen": 1,
- "track_views": 0
- }
\ No newline at end of file
+ "allow_import": 1,
+ "autoname": "naming_series:",
+ "creation": "2013-06-18 12:39:59",
+ "doctype": "DocType",
+ "document_type": "Document",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "customer_section",
+ "column_break0",
+ "title",
+ "naming_series",
+ "customer",
+ "customer_name",
+ "order_type",
+ "column_break1",
+ "amended_from",
+ "company",
+ "transaction_date",
+ "delivery_date",
+ "po_no",
+ "po_date",
+ "tax_id",
+ "contact_info",
+ "customer_address",
+ "address_display",
+ "contact_person",
+ "contact_display",
+ "contact_phone",
+ "contact_mobile",
+ "contact_email",
+ "company_address_display",
+ "company_address",
+ "col_break46",
+ "shipping_address_name",
+ "shipping_address",
+ "customer_group",
+ "territory",
+ "currency_and_price_list",
+ "currency",
+ "conversion_rate",
+ "column_break2",
+ "selling_price_list",
+ "price_list_currency",
+ "plc_conversion_rate",
+ "ignore_pricing_rule",
+ "sec_warehouse",
+ "set_warehouse",
+ "items_section",
+ "scan_barcode",
+ "items",
+ "pricing_rule_details",
+ "pricing_rules",
+ "section_break_31",
+ "column_break_33a",
+ "total_qty",
+ "base_total",
+ "base_net_total",
+ "column_break_33",
+ "total",
+ "net_total",
+ "total_net_weight",
+ "taxes_section",
+ "tax_category",
+ "column_break_38",
+ "shipping_rule",
+ "section_break_40",
+ "taxes_and_charges",
+ "taxes",
+ "sec_tax_breakup",
+ "other_charges_calculation",
+ "section_break_43",
+ "base_total_taxes_and_charges",
+ "column_break_46",
+ "total_taxes_and_charges",
+ "loyalty_points_redemption",
+ "loyalty_points",
+ "loyalty_amount",
+ "section_break_48",
+ "apply_discount_on",
+ "base_discount_amount",
+ "column_break_50",
+ "additional_discount_percentage",
+ "discount_amount",
+ "totals",
+ "base_grand_total",
+ "base_rounding_adjustment",
+ "base_rounded_total",
+ "base_in_words",
+ "column_break3",
+ "grand_total",
+ "rounding_adjustment",
+ "rounded_total",
+ "in_words",
+ "advance_paid",
+ "packing_list",
+ "packed_items",
+ "payment_schedule_section",
+ "payment_terms_template",
+ "payment_schedule",
+ "terms_section_break",
+ "tc_name",
+ "terms",
+ "more_info",
+ "inter_company_order_reference",
+ "project",
+ "party_account_currency",
+ "column_break_77",
+ "source",
+ "campaign",
+ "printing_details",
+ "language",
+ "letter_head",
+ "column_break4",
+ "select_print_heading",
+ "group_same_items",
+ "section_break_78",
+ "status",
+ "delivery_status",
+ "per_delivered",
+ "column_break_81",
+ "per_billed",
+ "billing_status",
+ "sales_team_section_break",
+ "sales_partner",
+ "column_break7",
+ "commission_rate",
+ "total_commission",
+ "section_break1",
+ "sales_team",
+ "subscription_section",
+ "from_date",
+ "to_date",
+ "column_break_108",
+ "auto_repeat",
+ "update_auto_repeat_reference"
+ ],
+ "fields": [
+ {
+ "fieldname": "customer_section",
+ "fieldtype": "Section Break",
+ "options": "fa fa-user"
+ },
+ {
+ "fieldname": "column_break0",
+ "fieldtype": "Column Break",
+ "oldfieldtype": "Column Break",
+ "width": "50%"
+ },
+ {
+ "allow_on_submit": 1,
+ "default": "{customer_name}",
+ "fieldname": "title",
+ "fieldtype": "Data",
+ "hidden": 1,
+ "label": "Title",
+ "no_copy": 1,
+ "print_hide": 1
+ },
+ {
+ "fieldname": "naming_series",
+ "fieldtype": "Select",
+ "label": "Series",
+ "no_copy": 1,
+ "oldfieldname": "naming_series",
+ "oldfieldtype": "Select",
+ "options": "SAL-ORD-.YYYY.-",
+ "print_hide": 1,
+ "reqd": 1,
+ "set_only_once": 1
+ },
+ {
+ "bold": 1,
+ "fieldname": "customer",
+ "fieldtype": "Link",
+ "in_global_search": 1,
+ "in_standard_filter": 1,
+ "label": "Customer",
+ "oldfieldname": "customer",
+ "oldfieldtype": "Link",
+ "options": "Customer",
+ "print_hide": 1,
+ "reqd": 1,
+ "search_index": 1
+ },
+ {
+ "bold": 1,
+ "fetch_from": "customer.customer_name",
+ "fieldname": "customer_name",
+ "fieldtype": "Data",
+ "in_global_search": 1,
+ "label": "Customer Name",
+ "read_only": 1
+ },
+ {
+ "default": "Sales",
+ "fieldname": "order_type",
+ "fieldtype": "Select",
+ "label": "Order Type",
+ "oldfieldname": "order_type",
+ "oldfieldtype": "Select",
+ "options": "\nSales\nMaintenance\nShopping Cart",
+ "print_hide": 1,
+ "reqd": 1
+ },
+ {
+ "fieldname": "column_break1",
+ "fieldtype": "Column Break",
+ "oldfieldtype": "Column Break",
+ "width": "50%"
+ },
+ {
+ "fieldname": "amended_from",
+ "fieldtype": "Link",
+ "hidden": 1,
+ "ignore_user_permissions": 1,
+ "label": "Amended From",
+ "no_copy": 1,
+ "oldfieldname": "amended_from",
+ "oldfieldtype": "Data",
+ "options": "Sales Order",
+ "print_hide": 1,
+ "read_only": 1,
+ "width": "150px"
+ },
+ {
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "in_standard_filter": 1,
+ "label": "Company",
+ "oldfieldname": "company",
+ "oldfieldtype": "Link",
+ "options": "Company",
+ "print_hide": 1,
+ "remember_last_selected_value": 1,
+ "reqd": 1,
+ "width": "150px"
+ },
+ {
+ "default": "Today",
+ "fieldname": "transaction_date",
+ "fieldtype": "Date",
+ "in_standard_filter": 1,
+ "label": "Date",
+ "no_copy": 1,
+ "oldfieldname": "transaction_date",
+ "oldfieldtype": "Date",
+ "reqd": 1,
+ "search_index": 1,
+ "width": "160px"
+ },
+ {
+ "allow_on_submit": 1,
+ "fieldname": "delivery_date",
+ "fieldtype": "Date",
+ "in_list_view": 1,
+ "label": "Delivery Date",
+ "no_copy": 1
+ },
+ {
+ "allow_on_submit": 1,
+ "fieldname": "po_no",
+ "fieldtype": "Data",
+ "label": "Customer's Purchase Order",
+ "oldfieldname": "po_no",
+ "oldfieldtype": "Data",
+ "width": "100px"
+ },
+ {
+ "allow_on_submit": 1,
+ "depends_on": "eval:doc.po_no",
+ "fieldname": "po_date",
+ "fieldtype": "Date",
+ "label": "Customer's Purchase Order Date",
+ "oldfieldname": "po_date",
+ "oldfieldtype": "Date",
+ "width": "100px"
+ },
+ {
+ "fieldname": "tax_id",
+ "fieldtype": "Data",
+ "label": "Tax Id",
+ "read_only": 1,
+ "width": "100px"
+ },
+ {
+ "collapsible": 1,
+ "depends_on": "customer",
+ "fieldname": "contact_info",
+ "fieldtype": "Section Break",
+ "label": "Address and Contact",
+ "options": "fa fa-bullhorn"
+ },
+ {
+ "allow_on_submit": 1,
+ "fieldname": "customer_address",
+ "fieldtype": "Link",
+ "label": "Customer Address",
+ "options": "Address",
+ "print_hide": 1
+ },
+ {
+ "allow_on_submit": 1,
+ "fieldname": "address_display",
+ "fieldtype": "Small Text",
+ "label": "Address",
+ "read_only": 1
+ },
+ {
+ "fieldname": "contact_person",
+ "fieldtype": "Link",
+ "label": "Contact Person",
+ "options": "Contact",
+ "print_hide": 1
+ },
+ {
+ "fieldname": "contact_display",
+ "fieldtype": "Small Text",
+ "in_global_search": 1,
+ "label": "Contact",
+ "read_only": 1
+ },
+ {
+ "fieldname": "contact_mobile",
+ "fieldtype": "Small Text",
+ "label": "Mobile No",
+ "read_only": 1
+ },
+ {
+ "fieldname": "contact_email",
+ "fieldtype": "Data",
+ "hidden": 1,
+ "label": "Contact Email",
+ "options": "Email",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "fieldname": "company_address_display",
+ "fieldtype": "Small Text",
+ "read_only": 1
+ },
+ {
+ "fieldname": "company_address",
+ "fieldtype": "Link",
+ "label": "Company Address",
+ "options": "Address"
+ },
+ {
+ "fieldname": "col_break46",
+ "fieldtype": "Column Break",
+ "width": "50%"
+ },
+ {
+ "allow_on_submit": 1,
+ "fieldname": "shipping_address_name",
+ "fieldtype": "Link",
+ "label": "Shipping Address Name",
+ "options": "Address",
+ "print_hide": 1
+ },
+ {
+ "allow_on_submit": 1,
+ "fieldname": "shipping_address",
+ "fieldtype": "Small Text",
+ "label": "Shipping Address",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "fieldname": "customer_group",
+ "fieldtype": "Link",
+ "hidden": 1,
+ "label": "Customer Group",
+ "options": "Customer Group",
+ "print_hide": 1
+ },
+ {
+ "fieldname": "territory",
+ "fieldtype": "Link",
+ "label": "Territory",
+ "options": "Territory",
+ "print_hide": 1
+ },
+ {
+ "collapsible": 1,
+ "fieldname": "currency_and_price_list",
+ "fieldtype": "Section Break",
+ "label": "Currency and Price List",
+ "options": "fa fa-tag",
+ "print_hide": 1
+ },
+ {
+ "fieldname": "currency",
+ "fieldtype": "Link",
+ "label": "Currency",
+ "oldfieldname": "currency",
+ "oldfieldtype": "Select",
+ "options": "Currency",
+ "print_hide": 1,
+ "reqd": 1,
+ "width": "100px"
+ },
+ {
+ "description": "Rate at which customer's currency is converted to company's base currency",
+ "fieldname": "conversion_rate",
+ "fieldtype": "Float",
+ "label": "Exchange Rate",
+ "oldfieldname": "conversion_rate",
+ "oldfieldtype": "Currency",
+ "precision": "9",
+ "print_hide": 1,
+ "reqd": 1,
+ "width": "100px"
+ },
+ {
+ "fieldname": "column_break2",
+ "fieldtype": "Column Break",
+ "width": "50%"
+ },
+ {
+ "fieldname": "selling_price_list",
+ "fieldtype": "Link",
+ "label": "Price List",
+ "oldfieldname": "price_list_name",
+ "oldfieldtype": "Select",
+ "options": "Price List",
+ "print_hide": 1,
+ "reqd": 1,
+ "width": "100px"
+ },
+ {
+ "fieldname": "price_list_currency",
+ "fieldtype": "Link",
+ "label": "Price List Currency",
+ "options": "Currency",
+ "print_hide": 1,
+ "read_only": 1,
+ "reqd": 1
+ },
+ {
+ "description": "Rate at which Price list currency is converted to company's base currency",
+ "fieldname": "plc_conversion_rate",
+ "fieldtype": "Float",
+ "label": "Price List Exchange Rate",
+ "precision": "9",
+ "print_hide": 1,
+ "reqd": 1
+ },
+ {
+ "default": "0",
+ "fieldname": "ignore_pricing_rule",
+ "fieldtype": "Check",
+ "label": "Ignore Pricing Rule",
+ "no_copy": 1,
+ "permlevel": 1,
+ "print_hide": 1
+ },
+ {
+ "fieldname": "sec_warehouse",
+ "fieldtype": "Section Break"
+ },
+ {
+ "fieldname": "set_warehouse",
+ "fieldtype": "Link",
+ "label": "Set Source Warehouse",
+ "options": "Warehouse",
+ "print_hide": 1
+ },
+ {
+ "fieldname": "items_section",
+ "fieldtype": "Section Break",
+ "oldfieldtype": "Section Break",
+ "options": "fa fa-shopping-cart"
+ },
+ {
+ "fieldname": "scan_barcode",
+ "fieldtype": "Data",
+ "label": "Scan Barcode"
+ },
+ {
+ "allow_bulk_edit": 1,
+ "fieldname": "items",
+ "fieldtype": "Table",
+ "label": "Items",
+ "oldfieldname": "sales_order_details",
+ "oldfieldtype": "Table",
+ "options": "Sales Order Item",
+ "reqd": 1
+ },
+ {
+ "fieldname": "pricing_rule_details",
+ "fieldtype": "Section Break",
+ "label": "Pricing Rules"
+ },
+ {
+ "fieldname": "pricing_rules",
+ "fieldtype": "Table",
+ "label": "Pricing Rule Detail",
+ "options": "Pricing Rule Detail",
+ "read_only": 1
+ },
+ {
+ "fieldname": "section_break_31",
+ "fieldtype": "Section Break"
+ },
+ {
+ "fieldname": "column_break_33a",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "total_qty",
+ "fieldtype": "Float",
+ "label": "Total Quantity",
+ "read_only": 1
+ },
+ {
+ "fieldname": "base_total",
+ "fieldtype": "Currency",
+ "label": "Total (Company Currency)",
+ "options": "Company:company:default_currency",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "fieldname": "base_net_total",
+ "fieldtype": "Currency",
+ "label": "Net Total (Company Currency)",
+ "oldfieldname": "net_total",
+ "oldfieldtype": "Currency",
+ "options": "Company:company:default_currency",
+ "print_hide": 1,
+ "read_only": 1,
+ "width": "150px"
+ },
+ {
+ "fieldname": "column_break_33",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "total",
+ "fieldtype": "Currency",
+ "label": "Total",
+ "options": "currency",
+ "read_only": 1
+ },
+ {
+ "fieldname": "net_total",
+ "fieldtype": "Currency",
+ "label": "Net Total",
+ "options": "currency",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "fieldname": "total_net_weight",
+ "fieldtype": "Float",
+ "label": "Total Net Weight",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "fieldname": "taxes_section",
+ "fieldtype": "Section Break",
+ "label": "Taxes and Charges",
+ "oldfieldtype": "Section Break",
+ "options": "fa fa-money"
+ },
+ {
+ "fieldname": "tax_category",
+ "fieldtype": "Link",
+ "label": "Tax Category",
+ "options": "Tax Category",
+ "print_hide": 1
+ },
+ {
+ "fieldname": "column_break_38",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "shipping_rule",
+ "fieldtype": "Link",
+ "label": "Shipping Rule",
+ "oldfieldtype": "Button",
+ "options": "Shipping Rule",
+ "print_hide": 1
+ },
+ {
+ "fieldname": "section_break_40",
+ "fieldtype": "Section Break"
+ },
+ {
+ "fieldname": "taxes_and_charges",
+ "fieldtype": "Link",
+ "label": "Sales Taxes and Charges Template",
+ "oldfieldname": "charge",
+ "oldfieldtype": "Link",
+ "options": "Sales Taxes and Charges Template",
+ "print_hide": 1
+ },
+ {
+ "fieldname": "taxes",
+ "fieldtype": "Table",
+ "label": "Sales Taxes and Charges",
+ "oldfieldname": "other_charges",
+ "oldfieldtype": "Table",
+ "options": "Sales Taxes and Charges"
+ },
+ {
+ "collapsible": 1,
+ "fieldname": "sec_tax_breakup",
+ "fieldtype": "Section Break",
+ "label": "Tax Breakup"
+ },
+ {
+ "fieldname": "other_charges_calculation",
+ "fieldtype": "Text",
+ "label": "Taxes and Charges Calculation",
+ "no_copy": 1,
+ "oldfieldtype": "HTML",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "fieldname": "section_break_43",
+ "fieldtype": "Section Break"
+ },
+ {
+ "fieldname": "base_total_taxes_and_charges",
+ "fieldtype": "Currency",
+ "label": "Total Taxes and Charges (Company Currency)",
+ "oldfieldname": "other_charges_total",
+ "oldfieldtype": "Currency",
+ "options": "Company:company:default_currency",
+ "print_hide": 1,
+ "read_only": 1,
+ "width": "150px"
+ },
+ {
+ "fieldname": "column_break_46",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "total_taxes_and_charges",
+ "fieldtype": "Currency",
+ "label": "Total Taxes and Charges",
+ "options": "currency",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "fieldname": "loyalty_points_redemption",
+ "fieldtype": "Section Break",
+ "hidden": 1,
+ "label": "Loyalty Points Redemption",
+ "print_hide": 1
+ },
+ {
+ "fieldname": "loyalty_points",
+ "fieldtype": "Int",
+ "hidden": 1,
+ "label": "Loyalty Points",
+ "read_only": 1
+ },
+ {
+ "fieldname": "loyalty_amount",
+ "fieldtype": "Currency",
+ "hidden": 1,
+ "label": "Loyalty Amount",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "collapsible": 1,
+ "collapsible_depends_on": "discount_amount",
+ "fieldname": "section_break_48",
+ "fieldtype": "Section Break",
+ "label": "Additional Discount"
+ },
+ {
+ "default": "Grand Total",
+ "fieldname": "apply_discount_on",
+ "fieldtype": "Select",
+ "label": "Apply Additional Discount On",
+ "options": "\nGrand Total\nNet Total",
+ "print_hide": 1
+ },
+ {
+ "fieldname": "base_discount_amount",
+ "fieldtype": "Currency",
+ "label": "Additional Discount Amount (Company Currency)",
+ "options": "Company:company:default_currency",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "fieldname": "column_break_50",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "additional_discount_percentage",
+ "fieldtype": "Float",
+ "label": "Additional Discount Percentage",
+ "print_hide": 1
+ },
+ {
+ "fieldname": "discount_amount",
+ "fieldtype": "Currency",
+ "label": "Additional Discount Amount",
+ "options": "currency",
+ "print_hide": 1
+ },
+ {
+ "fieldname": "totals",
+ "fieldtype": "Section Break",
+ "oldfieldtype": "Section Break",
+ "options": "fa fa-money",
+ "print_hide": 1
+ },
+ {
+ "fieldname": "base_grand_total",
+ "fieldtype": "Currency",
+ "label": "Grand Total (Company Currency)",
+ "oldfieldname": "grand_total",
+ "oldfieldtype": "Currency",
+ "options": "Company:company:default_currency",
+ "print_hide": 1,
+ "read_only": 1,
+ "width": "150px"
+ },
+ {
+ "fieldname": "base_rounding_adjustment",
+ "fieldtype": "Currency",
+ "label": "Rounding Adjustment (Company Currency)",
+ "no_copy": 1,
+ "options": "Company:company:default_currency",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "fieldname": "base_rounded_total",
+ "fieldtype": "Currency",
+ "label": "Rounded Total (Company Currency)",
+ "oldfieldname": "rounded_total",
+ "oldfieldtype": "Currency",
+ "options": "Company:company:default_currency",
+ "print_hide": 1,
+ "read_only": 1,
+ "width": "150px"
+ },
+ {
+ "description": "In Words will be visible once you save the Sales Order.",
+ "fieldname": "base_in_words",
+ "fieldtype": "Data",
+ "label": "In Words (Company Currency)",
+ "oldfieldname": "in_words",
+ "oldfieldtype": "Data",
+ "print_hide": 1,
+ "read_only": 1,
+ "width": "200px"
+ },
+ {
+ "fieldname": "column_break3",
+ "fieldtype": "Column Break",
+ "oldfieldtype": "Column Break",
+ "print_hide": 1,
+ "width": "50%"
+ },
+ {
+ "fieldname": "grand_total",
+ "fieldtype": "Currency",
+ "in_list_view": 1,
+ "label": "Grand Total",
+ "oldfieldname": "grand_total_export",
+ "oldfieldtype": "Currency",
+ "options": "currency",
+ "read_only": 1,
+ "width": "150px"
+ },
+ {
+ "fieldname": "rounding_adjustment",
+ "fieldtype": "Currency",
+ "label": "Rounding Adjustment",
+ "no_copy": 1,
+ "options": "currency",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "bold": 1,
+ "fieldname": "rounded_total",
+ "fieldtype": "Currency",
+ "label": "Rounded Total",
+ "oldfieldname": "rounded_total_export",
+ "oldfieldtype": "Currency",
+ "options": "currency",
+ "read_only": 1,
+ "width": "150px"
+ },
+ {
+ "fieldname": "in_words",
+ "fieldtype": "Data",
+ "label": "In Words",
+ "oldfieldname": "in_words_export",
+ "oldfieldtype": "Data",
+ "print_hide": 1,
+ "read_only": 1,
+ "width": "200px"
+ },
+ {
+ "fieldname": "advance_paid",
+ "fieldtype": "Currency",
+ "label": "Advance Paid",
+ "no_copy": 1,
+ "options": "party_account_currency",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "collapsible": 1,
+ "collapsible_depends_on": "packed_items",
+ "fieldname": "packing_list",
+ "fieldtype": "Section Break",
+ "label": "Packing List",
+ "oldfieldtype": "Section Break",
+ "options": "fa fa-suitcase",
+ "print_hide": 1
+ },
+ {
+ "fieldname": "packed_items",
+ "fieldtype": "Table",
+ "label": "Packed Items",
+ "options": "Packed Item",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "fieldname": "payment_schedule_section",
+ "fieldtype": "Section Break",
+ "label": "Payment Terms"
+ },
+ {
+ "fieldname": "payment_terms_template",
+ "fieldtype": "Link",
+ "label": "Payment Terms Template",
+ "options": "Payment Terms Template",
+ "print_hide": 1
+ },
+ {
+ "fieldname": "payment_schedule",
+ "fieldtype": "Table",
+ "label": "Payment Schedule",
+ "no_copy": 1,
+ "options": "Payment Schedule",
+ "print_hide": 1
+ },
+ {
+ "collapsible": 1,
+ "collapsible_depends_on": "terms",
+ "fieldname": "terms_section_break",
+ "fieldtype": "Section Break",
+ "label": "Terms and Conditions",
+ "oldfieldtype": "Section Break",
+ "options": "fa fa-legal"
+ },
+ {
+ "fieldname": "tc_name",
+ "fieldtype": "Link",
+ "label": "Terms",
+ "oldfieldname": "tc_name",
+ "oldfieldtype": "Link",
+ "options": "Terms and Conditions",
+ "print_hide": 1
+ },
+ {
+ "fieldname": "terms",
+ "fieldtype": "Text Editor",
+ "label": "Terms and Conditions Details",
+ "oldfieldname": "terms",
+ "oldfieldtype": "Text Editor"
+ },
+ {
+ "collapsible": 1,
+ "collapsible_depends_on": "project",
+ "fieldname": "more_info",
+ "fieldtype": "Section Break",
+ "label": "More Information",
+ "oldfieldtype": "Section Break",
+ "options": "fa fa-file-text",
+ "print_hide": 1
+ },
+ {
+ "fieldname": "inter_company_order_reference",
+ "fieldtype": "Link",
+ "label": "Inter Company Order Reference",
+ "options": "Purchase Order"
+ },
+ {
+ "description": "Track this Sales Order against any Project",
+ "fieldname": "project",
+ "fieldtype": "Link",
+ "label": "Project",
+ "oldfieldname": "project",
+ "oldfieldtype": "Link",
+ "options": "Project"
+ },
+ {
+ "fieldname": "party_account_currency",
+ "fieldtype": "Link",
+ "hidden": 1,
+ "label": "Party Account Currency",
+ "no_copy": 1,
+ "options": "Currency",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "fieldname": "column_break_77",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "source",
+ "fieldtype": "Link",
+ "label": "Source",
+ "oldfieldname": "source",
+ "oldfieldtype": "Select",
+ "options": "Lead Source",
+ "print_hide": 1
+ },
+ {
+ "fieldname": "campaign",
+ "fieldtype": "Link",
+ "label": "Campaign",
+ "oldfieldname": "campaign",
+ "oldfieldtype": "Link",
+ "options": "Campaign",
+ "print_hide": 1
+ },
+ {
+ "collapsible": 1,
+ "fieldname": "printing_details",
+ "fieldtype": "Section Break",
+ "label": "Printing Details"
+ },
+ {
+ "fieldname": "language",
+ "fieldtype": "Data",
+ "label": "Print Language",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "allow_on_submit": 1,
+ "fieldname": "letter_head",
+ "fieldtype": "Link",
+ "label": "Letter Head",
+ "oldfieldname": "letter_head",
+ "oldfieldtype": "Select",
+ "options": "Letter Head",
+ "print_hide": 1
+ },
+ {
+ "fieldname": "column_break4",
+ "fieldtype": "Column Break",
+ "oldfieldtype": "Column Break",
+ "print_hide": 1,
+ "width": "50%"
+ },
+ {
+ "allow_on_submit": 1,
+ "fieldname": "select_print_heading",
+ "fieldtype": "Link",
+ "label": "Print Heading",
+ "no_copy": 1,
+ "oldfieldname": "select_print_heading",
+ "oldfieldtype": "Link",
+ "options": "Print Heading",
+ "print_hide": 1,
+ "report_hide": 1
+ },
+ {
+ "allow_on_submit": 1,
+ "default": "0",
+ "fieldname": "group_same_items",
+ "fieldtype": "Check",
+ "label": "Group same items",
+ "print_hide": 1
+ },
+ {
+ "collapsible": 1,
+ "fieldname": "section_break_78",
+ "fieldtype": "Section Break",
+ "label": "Billing and Delivery Status",
+ "oldfieldtype": "Column Break",
+ "print_hide": 1,
+ "width": "50%"
+ },
+ {
+ "default": "Draft",
+ "fieldname": "status",
+ "fieldtype": "Select",
+ "in_list_view": 1,
+ "label": "Status",
+ "no_copy": 1,
+ "oldfieldname": "status",
+ "oldfieldtype": "Select",
+ "options": "\nDraft\nOn Hold\nTo Deliver and Bill\nTo Bill\nTo Deliver\nCompleted\nCancelled\nClosed",
+ "print_hide": 1,
+ "read_only": 1,
+ "reqd": 1,
+ "search_index": 1,
+ "width": "100px"
+ },
+ {
+ "fieldname": "delivery_status",
+ "fieldtype": "Select",
+ "hidden": 1,
+ "in_standard_filter": 1,
+ "label": "Delivery Status",
+ "no_copy": 1,
+ "options": "Not Delivered\nFully Delivered\nPartly Delivered\nClosed\nNot Applicable",
+ "print_hide": 1
+ },
+ {
+ "depends_on": "eval:!doc.__islocal",
+ "description": "% of materials delivered against this Sales Order",
+ "fieldname": "per_delivered",
+ "fieldtype": "Percent",
+ "in_list_view": 1,
+ "label": "% Delivered",
+ "no_copy": 1,
+ "oldfieldname": "per_delivered",
+ "oldfieldtype": "Currency",
+ "print_hide": 1,
+ "read_only": 1,
+ "width": "100px"
+ },
+ {
+ "fieldname": "column_break_81",
+ "fieldtype": "Column Break"
+ },
+ {
+ "depends_on": "eval:!doc.__islocal",
+ "description": "% of materials billed against this Sales Order",
+ "fieldname": "per_billed",
+ "fieldtype": "Percent",
+ "in_list_view": 1,
+ "label": "% Amount Billed",
+ "no_copy": 1,
+ "oldfieldname": "per_billed",
+ "oldfieldtype": "Currency",
+ "print_hide": 1,
+ "read_only": 1,
+ "width": "100px"
+ },
+ {
+ "fieldname": "billing_status",
+ "fieldtype": "Select",
+ "hidden": 1,
+ "in_standard_filter": 1,
+ "label": "Billing Status",
+ "no_copy": 1,
+ "options": "Not Billed\nFully Billed\nPartly Billed\nClosed",
+ "print_hide": 1
+ },
+ {
+ "collapsible": 1,
+ "collapsible_depends_on": "commission_rate",
+ "fieldname": "sales_team_section_break",
+ "fieldtype": "Section Break",
+ "label": "Commission",
+ "oldfieldtype": "Section Break",
+ "options": "fa fa-group",
+ "print_hide": 1
+ },
+ {
+ "fieldname": "sales_partner",
+ "fieldtype": "Link",
+ "label": "Sales Partner",
+ "oldfieldname": "sales_partner",
+ "oldfieldtype": "Link",
+ "options": "Sales Partner",
+ "print_hide": 1,
+ "width": "150px"
+ },
+ {
+ "fieldname": "column_break7",
+ "fieldtype": "Column Break",
+ "print_hide": 1,
+ "width": "50%"
+ },
+ {
+ "fieldname": "commission_rate",
+ "fieldtype": "Float",
+ "label": "Commission Rate",
+ "oldfieldname": "commission_rate",
+ "oldfieldtype": "Currency",
+ "print_hide": 1,
+ "width": "100px"
+ },
+ {
+ "fieldname": "total_commission",
+ "fieldtype": "Currency",
+ "label": "Total Commission",
+ "oldfieldname": "total_commission",
+ "oldfieldtype": "Currency",
+ "options": "Company:company:default_currency",
+ "print_hide": 1
+ },
+ {
+ "collapsible": 1,
+ "collapsible_depends_on": "sales_team",
+ "fieldname": "section_break1",
+ "fieldtype": "Section Break",
+ "label": "Sales Team",
+ "print_hide": 1
+ },
+ {
+ "allow_on_submit": 1,
+ "fieldname": "sales_team",
+ "fieldtype": "Table",
+ "label": "Sales Team1",
+ "oldfieldname": "sales_team",
+ "oldfieldtype": "Table",
+ "options": "Sales Team",
+ "print_hide": 1
+ },
+ {
+ "allow_on_submit": 1,
+ "fieldname": "subscription_section",
+ "fieldtype": "Section Break",
+ "label": "Auto Repeat Section",
+ "no_copy": 1,
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "allow_on_submit": 1,
+ "fieldname": "from_date",
+ "fieldtype": "Date",
+ "label": "From Date",
+ "no_copy": 1
+ },
+ {
+ "allow_on_submit": 1,
+ "fieldname": "to_date",
+ "fieldtype": "Date",
+ "label": "To Date",
+ "no_copy": 1
+ },
+ {
+ "fieldname": "column_break_108",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "auto_repeat",
+ "fieldtype": "Link",
+ "label": "Auto Repeat",
+ "options": "Auto Repeat"
+ },
+ {
+ "allow_on_submit": 1,
+ "depends_on": "eval: doc.auto_repeat",
+ "fieldname": "update_auto_repeat_reference",
+ "fieldtype": "Button",
+ "label": "Update Auto Repeat Reference"
+ },
+ {
+ "fieldname": "contact_phone",
+ "fieldtype": "Data",
+ "label": "Phone",
+ "read_only": 1
+ }
+ ],
+ "icon": "fa fa-file-text",
+ "idx": 105,
+ "is_submittable": 1,
+ "modified": "2019-09-12 02:13:56.308839",
+ "modified_by": "Administrator",
+ "module": "Selling",
+ "name": "Sales Order",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "amend": 1,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Sales User",
+ "share": 1,
+ "submit": 1,
+ "write": 1
+ },
+ {
+ "amend": 1,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "import": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Sales Manager",
+ "set_user_permissions": 1,
+ "share": 1,
+ "submit": 1,
+ "write": 1
+ },
+ {
+ "amend": 1,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Maintenance User",
+ "share": 1,
+ "submit": 1,
+ "write": 1
+ },
+ {
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "role": "Accounts User"
+ },
+ {
+ "read": 1,
+ "report": 1,
+ "role": "Stock User"
+ },
+ {
+ "permlevel": 1,
+ "read": 1,
+ "role": "Sales Manager",
+ "write": 1
+ }
+ ],
+ "search_fields": "status,transaction_date,customer,customer_name, territory,order_type,company",
+ "show_name_in_global_search": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "timeline_field": "customer",
+ "title_field": "title",
+ "track_changes": 1,
+ "track_seen": 1
+}
\ No newline at end of file
From cdce6c746f8625681aba750e3a7af25eac38233e Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Thu, 12 Sep 2019 22:04:49 +0530
Subject: [PATCH 476/484] fix: Make -> Create
---
erpnext/public/js/call_popup/call_popup.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/erpnext/public/js/call_popup/call_popup.js b/erpnext/public/js/call_popup/call_popup.js
index 5278b322a4..5e4d4a585f 100644
--- a/erpnext/public/js/call_popup/call_popup.js
+++ b/erpnext/public/js/call_popup/call_popup.js
@@ -28,12 +28,12 @@ class CallPopup {
'depends_on': () => this.call_log.lead
}, {
'fieldtype': 'Button',
- 'label': __('Make New Contact'),
+ 'label': __('Create New Contact'),
'click': () => frappe.new_doc('Contact', { 'mobile_no': this.caller_number }),
'depends_on': () => !this.get_caller_name()
}, {
'fieldtype': 'Button',
- 'label': __('Make New Lead'),
+ 'label': __('Create New Lead'),
'click': () => frappe.new_doc('Lead', { 'mobile_no': this.caller_number }),
'depends_on': () => !this.get_caller_name()
}, {
From 72949e7f7387f0db3d39bd20a5749065d7f4ee4b Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Fri, 13 Sep 2019 11:05:40 +0530
Subject: [PATCH 477/484] fix: share transfer validations for journal entry
(#19018)
* fix share transfer validations for journal entry
* fix: share transfer test
* fix: tests
---
.../doctype/share_transfer/share_transfer.py | 6 +
.../share_transfer/test_share_transfer.py | 158 ++++++++++--------
2 files changed, 90 insertions(+), 74 deletions(-)
diff --git a/erpnext/accounts/doctype/share_transfer/share_transfer.py b/erpnext/accounts/doctype/share_transfer/share_transfer.py
index 1a1f036278..e95c69413f 100644
--- a/erpnext/accounts/doctype/share_transfer/share_transfer.py
+++ b/erpnext/accounts/doctype/share_transfer/share_transfer.py
@@ -86,17 +86,23 @@ class ShareTransfer(Document):
frappe.throw(_('The field From Shareholder cannot be blank'))
if self.from_folio_no is None or self.from_folio_no is '':
self.to_folio_no = self.autoname_folio(self.to_shareholder)
+ if self.asset_account is None:
+ frappe.throw(_('The field Asset Account cannot be blank'))
elif (self.transfer_type == 'Issue'):
self.from_shareholder = ''
if self.to_shareholder is None or self.to_shareholder == '':
frappe.throw(_('The field To Shareholder cannot be blank'))
if self.to_folio_no is None or self.to_folio_no is '':
self.to_folio_no = self.autoname_folio(self.to_shareholder)
+ if self.asset_account is None:
+ frappe.throw(_('The field Asset Account cannot be blank'))
else:
if self.from_shareholder is None or self.to_shareholder is None:
frappe.throw(_('The fields From Shareholder and To Shareholder cannot be blank'))
if self.to_folio_no is None or self.to_folio_no is '':
self.to_folio_no = self.autoname_folio(self.to_shareholder)
+ if self.equity_or_liability_account is None:
+ frappe.throw(_('The field Equity/Liability Account cannot be blank'))
if self.from_shareholder == self.to_shareholder:
frappe.throw(_('The seller and the buyer cannot be the same'))
if self.no_of_shares != self.to_no - self.from_no + 1:
diff --git a/erpnext/accounts/doctype/share_transfer/test_share_transfer.py b/erpnext/accounts/doctype/share_transfer/test_share_transfer.py
index f1cf31b820..910dfd05da 100644
--- a/erpnext/accounts/doctype/share_transfer/test_share_transfer.py
+++ b/erpnext/accounts/doctype/share_transfer/test_share_transfer.py
@@ -15,67 +15,74 @@ class TestShareTransfer(unittest.TestCase):
frappe.db.sql("delete from `tabShare Balance`")
share_transfers = [
{
- "doctype" : "Share Transfer",
- "transfer_type" : "Issue",
- "date" : "2018-01-01",
- "to_shareholder" : "SH-00001",
- "share_type" : "Equity",
- "from_no" : 1,
- "to_no" : 500,
- "no_of_shares" : 500,
- "rate" : 10,
- "company" : "_Test Company"
+ "doctype" : "Share Transfer",
+ "transfer_type" : "Issue",
+ "date" : "2018-01-01",
+ "to_shareholder" : "SH-00001",
+ "share_type" : "Equity",
+ "from_no" : 1,
+ "to_no" : 500,
+ "no_of_shares" : 500,
+ "rate" : 10,
+ "company" : "_Test Company",
+ "asset_account" : "Cash - _TC",
+ "equity_or_liability_account": "Creditors - _TC"
},
{
- "doctype" : "Share Transfer",
- "transfer_type" : "Transfer",
- "date" : "2018-01-02",
- "from_shareholder" : "SH-00001",
- "to_shareholder" : "SH-00002",
- "share_type" : "Equity",
- "from_no" : 101,
- "to_no" : 200,
- "no_of_shares" : 100,
- "rate" : 15,
- "company" : "_Test Company"
+ "doctype" : "Share Transfer",
+ "transfer_type" : "Transfer",
+ "date" : "2018-01-02",
+ "from_shareholder" : "SH-00001",
+ "to_shareholder" : "SH-00002",
+ "share_type" : "Equity",
+ "from_no" : 101,
+ "to_no" : 200,
+ "no_of_shares" : 100,
+ "rate" : 15,
+ "company" : "_Test Company",
+ "equity_or_liability_account": "Creditors - _TC"
},
{
- "doctype" : "Share Transfer",
- "transfer_type" : "Transfer",
- "date" : "2018-01-03",
- "from_shareholder" : "SH-00001",
- "to_shareholder" : "SH-00003",
- "share_type" : "Equity",
- "from_no" : 201,
- "to_no" : 500,
- "no_of_shares" : 300,
- "rate" : 20,
- "company" : "_Test Company"
+ "doctype" : "Share Transfer",
+ "transfer_type" : "Transfer",
+ "date" : "2018-01-03",
+ "from_shareholder" : "SH-00001",
+ "to_shareholder" : "SH-00003",
+ "share_type" : "Equity",
+ "from_no" : 201,
+ "to_no" : 500,
+ "no_of_shares" : 300,
+ "rate" : 20,
+ "company" : "_Test Company",
+ "equity_or_liability_account": "Creditors - _TC"
},
{
- "doctype" : "Share Transfer",
- "transfer_type" : "Transfer",
- "date" : "2018-01-04",
- "from_shareholder" : "SH-00003",
- "to_shareholder" : "SH-00002",
- "share_type" : "Equity",
- "from_no" : 201,
- "to_no" : 400,
- "no_of_shares" : 200,
- "rate" : 15,
- "company" : "_Test Company"
+ "doctype" : "Share Transfer",
+ "transfer_type" : "Transfer",
+ "date" : "2018-01-04",
+ "from_shareholder" : "SH-00003",
+ "to_shareholder" : "SH-00002",
+ "share_type" : "Equity",
+ "from_no" : 201,
+ "to_no" : 400,
+ "no_of_shares" : 200,
+ "rate" : 15,
+ "company" : "_Test Company",
+ "equity_or_liability_account": "Creditors - _TC"
},
{
- "doctype" : "Share Transfer",
- "transfer_type" : "Purchase",
- "date" : "2018-01-05",
- "from_shareholder" : "SH-00003",
- "share_type" : "Equity",
- "from_no" : 401,
- "to_no" : 500,
- "no_of_shares" : 100,
- "rate" : 25,
- "company" : "_Test Company"
+ "doctype" : "Share Transfer",
+ "transfer_type" : "Purchase",
+ "date" : "2018-01-05",
+ "from_shareholder" : "SH-00003",
+ "share_type" : "Equity",
+ "from_no" : 401,
+ "to_no" : 500,
+ "no_of_shares" : 100,
+ "rate" : 25,
+ "company" : "_Test Company",
+ "asset_account" : "Cash - _TC",
+ "equity_or_liability_account": "Creditors - _TC"
}
]
for d in share_transfers:
@@ -84,30 +91,33 @@ class TestShareTransfer(unittest.TestCase):
def test_invalid_share_transfer(self):
doc = frappe.get_doc({
- "doctype" : "Share Transfer",
- "transfer_type" : "Transfer",
- "date" : "2018-01-05",
- "from_shareholder" : "SH-00003",
- "to_shareholder" : "SH-00002",
- "share_type" : "Equity",
- "from_no" : 1,
- "to_no" : 100,
- "no_of_shares" : 100,
- "rate" : 15,
- "company" : "_Test Company"
+ "doctype" : "Share Transfer",
+ "transfer_type" : "Transfer",
+ "date" : "2018-01-05",
+ "from_shareholder" : "SH-00003",
+ "to_shareholder" : "SH-00002",
+ "share_type" : "Equity",
+ "from_no" : 1,
+ "to_no" : 100,
+ "no_of_shares" : 100,
+ "rate" : 15,
+ "company" : "_Test Company",
+ "equity_or_liability_account": "Creditors - _TC"
})
self.assertRaises(ShareDontExists, doc.insert)
doc = frappe.get_doc({
- "doctype" : "Share Transfer",
- "transfer_type" : "Purchase",
- "date" : "2018-01-02",
- "from_shareholder" : "SH-00001",
- "share_type" : "Equity",
- "from_no" : 1,
- "to_no" : 200,
- "no_of_shares" : 200,
- "rate" : 15,
- "company" : "_Test Company"
+ "doctype" : "Share Transfer",
+ "transfer_type" : "Purchase",
+ "date" : "2018-01-02",
+ "from_shareholder" : "SH-00001",
+ "share_type" : "Equity",
+ "from_no" : 1,
+ "to_no" : 200,
+ "no_of_shares" : 200,
+ "rate" : 15,
+ "company" : "_Test Company",
+ "asset_account" : "Cash - _TC",
+ "equity_or_liability_account": "Creditors - _TC"
})
self.assertRaises(ShareDontExists, doc.insert)
From 755020843b05e3f2609e6017dfb2794938199115 Mon Sep 17 00:00:00 2001
From: Mangesh-Khairnar
Date: Fri, 13 Sep 2019 11:07:09 +0530
Subject: [PATCH 478/484] fix: leave balance reports (#18984)
* fix: process allocation expiry
* fix: leave balance summary filter
* fix: opening and closing balance
* fix: check for department leave approvers
* fix: minor changes
* fix: consider leave approver in employee
* Update employee_leave_balance_summary.py
---
.../employee_leave_balance.py | 49 +++---------
.../employee_leave_balance_summary.js | 30 ++++---
.../employee_leave_balance_summary.py | 80 +++++++++++++------
3 files changed, 85 insertions(+), 74 deletions(-)
diff --git a/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py b/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py
index 22f0203c90..7717ba0e40 100644
--- a/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py
+++ b/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py
@@ -8,6 +8,8 @@ from frappe.utils import flt
from erpnext.hr.doctype.leave_application.leave_application \
import get_leave_balance_on, get_leaves_for_period
+from erpnext.hr.report.employee_leave_balance_summary.employee_leave_balance_summary \
+ import get_department_leave_approver_map
def execute(filters=None):
leave_types = frappe.db.sql_list("select name from `tabLeave Type` order by name asc")
@@ -19,7 +21,7 @@ def execute(filters=None):
def get_columns(leave_types):
columns = [
- _("Employee") + ":Link/Employee:150",
+ _("Employee") + ":Link.Employee:150",
_("Employee Name") + "::200",
_("Department") +"::150"
]
@@ -52,11 +54,13 @@ def get_data(filters, leave_types):
active_employees = frappe.get_all("Employee",
filters=conditions,
- fields=["name", "employee_name", "department", "user_id"])
+ fields=["name", "employee_name", "department", "user_id", "leave_approver"])
+
+ department_approver_map = get_department_leave_approver_map(filters.get('department'))
data = []
for employee in active_employees:
- leave_approvers = get_approvers(employee.department)
+ leave_approvers = department_approver_map.get(employee.department_name, []).append(employee.leave_approver)
if (len(leave_approvers) and user in leave_approvers) or (user in ["Administrator", employee.user_id]) or ("HR Manager" in frappe.get_roles(user)):
row = [employee.name, employee.employee_name, employee.department]
@@ -66,46 +70,13 @@ def get_data(filters, leave_types):
filters.from_date, filters.to_date) * -1
# opening balance
- opening = get_total_allocated_leaves(employee.name, leave_type, filters.from_date, filters.to_date)
+ opening = get_leave_balance_on(employee.name, leave_type, filters.from_date)
# closing balance
- closing = flt(opening) - flt(leaves_taken)
+ closing = get_leave_balance_on(employee.name, leave_type, filters.to_date)
row += [opening, leaves_taken, closing]
data.append(row)
- return data
-
-def get_approvers(department):
- if not department:
- return []
-
- approvers = []
- # get current department and all its child
- department_details = frappe.db.get_value("Department", {"name": department}, ["lft", "rgt"], as_dict=True)
- department_list = frappe.db.sql("""select name from `tabDepartment`
- where lft >= %s and rgt <= %s order by lft desc
- """, (department_details.lft, department_details.rgt), as_list = True)
-
- # retrieve approvers list from current department and from its subsequent child departments
- for d in department_list:
- approvers.extend([l.leave_approver for l in frappe.db.sql("""select approver from `tabDepartment Approver` \
- where parent = %s and parentfield = 'leave_approvers'""", (d), as_dict=True)])
-
- return approvers
-
-def get_total_allocated_leaves(employee, leave_type, from_date, to_date):
- ''' Returns leave allocation between from date and to date '''
- leave_allocation_records = frappe.db.get_all('Leave Ledger Entry', filters={
- 'docstatus': 1,
- 'is_expired': 0,
- 'leave_type': leave_type,
- 'employee': employee,
- 'transaction_type': 'Leave Allocation'
- }, or_filters={
- 'from_date': ['between', (from_date, to_date)],
- 'to_date': ['between', (from_date, to_date)]
- }, fields=['SUM(leaves) as leaves'])
-
- return flt(leave_allocation_records[0].get('leaves')) if leave_allocation_records else flt(0)
\ No newline at end of file
+ return data
\ No newline at end of file
diff --git a/erpnext/hr/report/employee_leave_balance_summary/employee_leave_balance_summary.js b/erpnext/hr/report/employee_leave_balance_summary/employee_leave_balance_summary.js
index 838f4ad147..3fb8f6e9c1 100644
--- a/erpnext/hr/report/employee_leave_balance_summary/employee_leave_balance_summary.js
+++ b/erpnext/hr/report/employee_leave_balance_summary/employee_leave_balance_summary.js
@@ -4,6 +4,20 @@
frappe.query_reports['Employee Leave Balance Summary'] = {
filters: [
+ {
+ fieldname:'from_date',
+ label: __('From Date'),
+ fieldtype: 'Date',
+ reqd: 1,
+ default: frappe.defaults.get_default('year_start_date')
+ },
+ {
+ fieldname:'to_date',
+ label: __('To Date'),
+ fieldtype: 'Date',
+ reqd: 1,
+ default: frappe.defaults.get_default('year_end_date')
+ },
{
fieldname:'company',
label: __('Company'),
@@ -19,18 +33,10 @@ frappe.query_reports['Employee Leave Balance Summary'] = {
options: 'Employee',
},
{
- fieldname:'from_date',
- label: __('From Date'),
- fieldtype: 'Date',
- reqd: 1,
- default: frappe.defaults.get_default('year_start_date')
- },
- {
- fieldname:'to_date',
- label: __('To Date'),
- fieldtype: 'Date',
- reqd: 1,
- default: frappe.defaults.get_default('year_end_date')
+ fieldname:'department',
+ label: __('Department'),
+ fieldtype: 'Link',
+ options: 'Department',
}
]
};
diff --git a/erpnext/hr/report/employee_leave_balance_summary/employee_leave_balance_summary.py b/erpnext/hr/report/employee_leave_balance_summary/employee_leave_balance_summary.py
index 64a5c1c13a..15a5da00f8 100644
--- a/erpnext/hr/report/employee_leave_balance_summary/employee_leave_balance_summary.py
+++ b/erpnext/hr/report/employee_leave_balance_summary/employee_leave_balance_summary.py
@@ -5,9 +5,7 @@ from __future__ import unicode_literals
import frappe
from frappe.utils import flt
from frappe import _
-from erpnext.hr.doctype.leave_application.leave_application import get_leaves_for_period
-
-from erpnext.hr.report.employee_leave_balance.employee_leave_balance import get_total_allocated_leaves
+from erpnext.hr.doctype.leave_application.leave_application import get_leaves_for_period, get_leave_balance_on
def execute(filters=None):
if filters.to_date <= filters.from_date:
@@ -58,16 +56,14 @@ def get_columns():
def get_data(filters):
leave_types = frappe.db.sql_list("SELECT `name` FROM `tabLeave Type` ORDER BY `name` ASC")
- conditions = {
- 'status': 'Active',
- }
+ conditions = get_conditions(filters)
- if filters.get('employee'):
- conditions['name'] = filters.get('employee')
+ user = frappe.session.user
+ department_approver_map = get_department_leave_approver_map(filters.get('department'))
- active_employees = frappe.get_all('Employee',
+ active_employees = frappe.get_list('Employee',
filters=conditions,
- fields=['name', 'employee_name', 'department', 'user_id'])
+ fields=['name', 'employee_name', 'department', 'user_id', 'leave_approver'])
data = []
@@ -76,21 +72,59 @@ def get_data(filters):
'leave_type': leave_type
})
for employee in active_employees:
- row = frappe._dict({
- 'employee': employee.name,
- 'employee_name': employee.employee_name
- })
+
+ leave_approvers = department_approver_map.get(employee.department_name, []).append(employee.leave_approver)
- leaves_taken = get_leaves_for_period(employee.name, leave_type,
- filters.from_date, filters.to_date) * -1
+ if (len(leave_approvers) and user in leave_approvers) or (user in ["Administrator", employee.user_id]) \
+ or ("HR Manager" in frappe.get_roles(user)):
+ row = frappe._dict({
+ 'employee': employee.name,
+ 'employee_name': employee.employee_name
+ })
- opening = get_total_allocated_leaves(employee.name, leave_type, filters.from_date, filters.to_date)
- closing = flt(opening) - flt(leaves_taken)
+ leaves_taken = get_leaves_for_period(employee.name, leave_type,
+ filters.from_date, filters.to_date) * -1
- row.opening_balance = opening
- row.leaves_taken = leaves_taken
- row.closing_balance = closing
- row.indent = 1
- data.append(row)
+ opening = get_leave_balance_on(employee.name, leave_type, filters.from_date)
+ closing = get_leave_balance_on(employee.name, leave_type, filters.to_date)
+
+ row.opening_balance = opening
+ row.leaves_taken = leaves_taken
+ row.closing_balance = closing
+ row.indent = 1
+ data.append(row)
return data
+
+def get_conditions(filters):
+ conditions={
+ 'status': 'Active',
+ }
+ if filters.get('employee'):
+ conditions['name'] = filters.get('employee')
+
+ if filters.get('employee'):
+ conditions['name'] = filters.get('employee')
+
+ return conditions
+
+def get_department_leave_approver_map(department=None):
+ conditions=''
+ if department:
+ conditions='and department_name = %(department)s or parent_department = %(department)s'%{'department': department}
+
+ # get current department and all its child
+ department_list = frappe.db.sql_list(''' SELECT name FROM `tabDepartment` WHERE disabled=0 {0}'''.format(conditions)) #nosec
+
+ # retrieve approvers list from current department and from its subsequent child departments
+ approver_list = frappe.get_all('Department Approver', filters={
+ 'parentfield': 'leave_approvers',
+ 'parent': ('in', department_list)
+ }, fields=['parent', 'approver'], as_list=1)
+
+ approvers = {}
+
+ for k, v in approver_list:
+ approvers.setdefault(k, []).append(v)
+
+ return approvers
From 6996c2d17d377484583301f044cef898f9310349 Mon Sep 17 00:00:00 2001
From: Suraj Shetty <13928957+surajshetty3416@users.noreply.github.com>
Date: Fri, 13 Sep 2019 12:25:06 +0530
Subject: [PATCH 479/484] fix: Fetch image from user if available (#19030)
---
erpnext/hr/doctype/employee/employee.json | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/erpnext/hr/doctype/employee/employee.json b/erpnext/hr/doctype/employee/employee.json
index ee0b2a265a..9291820524 100644
--- a/erpnext/hr/doctype/employee/employee.json
+++ b/erpnext/hr/doctype/employee/employee.json
@@ -171,6 +171,8 @@
"read_only": 1
},
{
+ "fetch_from": "user_id.user_image",
+ "fetch_if_empty": 1,
"fieldname": "image",
"fieldtype": "Attach Image",
"hidden": 1,
@@ -780,7 +782,7 @@
"icon": "fa fa-user",
"idx": 24,
"image_field": "image",
- "modified": "2019-09-06 15:54:36.735147",
+ "modified": "2019-09-12 14:21:12.711280",
"modified_by": "Administrator",
"module": "HR",
"name": "Employee",
From f8899827e0aff2c258e4d404f0f1019237307e2a Mon Sep 17 00:00:00 2001
From: Suraj Shetty <13928957+surajshetty3416@users.noreply.github.com>
Date: Fri, 13 Sep 2019 12:27:00 +0530
Subject: [PATCH 480/484] fix: Add Exotel Settings to integration module
(#19025)
* fix: Add Exotel Settings to integration module
* fix: Add description
---
erpnext/config/integrations.py | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/erpnext/config/integrations.py b/erpnext/config/integrations.py
index 52c9ab8e46..f8b3257b5c 100644
--- a/erpnext/config/integrations.py
+++ b/erpnext/config/integrations.py
@@ -40,6 +40,11 @@ def get_data():
"type": "doctype",
"name": "Plaid Settings",
"description": _("Connect your bank accounts to ERPNext"),
+ },
+ {
+ "type": "doctype",
+ "name": "Exotel Settings",
+ "description": _("Connect your Exotel Account to ERPNext and track call logs"),
}
]
}
From b3c732daf5fddcfa43bcb3ca8dbd633cc8b357d5 Mon Sep 17 00:00:00 2001
From: Chinmay Pai
Date: Fri, 13 Sep 2019 15:48:08 +0530
Subject: [PATCH 481/484] refactor(plaid): move configuration from site_config
to doctype (#18712)
* feat(plaid): move plaid from site_config to doctype
plaid requires accessing site_config and cloud users cannot access
site_config and hence, plaid integration doesn't work on the cloud.
Moving all the configuration from site_config to the Plaid Settings
doctype fixes this issue.
Signed-off-by: Chinmay D. Pai
* feat(plaid): make changes to plaid_settings and add patch
* remove all references for get()-ing plaid variables from frappe.conf
and replace them with values from doctype
* add patch to move all existing plaid settings variable values from
frappe.conf to plaid_settings doctype
Signed-off-by: Chinmay D. Pai
* fix(plaid): use get_single_value for Plaid Settings
Co-Authored-By: Himanshu
* chore: reload plaid_settings before running patch
Signed-off-by: Chinmay D. Pai
* chore: remove useless semicolon
fuck codacy
Signed-off-by: Chinmay D. Pai
---
.../doctype/plaid_settings/plaid_connector.py | 29 +--
.../doctype/plaid_settings/plaid_settings.js | 34 +--
.../plaid_settings/plaid_settings.json | 235 +++++++-----------
.../doctype/plaid_settings/plaid_settings.py | 9 +-
erpnext/patches.txt | 1 +
.../v12_0/move_plaid_settings_to_doctype.py | 22 ++
6 files changed, 147 insertions(+), 183 deletions(-)
create mode 100644 erpnext/patches/v12_0/move_plaid_settings_to_doctype.py
diff --git a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_connector.py b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_connector.py
index fbb0ebc2c8..532e19cffd 100644
--- a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_connector.py
+++ b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_connector.py
@@ -3,30 +3,31 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
from frappe import _
-import requests
+from frappe.utils.password import get_decrypted_password
from plaid import Client
from plaid.errors import APIError, ItemError
+import frappe
+import requests
+
class PlaidConnector():
def __init__(self, access_token=None):
- if not(frappe.conf.get("plaid_client_id") and frappe.conf.get("plaid_secret") and frappe.conf.get("plaid_public_key")):
- frappe.throw(_("Please complete your Plaid API configuration before synchronizing your account"))
+ plaid_settings = frappe.get_single("Plaid Settings")
self.config = {
- "plaid_client_id": frappe.conf.get("plaid_client_id"),
- "plaid_secret": frappe.conf.get("plaid_secret"),
- "plaid_public_key": frappe.conf.get("plaid_public_key"),
- "plaid_env": frappe.conf.get("plaid_env")
+ "plaid_client_id": plaid_settings.plaid_client_id,
+ "plaid_secret": get_decrypted_password("Plaid Settings", "Plaid Settings", 'plaid_secret'),
+ "plaid_public_key": plaid_settings.plaid_public_key,
+ "plaid_env": plaid_settings.plaid_env
}
- self.client = Client(client_id=self.config["plaid_client_id"],
- secret=self.config["plaid_secret"],
- public_key=self.config["plaid_public_key"],
- environment=self.config["plaid_env"]
- )
+ self.client = Client(client_id=self.config.get("plaid_client_id"),
+ secret=self.config.get("plaid_secret"),
+ public_key=self.config.get("plaid_public_key"),
+ environment=self.config.get("plaid_env")
+ )
self.access_token = access_token
@@ -78,4 +79,4 @@ class PlaidConnector():
transactions.extend(response['transactions'])
return transactions
except Exception:
- frappe.log_error(frappe.get_traceback(), _("Plaid transactions sync error"))
\ No newline at end of file
+ frappe.log_error(frappe.get_traceback(), _("Plaid transactions sync error"))
diff --git a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.js b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.js
index ace4fbf9e3..0ffbb877ea 100644
--- a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.js
+++ b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.js
@@ -4,8 +4,18 @@
frappe.provide("erpnext.integrations");
frappe.ui.form.on('Plaid Settings', {
- link_new_account: function(frm) {
- new erpnext.integrations.plaidLink(frm);
+ enabled: function(frm) {
+ frm.toggle_reqd('plaid_client_id', frm.doc.enabled);
+ frm.toggle_reqd('plaid_secret', frm.doc.enabled);
+ frm.toggle_reqd('plaid_public_key', frm.doc.enabled);
+ frm.toggle_reqd('plaid_env', frm.doc.enabled);
+ },
+ refresh: function(frm) {
+ if(frm.doc.enabled) {
+ frm.add_custom_button('Link a new bank account', () => {
+ new erpnext.integrations.plaidLink(frm);
+ });
+ }
}
});
@@ -19,20 +29,10 @@ erpnext.integrations.plaidLink = class plaidLink {
init_config() {
const me = this;
- frappe.xcall('erpnext.erpnext_integrations.doctype.plaid_settings.plaid_settings.plaid_configuration')
- .then(result => {
- if (result !== "disabled") {
- if (result.plaid_env == undefined || result.plaid_public_key == undefined) {
- frappe.throw(__("Please add valid Plaid api keys in site_config.json first"));
- }
- me.plaid_env = result.plaid_env;
- me.plaid_public_key = result.plaid_public_key;
- me.client_name = result.client_name;
- me.init_plaid();
- } else {
- frappe.throw(__("Please save your document before adding a new account"));
- }
- });
+ me.plaid_env = me.frm.doc.plaid_env;
+ me.plaid_public_key = me.frm.doc.plaid_public_key;
+ me.client_name = frappe.boot.sitename;
+ me.init_plaid();
}
init_plaid() {
@@ -104,4 +104,4 @@ erpnext.integrations.plaidLink = class plaidLink {
});
}, __("Select a company"), __("Continue"));
}
-};
\ No newline at end of file
+};
diff --git a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.json b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.json
index ed51c4e8f8..9903048d0b 100644
--- a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.json
+++ b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.json
@@ -1,161 +1,96 @@
{
- "allow_copy": 0,
- "allow_events_in_timeline": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "beta": 0,
- "creation": "2018-10-25 10:02:48.656165",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "",
- "editable_grid": 1,
- "engine": "InnoDB",
+ "creation": "2018-10-25 10:02:48.656165",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "enabled",
+ "column_break_2",
+ "automatic_sync",
+ "section_break_4",
+ "plaid_client_id",
+ "plaid_secret",
+ "column_break_7",
+ "plaid_public_key",
+ "plaid_env"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "enabled",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Enabled",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "default": "0",
+ "fieldname": "enabled",
+ "fieldtype": "Check",
+ "label": "Enabled"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:doc.enabled==1",
- "fieldname": "automatic_sync",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Synchronize all accounts every hour",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "default": "0",
+ "depends_on": "eval:doc.enabled==1",
+ "fieldname": "automatic_sync",
+ "fieldtype": "Check",
+ "label": "Synchronize all accounts every hour"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:(doc.enabled==1)&&(!doc.__islocal)",
- "fieldname": "link_new_account",
- "fieldtype": "Button",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Link a new bank account",
- "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,
- "translatable": 0,
- "unique": 0
+ "depends_on": "eval:doc.enabled==1",
+ "fieldname": "plaid_client_id",
+ "fieldtype": "Data",
+ "in_list_view": 1,
+ "label": "Plaid Client ID",
+ "reqd": 1
+ },
+ {
+ "depends_on": "eval:doc.enabled==1",
+ "fieldname": "plaid_secret",
+ "fieldtype": "Password",
+ "in_list_view": 1,
+ "label": "Plaid Secret",
+ "reqd": 1
+ },
+ {
+ "depends_on": "eval:doc.enabled==1",
+ "fieldname": "plaid_public_key",
+ "fieldtype": "Data",
+ "in_list_view": 1,
+ "label": "Plaid Public Key",
+ "reqd": 1
+ },
+ {
+ "depends_on": "eval:doc.enabled==1",
+ "fieldname": "plaid_env",
+ "fieldtype": "Data",
+ "in_list_view": 1,
+ "label": "Plaid Environment",
+ "reqd": 1
+ },
+ {
+ "fieldname": "column_break_2",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "section_break_4",
+ "fieldtype": "Section Break"
+ },
+ {
+ "fieldname": "column_break_7",
+ "fieldtype": "Column Break"
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 1,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2018-12-14 12:51:12.331395",
- "modified_by": "Administrator",
- "module": "ERPNext Integrations",
- "name": "Plaid Settings",
- "name_case": "",
- "owner": "Administrator",
+ ],
+ "issingle": 1,
+ "modified": "2019-08-13 17:00:06.939422",
+ "modified_by": "Administrator",
+ "module": "ERPNext Integrations",
+ "name": "Plaid Settings",
+ "owner": "Administrator",
"permissions": [
{
- "amend": 0,
- "cancel": 0,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 0,
- "role": "System Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "role": "System Manager",
+ "share": 1,
"write": 1
}
- ],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 0,
- "track_seen": 0,
- "track_views": 0
+ ],
+ "sort_field": "modified",
+ "sort_order": "DESC"
}
\ No newline at end of file
diff --git a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py
index 8d31e24cd6..4af1d74094 100644
--- a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py
+++ b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py
@@ -16,8 +16,13 @@ class PlaidSettings(Document):
@frappe.whitelist()
def plaid_configuration():
- if frappe.db.get_value("Plaid Settings", None, "enabled") == "1":
- return {"plaid_public_key": frappe.conf.get("plaid_public_key") or None, "plaid_env": frappe.conf.get("plaid_env") or None, "client_name": frappe.local.site }
+ if frappe.db.get_single_value("Plaid Settings", "enabled"):
+ plaid_settings = frappe.get_single("Plaid Settings")
+ return {
+ "plaid_public_key": plaid_settings.plaid_public_key,
+ "plaid_env": plaid_settings.plaid_env,
+ "client_name": frappe.local.site
+ }
else:
return "disabled"
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 2f74d54dd2..7c1d8a034d 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -625,6 +625,7 @@ erpnext.patches.v12_0.add_default_buying_selling_terms_in_company
erpnext.patches.v12_0.update_ewaybill_field_position
erpnext.patches.v12_0.create_accounting_dimensions_in_missing_doctypes
erpnext.patches.v11_1.set_status_for_material_request_type_manufacture
+erpnext.patches.v12_0.move_plaid_settings_to_doctype
execute:frappe.reload_doc('desk', 'doctype','dashboard_chart_link')
execute:frappe.reload_doc('desk', 'doctype','dashboard')
execute:frappe.reload_doc('desk', 'doctype','dashboard_chart_source')
diff --git a/erpnext/patches/v12_0/move_plaid_settings_to_doctype.py b/erpnext/patches/v12_0/move_plaid_settings_to_doctype.py
new file mode 100644
index 0000000000..8e60d33f85
--- /dev/null
+++ b/erpnext/patches/v12_0/move_plaid_settings_to_doctype.py
@@ -0,0 +1,22 @@
+# Copyright (c) 2017, Frappe and Contributors
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+import frappe
+
+def execute():
+ frappe.reload_doc("erpnext_integrations", "doctype", "plaid_settings")
+ plaid_settings = frappe.get_single("Plaid Settings")
+ if plaid_settings.enabled:
+ if not (frappe.conf.plaid_client_id and frappe.conf.plaid_env \
+ and frappe.conf.plaid_public_key and frappe.conf.plaid_secret):
+ plaid_settings.enabled = 0
+ else:
+ plaid_settings.update({
+ "plaid_client_id": frappe.conf.plaid_client_id,
+ "plaid_public_key": frappe.conf.plaid_public_key,
+ "plaid_env": frappe.conf.plaid_env,
+ "plaid_secret": frappe.conf.plaid_secret
+ })
+ plaid_settings.flags.ignore_mandatory = True
+ plaid_settings.save()
From 93a9c081162a54db3faa77694f177e64798ab907 Mon Sep 17 00:00:00 2001
From: Nabin Hait
Date: Fri, 13 Sep 2019 15:48:50 +0530
Subject: [PATCH 482/484] fix: Allocate payment amount in reference table on
change of payment amount (#19041)
---
erpnext/accounts/doctype/payment_entry/payment_entry.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.js b/erpnext/accounts/doctype/payment_entry/payment_entry.js
index f17b2cbeda..172d5372a6 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.js
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.js
@@ -720,7 +720,7 @@ frappe.ui.form.on('Payment Entry', {
$.each(frm.doc.references || [], function(i, row) {
row.allocated_amount = 0 //If allocate payment amount checkbox is unchecked, set zero to allocate amount
- if(frappe.flags.allocate_payment_amount){
+ if(frappe.flags.allocate_payment_amount != 0){
if(row.outstanding_amount > 0 && allocated_positive_outstanding > 0) {
if(row.outstanding_amount >= allocated_positive_outstanding) {
row.allocated_amount = allocated_positive_outstanding;
From 3d433efdfe7cc97ce801cb6d8909e8fd8879a176 Mon Sep 17 00:00:00 2001
From: marination
Date: Fri, 13 Sep 2019 16:28:11 +0530
Subject: [PATCH 483/484] fix[minor]: Changed error message in GSTR-1 Report
Error message didn't prompt where the user has to add the missing value(GSTIN No.)
---
erpnext/regional/report/gstr_1/gstr_1.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/regional/report/gstr_1/gstr_1.py b/erpnext/regional/report/gstr_1/gstr_1.py
index 43e232bf72..922619cc42 100644
--- a/erpnext/regional/report/gstr_1/gstr_1.py
+++ b/erpnext/regional/report/gstr_1/gstr_1.py
@@ -722,7 +722,7 @@ def get_company_gstin_number(company):
if gstin:
return gstin[0]["gstin"]
else:
- frappe.throw(_("No GST No. found for the Company."))
+ frappe.throw(_("Please set valid GSTIN No. in Company Address"))
def download_json_file(filename, report_type, data):
''' download json content in a file '''
From 4a323463f76fcfeafb95dd97c016506857599511 Mon Sep 17 00:00:00 2001
From: rohitwaghchaure
Date: Fri, 13 Sep 2019 18:36:57 +0530
Subject: [PATCH 484/484] fix: for pos, paid amount has not considered the tax
amount due to which outstanding amount showing for the pos invoices (#19039)
---
erpnext/accounts/page/pos/pos.js | 11 ++---------
1 file changed, 2 insertions(+), 9 deletions(-)
diff --git a/erpnext/accounts/page/pos/pos.js b/erpnext/accounts/page/pos/pos.js
index 2173e7dfb7..0cd8bfefb8 100755
--- a/erpnext/accounts/page/pos/pos.js
+++ b/erpnext/accounts/page/pos/pos.js
@@ -1691,20 +1691,13 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
if(this.si_docs) {
this.si_docs.forEach((row) => {
- existing_pos_list.push(Object.keys(row));
+ existing_pos_list.push(Object.keys(row)[0]);
});
}
if (this.frm.doc.offline_pos_name
- && in_list(existing_pos_list, this.frm.doc.offline_pos_name)) {
+ && in_list(existing_pos_list, cstr(this.frm.doc.offline_pos_name))) {
this.update_invoice()
- //to retrieve and set the default payment
- invoice_data[this.frm.doc.offline_pos_name] = this.frm.doc;
- invoice_data[this.frm.doc.offline_pos_name].payments[0].amount = this.frm.doc.net_total
- invoice_data[this.frm.doc.offline_pos_name].payments[0].base_amount = this.frm.doc.net_total
-
- this.frm.doc.paid_amount = this.frm.doc.net_total
- this.frm.doc.outstanding_amount = 0
} else if(!this.frm.doc.offline_pos_name) {
this.frm.doc.offline_pos_name = frappe.datetime.now_datetime();
this.frm.doc.posting_date = frappe.datetime.get_today();