From c7feea830ff3e617d0d9d15b505a44b8cddd355f Mon Sep 17 00:00:00 2001 From: Himanshu Warekar Date: Thu, 12 Dec 2019 21:12:17 +0530 Subject: [PATCH 01/50] feat: Email Append To --- erpnext/crm/doctype/lead/lead.json | 7 +- .../crm/doctype/opportunity/opportunity.json | 7 +- .../doctype/job_applicant/job_applicant.json | 470 ++++-------------- erpnext/support/doctype/issue/issue.json | 9 +- 4 files changed, 123 insertions(+), 370 deletions(-) diff --git a/erpnext/crm/doctype/lead/lead.json b/erpnext/crm/doctype/lead/lead.json index eb68c679ba..f7cb31f492 100644 --- a/erpnext/crm/doctype/lead/lead.json +++ b/erpnext/crm/doctype/lead/lead.json @@ -1,10 +1,12 @@ { + "actions": [], "allow_events_in_timeline": 1, "allow_import": 1, "autoname": "naming_series:", "creation": "2013-04-10 11:45:37", "doctype": "DocType", "document_type": "Document", + "email_append_to": 1, "engine": "InnoDB", "field_order": [ "organization_lead", @@ -366,7 +368,8 @@ "icon": "fa fa-user", "idx": 5, "image_field": "image", - "modified": "2019-09-19 12:49:02.536647", + "links": [], + "modified": "2019-12-12 21:00:59.166518", "modified_by": "Administrator", "module": "CRM", "name": "Lead", @@ -435,8 +438,10 @@ } ], "search_fields": "lead_name,lead_owner,status", + "sender_field": "status", "show_name_in_global_search": 1, "sort_field": "modified", "sort_order": "DESC", + "subject_field": "notes", "title_field": "lead_name" } \ No newline at end of file diff --git a/erpnext/crm/doctype/opportunity/opportunity.json b/erpnext/crm/doctype/opportunity/opportunity.json index 66e3ca48dd..070475b59a 100644 --- a/erpnext/crm/doctype/opportunity/opportunity.json +++ b/erpnext/crm/doctype/opportunity/opportunity.json @@ -1,4 +1,5 @@ { + "actions": [], "allow_import": 1, "allow_rename": 1, "autoname": "naming_series:", @@ -7,6 +8,7 @@ "doctype": "DocType", "document_type": "Document", "editable_grid": 1, + "email_append_to": 1, "engine": "InnoDB", "field_order": [ "from_section", @@ -412,7 +414,8 @@ ], "icon": "fa fa-info-sign", "idx": 195, - "modified": "2019-09-30 12:58:37.385400", + "links": [], + "modified": "2019-12-12 20:38:30.423368", "modified_by": "Administrator", "module": "CRM", "name": "Opportunity", @@ -444,9 +447,11 @@ } ], "search_fields": "status,transaction_date,party_name,opportunity_type,territory,company", + "sender_field": "contact_email", "show_name_in_global_search": 1, "sort_field": "modified", "sort_order": "DESC", + "subject_field": "title", "timeline_field": "party_name", "title_field": "title", "track_seen": 1, diff --git a/erpnext/hr/doctype/job_applicant/job_applicant.json b/erpnext/hr/doctype/job_applicant/job_applicant.json index b0cddc257e..21bf4986b2 100644 --- a/erpnext/hr/doctype/job_applicant/job_applicant.json +++ b/erpnext/hr/doctype/job_applicant/job_applicant.json @@ -1,385 +1,123 @@ { - "allow_copy": 0, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 1, - "autoname": "HR-APP-.YYYY.-.#####", - "beta": 0, - "creation": "2013-01-29 19:25:37", - "custom": 0, - "description": "Applicant for a Job", - "docstatus": 0, - "doctype": "DocType", - "document_type": "Document", - "editable_grid": 0, - "engine": "InnoDB", + "actions": [], + "allow_rename": 1, + "autoname": "HR-APP-.YYYY.-.#####", + "creation": "2013-01-29 19:25:37", + "description": "Applicant for a Job", + "doctype": "DocType", + "document_type": "Document", + "email_append_to": 1, + "engine": "InnoDB", + "field_order": [ + "applicant_name", + "email_id", + "status", + "column_break_3", + "job_title", + "source", + "source_name", + "section_break_6", + "notes", + "cover_letter", + "resume_attachment" + ], "fields": [ { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 1, - "collapsible": 0, - "columns": 0, - "fieldname": "applicant_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": "Applicant Name", - "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 - }, + "bold": 1, + "fieldname": "applicant_name", + "fieldtype": "Data", + "in_global_search": 1, + "label": "Applicant Name", + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 1, - "collapsible": 0, - "columns": 0, - "fieldname": "email_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": "Email Address", - "length": 0, - "no_copy": 0, - "options": "Email", - "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 - }, + "bold": 1, + "fieldname": "email_id", + "fieldtype": "Data", + "label": "Email Address", + "options": "Email", + "reqd": 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": 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": "Status", - "length": 0, - "no_copy": 0, - "options": "Open\nReplied\nRejected\nHold\nAccepted", - "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": "status", + "fieldtype": "Select", + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Status", + "options": "Open\nReplied\nRejected\nHold\nAccepted", + "reqd": 1 + }, { - "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, + "fieldname": "column_break_3", + "fieldtype": "Column Break", "width": "50%" - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "job_title", - "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": "Job Opening", - "length": 0, - "no_copy": 0, - "options": "Job Opening", - "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": "job_title", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Job Opening", + "options": "Job Opening" + }, { - "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, - "options": "Job Applicant Source", - "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": "source", + "fieldtype": "Link", + "label": "Source", + "options": "Job Applicant Source" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "eval: doc.source==\"Employee Referral\" ", - "fieldname": "source_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": "Source Name", - "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": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "depends_on": "eval: doc.source==\"Employee Referral\" ", + "fieldname": "source_name", + "fieldtype": "Link", + "label": "Source Name", + "options": "Employee" + }, { - "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, - "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_6", + "fieldtype": "Section Break" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "cover_letter", - "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": "Cover Letter", - "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": "cover_letter", + "fieldtype": "Text", + "label": "Cover Letter" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "resume_attachment", - "fieldtype": "Attach", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Resume Attachment", - "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": "resume_attachment", + "fieldtype": "Attach", + "label": "Resume Attachment" + }, + { + "fieldname": "notes", + "fieldtype": "Data", + "label": "Notes", + "read_only": 1 } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "icon": "fa fa-user", - "idx": 1, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 0, - "max_attachments": 0, - "modified": "2019-07-21 16:15:43.552049", - "modified_by": "Administrator", - "module": "HR", - "name": "Job Applicant", - "owner": "Administrator", + ], + "icon": "fa fa-user", + "idx": 1, + "links": [], + "modified": "2019-12-12 21:10:13.637336", + "modified_by": "Administrator", + "module": "HR", + "name": "Job Applicant", + "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, + "create": 1, + "delete": 1, + "email": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "HR User", + "share": 1, "write": 1 } - ], - "quick_entry": 0, - "read_only": 0, - "read_only_onload": 0, - "search_fields": "applicant_name", - "show_name_in_global_search": 0, - "sort_order": "ASC", - "title_field": "applicant_name", - "track_changes": 0, - "track_seen": 0, - "track_views": 0 + ], + "search_fields": "applicant_name", + "sender_field": "email_id", + "sort_field": "modified", + "sort_order": "ASC", + "subject_field": "notes", + "title_field": "applicant_name" } \ No newline at end of file diff --git a/erpnext/support/doctype/issue/issue.json b/erpnext/support/doctype/issue/issue.json index 222554bda1..94cff80edb 100644 --- a/erpnext/support/doctype/issue/issue.json +++ b/erpnext/support/doctype/issue/issue.json @@ -1,10 +1,12 @@ { + "actions": [], "allow_import": 1, "allow_rename": 1, "autoname": "naming_series:", "creation": "2013-02-01 10:36:25", "doctype": "DocType", "document_type": "Setup", + "email_append_to": 1, "engine": "InnoDB", "field_order": [ "subject_section", @@ -363,8 +365,9 @@ ], "icon": "fa fa-ticket", "idx": 7, - "modified": "2019-09-11 09:03:57.465623", - "modified_by": "himanshu@erpnext.com", + "links": [], + "modified": "2019-12-12 21:11:01.726692", + "modified_by": "Administrator", "module": "Support", "name": "Issue", "owner": "Administrator", @@ -383,8 +386,10 @@ ], "quick_entry": 1, "search_fields": "status,customer,subject,raised_by", + "sender_field": "raised_by", "sort_field": "modified", "sort_order": "ASC", + "subject_field": "subject", "timeline_field": "customer", "title_field": "subject", "track_changes": 1, From c9f497d7c0ce91c69ad2dbd86f7ee13a4298cfaa Mon Sep 17 00:00:00 2001 From: Himanshu Warekar Date: Mon, 13 Jan 2020 16:26:40 +0530 Subject: [PATCH 02/50] feat: move subject and sender fields to json --- erpnext/crm/doctype/lead/lead.json | 8 ++------ erpnext/crm/doctype/lead/lead.py | 3 --- erpnext/crm/doctype/opportunity/opportunity.json | 3 ++- erpnext/crm/doctype/opportunity/opportunity.py | 3 --- erpnext/hr/doctype/job_applicant/job_applicant.json | 2 +- erpnext/hr/doctype/job_applicant/job_applicant.py | 2 -- erpnext/support/doctype/issue/issue.json | 2 +- erpnext/support/doctype/issue/issue.py | 3 --- erpnext/www/book-appointment/__init__.py | 0 erpnext/www/book-appointment/verify/__init__.py | 0 10 files changed, 6 insertions(+), 20 deletions(-) create mode 100644 erpnext/www/book-appointment/__init__.py create mode 100644 erpnext/www/book-appointment/verify/__init__.py diff --git a/erpnext/crm/doctype/lead/lead.json b/erpnext/crm/doctype/lead/lead.json index dd282e5add..bd3110bcd3 100644 --- a/erpnext/crm/doctype/lead/lead.json +++ b/erpnext/crm/doctype/lead/lead.json @@ -440,11 +440,7 @@ "idx": 5, "image_field": "image", "links": [], -<<<<<<< HEAD - "modified": "2019-12-12 21:00:59.166518", -======= - "modified": "2019-12-24 16:00:44.239168", ->>>>>>> 2d151a7b85acc2bd530793ff3586a58f117ee270 + "modified": "2020-01-13 16:16:48.885228", "modified_by": "Administrator", "module": "CRM", "name": "Lead", @@ -513,7 +509,7 @@ } ], "search_fields": "lead_name,lead_owner,status", - "sender_field": "status", + "sender_field": "email_id", "show_name_in_global_search": 1, "sort_field": "modified", "sort_order": "DESC", diff --git a/erpnext/crm/doctype/lead/lead.py b/erpnext/crm/doctype/lead/lead.py index 6cab18dc1c..08d8f2590c 100644 --- a/erpnext/crm/doctype/lead/lead.py +++ b/erpnext/crm/doctype/lead/lead.py @@ -12,9 +12,6 @@ from frappe.email.inbox import link_communication_to_document from frappe.model.mapper import get_mapped_doc from frappe.utils import cint, comma_and, cstr, getdate, has_gravatar, nowdate, validate_email_address -sender_field = "email_id" - - class Lead(SellingController): def get_feed(self): return '{0}: {1}'.format(_(self.status), self.lead_name) diff --git a/erpnext/crm/doctype/opportunity/opportunity.json b/erpnext/crm/doctype/opportunity/opportunity.json index 070475b59a..d55c54ed75 100644 --- a/erpnext/crm/doctype/opportunity/opportunity.json +++ b/erpnext/crm/doctype/opportunity/opportunity.json @@ -322,6 +322,7 @@ "fieldname": "contact_email", "fieldtype": "Data", "label": "Contact Email", + "options": "Email", "read_only": 1 }, { @@ -415,7 +416,7 @@ "icon": "fa fa-info-sign", "idx": 195, "links": [], - "modified": "2019-12-12 20:38:30.423368", + "modified": "2020-01-13 16:18:44.477818", "modified_by": "Administrator", "module": "CRM", "name": "Opportunity", diff --git a/erpnext/crm/doctype/opportunity/opportunity.py b/erpnext/crm/doctype/opportunity/opportunity.py index 2880c8050e..198b38d899 100644 --- a/erpnext/crm/doctype/opportunity/opportunity.py +++ b/erpnext/crm/doctype/opportunity/opportunity.py @@ -11,9 +11,6 @@ from erpnext.utilities.transaction_base import TransactionBase from erpnext.accounts.party import get_party_account_currency from frappe.email.inbox import link_communication_to_document -subject_field = "title" -sender_field = "contact_email" - class Opportunity(TransactionBase): def after_insert(self): if self.opportunity_from == "Lead": diff --git a/erpnext/hr/doctype/job_applicant/job_applicant.json b/erpnext/hr/doctype/job_applicant/job_applicant.json index 21bf4986b2..c13548ab82 100644 --- a/erpnext/hr/doctype/job_applicant/job_applicant.json +++ b/erpnext/hr/doctype/job_applicant/job_applicant.json @@ -96,7 +96,7 @@ "icon": "fa fa-user", "idx": 1, "links": [], - "modified": "2019-12-12 21:10:13.637336", + "modified": "2020-01-13 16:19:39.113330", "modified_by": "Administrator", "module": "HR", "name": "Job Applicant", diff --git a/erpnext/hr/doctype/job_applicant/job_applicant.py b/erpnext/hr/doctype/job_applicant/job_applicant.py index 4fc7719f38..a6aef04919 100644 --- a/erpnext/hr/doctype/job_applicant/job_applicant.py +++ b/erpnext/hr/doctype/job_applicant/job_applicant.py @@ -9,8 +9,6 @@ import frappe from frappe import _ from frappe.utils import comma_and, validate_email_address -sender_field = "email_id" - class DuplicationError(frappe.ValidationError): pass class JobApplicant(Document): diff --git a/erpnext/support/doctype/issue/issue.json b/erpnext/support/doctype/issue/issue.json index 94cff80edb..87c4a605de 100644 --- a/erpnext/support/doctype/issue/issue.json +++ b/erpnext/support/doctype/issue/issue.json @@ -366,7 +366,7 @@ "icon": "fa fa-ticket", "idx": 7, "links": [], - "modified": "2019-12-12 21:11:01.726692", + "modified": "2020-01-13 16:20:30.392712", "modified_by": "Administrator", "module": "Support", "name": "Issue", diff --git a/erpnext/support/doctype/issue/issue.py b/erpnext/support/doctype/issue/issue.py index b748e3fa46..c1bd8bedec 100644 --- a/erpnext/support/doctype/issue/issue.py +++ b/erpnext/support/doctype/issue/issue.py @@ -14,9 +14,6 @@ from frappe.utils.user import is_website_user from erpnext.support.doctype.service_level_agreement.service_level_agreement import get_active_service_level_agreement_for from frappe.email.inbox import link_communication_to_document -sender_field = "raised_by" - - class Issue(Document): def get_feed(self): return "{0}: {1}".format(_(self.status), self.subject) diff --git a/erpnext/www/book-appointment/__init__.py b/erpnext/www/book-appointment/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/erpnext/www/book-appointment/verify/__init__.py b/erpnext/www/book-appointment/verify/__init__.py new file mode 100644 index 0000000000..e69de29bb2 From 7be91207309e350c6d70647694436e68ce63e87a Mon Sep 17 00:00:00 2001 From: Himanshu Warekar Date: Sun, 19 Jan 2020 15:05:26 +0530 Subject: [PATCH 03/50] fix: remove email_append_to from hooks --- erpnext/hooks.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/erpnext/hooks.py b/erpnext/hooks.py index 774c917f68..ffdec98a4b 100644 --- a/erpnext/hooks.py +++ b/erpnext/hooks.py @@ -55,12 +55,8 @@ treeviews = ['Account', 'Cost Center', 'Warehouse', 'Item Group', 'Customer Grou update_website_context = ["erpnext.shopping_cart.utils.update_website_context", "erpnext.education.doctype.education_settings.education_settings.update_website_context"] my_account_context = "erpnext.shopping_cart.utils.update_my_account_context" -email_append_to = ["Job Applicant", "Lead", "Opportunity", "Issue"] - calendars = ["Task", "Work Order", "Leave Application", "Sales Order", "Holiday List", "Course Schedule"] - - domains = { 'Agriculture': 'erpnext.domains.agriculture', 'Distribution': 'erpnext.domains.distribution', From 1943fb0de420928e2347d410af36cdfe68d01a01 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Fri, 6 Mar 2020 18:50:11 +0530 Subject: [PATCH 04/50] feat: Allow PI creation without PO --- .../doctype/purchase_invoice/purchase_invoice.py | 16 +++++++++++++--- erpnext/buying/doctype/supplier/supplier.json | 9 ++++++++- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py index cc992cec44..099fa64963 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -4,7 +4,7 @@ from __future__ import unicode_literals import frappe, erpnext -from frappe.utils import cint, cstr, formatdate, flt, getdate, nowdate +from frappe.utils import cint, cstr, formatdate, flt, getdate, nowdate, get_link_to_form from frappe import _, throw import frappe.defaults @@ -288,16 +288,26 @@ class PurchaseInvoice(BuyingController): def po_required(self): if frappe.db.get_value("Buying Settings", None, "po_required") == 'Yes': + + if frappe.get_value('Supplier', self.supplier, 'allow_purchase_invoice_creation_without_purchase_order'): + return + for d in self.get('items'): if not d.purchase_order: - throw(_("As per the Buying Settings if Purchase Order Required == 'YES', then for creating Purchase Invoice, user need to create Purchase Order first for item {0}").format(d.item_code)) + throw(_("""Purchase Order Required for item {0} + To submit the invoice without purchase order please set + {1} as {2} in {3}""").format(frappe.bold(d.item_code), frappe.bold('Purchase Order Required'), + frappe.bold('No'), get_link_to_form('Buying Settings', 'Buying Settings', 'Buying Settings'))) def pr_required(self): stock_items = self.get_stock_items() if frappe.db.get_value("Buying Settings", None, "pr_required") == 'Yes': for d in self.get('items'): if not d.purchase_receipt and d.item_code in stock_items: - throw(_("As per the Buying Settings if Purchase Reciept Required == 'YES', then for creating Purchase Invoice, user need to create Purchase Receipt first for item {0}").format(d.item_code)) + throw(_("""Purchase Receipt Required for item {0} + To submit the invoice without purchase receipt please set + {1} as {2} in {3}""").format(frappe.bold(d.item_code), frappe.bold('Purchase Receipt Required'), + frappe.bold('No'), get_link_to_form('Buying Settings', 'Buying Settings', 'Buying Settings'))) def validate_write_off_account(self): if self.write_off_amount and not self.write_off_account: diff --git a/erpnext/buying/doctype/supplier/supplier.json b/erpnext/buying/doctype/supplier/supplier.json index 1ab171ae37..7b0e6f8b25 100644 --- a/erpnext/buying/doctype/supplier/supplier.json +++ b/erpnext/buying/doctype/supplier/supplier.json @@ -27,6 +27,7 @@ "supplier_type", "pan", "language", + "allow_purchase_invoice_creation_without_purchase_order", "disabled", "warn_rfqs", "warn_pos", @@ -364,13 +365,19 @@ "fieldname": "is_frozen", "fieldtype": "Check", "label": "Is Frozen" + }, + { + "default": "0", + "fieldname": "allow_purchase_invoice_creation_without_purchase_order", + "fieldtype": "Check", + "label": "Allow Purchase Invoice creation without Purchase Order" } ], "icon": "fa fa-user", "idx": 370, "image_field": "image", "links": [], - "modified": "2019-12-19 18:17:16.614567", + "modified": "2020-03-06 18:19:25.235183", "modified_by": "Administrator", "module": "Buying", "name": "Supplier", From fcb54762a185d134838b37f4a668162d3a52f426 Mon Sep 17 00:00:00 2001 From: Ronel Cabrera Date: Mon, 18 Nov 2019 17:00:07 +0800 Subject: [PATCH 05/50] feat(Contacts): select billing contact for sales invoice --- erpnext/accounts/party.py | 32 +++++++++- .../erpnext_integrations/custom/contact.json | 60 +++++++++++++++++++ 2 files changed, 89 insertions(+), 3 deletions(-) create mode 100644 erpnext/erpnext_integrations/custom/contact.json diff --git a/erpnext/accounts/party.py b/erpnext/accounts/party.py index 422ace64f5..e9c652ecba 100644 --- a/erpnext/accounts/party.py +++ b/erpnext/accounts/party.py @@ -46,7 +46,7 @@ def _get_party_details(party=None, account=None, party_type="Customer", company= currency = party.default_currency if party.get("default_currency") else get_company_currency(company) party_address, shipping_address = set_address_details(party_details, party, party_type, doctype, company, party_address, company_address, shipping_address) - set_contact_details(party_details, party, party_type) + set_contact_details(party_details, party, party_type, doctype) set_other_values(party_details, party, party_type) set_price_list(party_details, party, party_type, price_list, pos_profile) @@ -115,8 +115,11 @@ def set_address_details(party_details, party, party_type, doctype=None, company= def get_regional_address_details(party_details, doctype, company): pass -def set_contact_details(party_details, party, party_type): - party_details.contact_person = get_default_contact(party_type, party.name) +def set_contact_details(party_details, party, party_type, doctype=None): + if doctype == 'Sales Invoice': + party_details.contact_person = get_default_billing_contact(doctype, party.name) + else: + party_details.contact_person = get_default_contact(party_type, party.name) if not party_details.contact_person: party_details.update({ @@ -615,3 +618,26 @@ def get_partywise_advanced_payment_amount(party_type, posting_date = None): if data: return frappe._dict(data) + +def get_default_billing_contact(doctype, name): + """ + Returns default contact for the given doctype and name. + Can be ordered by `contact_type` to either is_primary_contact or is_billing_contact. + """ + out = frappe.db.sql(""" + SELECT dl.parent, c.is_primary_contact, c.is_billing_contact + FROM `tabDynamic Link` dl + INNER JOIN tabContact c ON c.name = dl.parent + WHERE + dl.link_doctype=%s AND + dl.link_name=%s AND + dl.parenttype = "Contact" + ORDER BY is_billing_contact DESC, is_primary_contact DESC + """, (doctype, name)) + if out: + try: + return out[0][0] + except: + return None + else: + return None \ No newline at end of file diff --git a/erpnext/erpnext_integrations/custom/contact.json b/erpnext/erpnext_integrations/custom/contact.json new file mode 100644 index 0000000000..98a4bbc795 --- /dev/null +++ b/erpnext/erpnext_integrations/custom/contact.json @@ -0,0 +1,60 @@ +{ + "custom_fields": [ + { + "_assign": null, + "_comments": null, + "_liked_by": null, + "_user_tags": null, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "collapsible_depends_on": null, + "columns": 0, + "creation": "2019-12-02 11:00:03.432994", + "default": null, + "depends_on": null, + "description": null, + "docstatus": 0, + "dt": "Contact", + "fetch_from": null, + "fetch_if_empty": 0, + "fieldname": "is_billing_contact", + "fieldtype": "Check", + "hidden": 0, + "idx": 27, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "insert_after": "is_primary_contact", + "label": "Is Billing Contact", + "length": 0, + "modified": "2019-12-02 11:00:03.432994", + "modified_by": "Administrator", + "name": "Contact-is_billing_contact", + "no_copy": 0, + "options": null, + "owner": "Administrator", + "parent": null, + "parentfield": null, + "parenttype": null, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "print_width": null, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "translatable": 0, + "unique": 0, + "width": null + } + ], + "custom_perms": [], + "doctype": "Contact", + "property_setters": [], + "sync_on_migrate": 1 +} \ No newline at end of file From 4635ff93684ebd623a291b061b8a0528ebea91e1 Mon Sep 17 00:00:00 2001 From: Myuddin khatri Date: Thu, 12 Mar 2020 14:30:28 +0530 Subject: [PATCH 06/50] fix(shopping-cart): address is made mandatory to place order --- erpnext/shopping_cart/cart.py | 24 +++++++++---------- erpnext/templates/includes/cart.js | 5 ++-- .../templates/includes/cart/cart_address.html | 18 ++++++++++---- 3 files changed, 27 insertions(+), 20 deletions(-) diff --git a/erpnext/shopping_cart/cart.py b/erpnext/shopping_cart/cart.py index 1dac9bd162..39f8b8d358 100644 --- a/erpnext/shopping_cart/cart.py +++ b/erpnext/shopping_cart/cart.py @@ -38,14 +38,14 @@ def get_cart_quotation(doc=None): addresses = get_address_docs(party=party) if not doc.customer_address and addresses: - update_cart_address("customer_address", addresses[0].name) + update_cart_address("billing", addresses[0].name) return { "doc": decorate_quotation_doc(doc), "shipping_addresses": [{"name": address.name, "display": address.display} - for address in addresses], + for address in addresses if address.address_type == "Shipping"], "billing_addresses": [{"name": address.name, "display": address.display} - for address in addresses], + for address in addresses if address.address_type == "Billing"], "shipping_rules": get_applicable_shipping_rules(party), "cart_settings": frappe.get_cached_doc("Shopping Cart Settings") } @@ -64,6 +64,9 @@ def place_order(): # company used to create customer accounts frappe.defaults.set_user_default("company", quotation.company) + if not (quotation.shipping_address_name or quotation.customer_address): + frappe.throw(_("Set Shipping Address or Billing Address")) + from erpnext.selling.doctype.quotation.quotation import _make_sales_order sales_order = frappe.get_doc(_make_sales_order(quotation.name, ignore_permissions=True)) sales_order.payment_schedule = [] @@ -194,21 +197,16 @@ def get_terms_and_conditions(terms_name): return frappe.db.get_value('Terms and Conditions', terms_name, 'terms') @frappe.whitelist() -def update_cart_address(address_fieldname, address_name): +def update_cart_address(address_type, address_name): quotation = _get_cart_quotation() address_display = get_address_display(frappe.get_doc("Address", address_name).as_dict()) - if address_fieldname == "shipping_address_name": - quotation.shipping_address_name = address_name - quotation.shipping_address = address_display - - if not quotation.customer_address: - address_fieldname == "customer_address" - - if address_fieldname == "customer_address": + if address_type.lower() == "billing": quotation.customer_address = address_name quotation.address_display = address_display - + elif address_type.lower() == "shipping": + quotation.shipping_address_name = address_name + quotation.shipping_address = address_display apply_cart_settings(quotation=quotation) diff --git a/erpnext/templates/includes/cart.js b/erpnext/templates/includes/cart.js index 456bc7e413..c6dfd35e29 100644 --- a/erpnext/templates/includes/cart.js +++ b/erpnext/templates/includes/cart.js @@ -26,15 +26,14 @@ $.extend(shopping_cart, { bind_address_select: function() { $(".cart-addresses").on('click', '.address-card', function(e) { const $card = $(e.currentTarget); - const address_fieldname = $card.closest('[data-fieldname]').attr('data-fieldname'); + const address_type = $card.closest('[data-address-type]').attr('data-address-type'); const address_name = $card.closest('[data-address-name]').attr('data-address-name'); - return frappe.call({ type: "POST", method: "erpnext.shopping_cart.cart.update_cart_address", freeze: true, args: { - address_fieldname, + address_type, address_name }, callback: function(r) { diff --git a/erpnext/templates/includes/cart/cart_address.html b/erpnext/templates/includes/cart/cart_address.html index f7f3548320..60de3af17b 100644 --- a/erpnext/templates/includes/cart/cart_address.html +++ b/erpnext/templates/includes/cart/cart_address.html @@ -18,7 +18,7 @@
{{ _("Shipping Address") }}
{% for address in shipping_addresses %} -
+
{% include "templates/includes/cart/address_card.html" %}
{% endfor %} @@ -28,7 +28,7 @@
{{ _("Billing Address") }}
{% for address in billing_addresses %} -
+
{% include "templates/includes/cart/address_card.html" %}
{% endfor %} @@ -123,9 +123,19 @@ frappe.ready(() => { primary_action: (values) => { frappe.call('erpnext.shopping_cart.cart.add_new_address', { doc: values }) .then(r => { - d.hide(); - window.location.reload(); + frappe.call({ + method: "erpnext.shopping_cart.cart.update_cart_address", + args: { + address_type: r.message.address_type, + address_name: r.message.name + }, + callback: function (r) { + d.hide(); + window.location.reload(); + } + }); }); + } }) From b9631a501fb485f40fdc8d19e83e907969c0e860 Mon Sep 17 00:00:00 2001 From: Myuddin khatri Date: Thu, 12 Mar 2020 16:04:22 +0530 Subject: [PATCH 07/50] fix(shopping-cart): setting billing and shipping address setting billing and shipping address --- erpnext/shopping_cart/cart.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/erpnext/shopping_cart/cart.py b/erpnext/shopping_cart/cart.py index 39f8b8d358..e11e1bb5dc 100644 --- a/erpnext/shopping_cart/cart.py +++ b/erpnext/shopping_cart/cart.py @@ -65,7 +65,7 @@ def place_order(): frappe.defaults.set_user_default("company", quotation.company) if not (quotation.shipping_address_name or quotation.customer_address): - frappe.throw(_("Set Shipping Address or Billing Address")) + frappe.throw(_("Set Shipping Address or Billing Address")) from erpnext.selling.doctype.quotation.quotation import _make_sales_order sales_order = frappe.get_doc(_make_sales_order(quotation.name, ignore_permissions=True)) @@ -204,9 +204,11 @@ def update_cart_address(address_type, address_name): if address_type.lower() == "billing": quotation.customer_address = address_name quotation.address_display = address_display + quotation.shipping_address_name == quotation.shipping_address_name or address_name elif address_type.lower() == "shipping": quotation.shipping_address_name = address_name quotation.shipping_address = address_display + quotation.customer_address == quotation.customer_address or address_name apply_cart_settings(quotation=quotation) From 0b7acc0fd6721fd43d3d379263dc91434b1f4409 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Fri, 13 Mar 2020 11:51:14 +0530 Subject: [PATCH 08/50] fix: Create Item tax template only for specific account types --- erpnext/patches/v12_0/move_item_tax_to_item_tax_template.py | 4 +++- 1 file changed, 3 insertions(+), 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 31d500ea2f..8889056e2d 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 @@ -118,7 +118,9 @@ def get_item_tax_template(item_tax_templates, item_tax_map, item_code, parenttyp account.insert() tax_type = account.name - if tax_type: + account_type = frappe.get_cached_value("Account", tax_type, "account_type") + + if tax_type and account_type in ('Tax', 'Chargeable', 'Income Account', 'Expense Account', 'Expenses Included In Valuation'): item_tax_template.append("taxes", {"tax_type": tax_type, "tax_rate": tax_rate}) item_tax_templates.setdefault(item_tax_template.title, {}) item_tax_templates[item_tax_template.title][tax_type] = tax_rate From eeb1922e37a6123ceb11891ee75b716a175cb212 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Tue, 17 Mar 2020 11:43:34 +0530 Subject: [PATCH 09/50] fix: Add check to skip SO and DN in customer master --- .../doctype/sales_invoice/sales_invoice.py | 15 ++++++++++----- erpnext/selling/doctype/customer/customer.json | 16 +++++++++++++++- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index 7f7938db24..fd1553a9da 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -542,12 +542,17 @@ class SalesInvoice(SellingController): """check in manage account if sales order / delivery note required or not.""" if self.is_return: return - dic = {'Sales Order':['so_required', 'is_pos'],'Delivery Note':['dn_required', 'update_stock']} - for i in dic: - if frappe.db.get_single_value('Selling Settings', dic[i][0]) == 'Yes': + + prev_doc_field_map = {'Sales Order': ['so_required', 'is_pos'],'Delivery Note': ['dn_required', 'update_stock']} + for key, value in iteritems(prev_doc_field_map): + if frappe.db.get_single_value('Selling Settings', value[0]) == 'Yes': + + if frappe.get_value('Customer', self.customer, value[0]): + continue + for d in self.get('items'): - if (d.item_code and not d.get(i.lower().replace(' ','_')) and not self.get(dic[i][1])): - msgprint(_("{0} is mandatory for Item {1}").format(i,d.item_code), raise_exception=1) + if (d.item_code and not d.get(key.lower().replace(' ', '_')) and not self.get(value[1])): + msgprint(_("{0} is mandatory for Item {1}").format(key, d.item_code), raise_exception=1) def validate_proj_cust(self): diff --git a/erpnext/selling/doctype/customer/customer.json b/erpnext/selling/doctype/customer/customer.json index df563ee8ff..557c7151d9 100644 --- a/erpnext/selling/doctype/customer/customer.json +++ b/erpnext/selling/doctype/customer/customer.json @@ -25,6 +25,8 @@ "territory", "tax_id", "tax_category", + "so_required", + "dn_required", "disabled", "is_internal_customer", "represents_company", @@ -465,13 +467,25 @@ "fieldtype": "Table", "label": "Credit Limit", "options": "Customer Credit Limit" + }, + { + "default": "0", + "fieldname": "so_required", + "fieldtype": "Check", + "label": "Allow Sales Invoice Creation Without Sales Order" + }, + { + "default": "0", + "fieldname": "dn_required", + "fieldtype": "Check", + "label": "Allow Sales Invoice Creation Without Delivery Note" } ], "icon": "fa fa-user", "idx": 363, "image_field": "image", "links": [], - "modified": "2020-01-29 20:36:37.879581", + "modified": "2020-03-17 11:03:42.706907", "modified_by": "Administrator", "module": "Selling", "name": "Customer", From e7aefc116384784e1ed8988a2c4abccbdf9c158b Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Tue, 17 Mar 2020 11:44:02 +0530 Subject: [PATCH 10/50] fix: Add check to skip PR in supplier master --- .../doctype/purchase_invoice/purchase_invoice.py | 8 ++++++-- erpnext/buying/doctype/supplier/supplier.json | 11 +++++++++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py index 099fa64963..1db7d37db0 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -296,17 +296,21 @@ class PurchaseInvoice(BuyingController): if not d.purchase_order: throw(_("""Purchase Order Required for item {0} To submit the invoice without purchase order please set - {1} as {2} in {3}""").format(frappe.bold(d.item_code), frappe.bold('Purchase Order Required'), + {1} as {2} in {3}""").format(frappe.bold(d.item_code), frappe.bold(_('Purchase Order Required')), frappe.bold('No'), get_link_to_form('Buying Settings', 'Buying Settings', 'Buying Settings'))) def pr_required(self): stock_items = self.get_stock_items() if frappe.db.get_value("Buying Settings", None, "pr_required") == 'Yes': + + if frappe.get_value('Supplier', self.supplier, 'allow_purchase_invoice_creation_without_purchase_receipt'): + return + for d in self.get('items'): if not d.purchase_receipt and d.item_code in stock_items: throw(_("""Purchase Receipt Required for item {0} To submit the invoice without purchase receipt please set - {1} as {2} in {3}""").format(frappe.bold(d.item_code), frappe.bold('Purchase Receipt Required'), + {1} as {2} in {3}""").format(frappe.bold(d.item_code), frappe.bold(_('Purchase Receipt Required')), frappe.bold('No'), get_link_to_form('Buying Settings', 'Buying Settings', 'Buying Settings'))) def validate_write_off_account(self): diff --git a/erpnext/buying/doctype/supplier/supplier.json b/erpnext/buying/doctype/supplier/supplier.json index 7b0e6f8b25..4606395ebe 100644 --- a/erpnext/buying/doctype/supplier/supplier.json +++ b/erpnext/buying/doctype/supplier/supplier.json @@ -28,6 +28,7 @@ "pan", "language", "allow_purchase_invoice_creation_without_purchase_order", + "allow_purchase_invoice_creation_without_purchase_receipt", "disabled", "warn_rfqs", "warn_pos", @@ -370,14 +371,20 @@ "default": "0", "fieldname": "allow_purchase_invoice_creation_without_purchase_order", "fieldtype": "Check", - "label": "Allow Purchase Invoice creation without Purchase Order" + "label": "Allow Purchase Invoice Creation Without Purchase Order" + }, + { + "default": "0", + "fieldname": "allow_purchase_invoice_creation_without_purchase_receipt", + "fieldtype": "Check", + "label": "Allow Purchase Invoice Creation Without Purchase Receipt" } ], "icon": "fa fa-user", "idx": 370, "image_field": "image", "links": [], - "modified": "2020-03-06 18:19:25.235183", + "modified": "2020-03-17 09:48:30.578242", "modified_by": "Administrator", "module": "Buying", "name": "Supplier", From 815c36a4eb68b0de5cab71519e9105c26c4c64ba Mon Sep 17 00:00:00 2001 From: marination Date: Thu, 26 Mar 2020 14:49:28 +0530 Subject: [PATCH 11/50] fix: Updated Bin Requested Qty logic --- erpnext/patches.txt | 1 + .../v12_0/recalculate_requested_qty_in_bin.py | 13 ++++++++++++ erpnext/stock/stock_balance.py | 21 ++++++++++++++----- 3 files changed, 30 insertions(+), 5 deletions(-) create mode 100644 erpnext/patches/v12_0/recalculate_requested_qty_in_bin.py diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 8aec8bddb9..6ff8b909c3 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -660,3 +660,4 @@ erpnext.patches.v12_0.set_job_offer_applicant_email erpnext.patches.v12_0.create_irs_1099_field_united_states erpnext.patches.v12_0.move_bank_account_swift_number_to_bank erpnext.patches.v12_0.rename_bank_reconciliation_fields # 2020-01-22 +erpnext.patches.v12_0.recalculate_requested_qty_in_bin \ No newline at end of file diff --git a/erpnext/patches/v12_0/recalculate_requested_qty_in_bin.py b/erpnext/patches/v12_0/recalculate_requested_qty_in_bin.py new file mode 100644 index 0000000000..8267df95e1 --- /dev/null +++ b/erpnext/patches/v12_0/recalculate_requested_qty_in_bin.py @@ -0,0 +1,13 @@ +from __future__ import unicode_literals +import frappe +from erpnext.stock.stock_balance import update_bin_qty, get_indented_qty + +def execute(): + bin_details = frappe.db.sql(""" + SELECT item_code, warehouse + FROM `tabBin`""",as_dict=1) + + for entry in bin_details: + update_bin_qty(entry.get("item_code"), entry.get("warehouse"), { + "indented_qty": get_indented_qty(entry.get("item_code"), entry.get("warehouse")) + }) \ No newline at end of file diff --git a/erpnext/stock/stock_balance.py b/erpnext/stock/stock_balance.py index e5dc6b12df..2bdb04ed2c 100644 --- a/erpnext/stock/stock_balance.py +++ b/erpnext/stock/stock_balance.py @@ -113,13 +113,24 @@ def get_reserved_qty(item_code, warehouse): return flt(reserved_qty[0][0]) if reserved_qty else 0 def get_indented_qty(item_code, warehouse): - indented_qty = frappe.db.sql("""select sum((mr_item.qty - mr_item.ordered_qty) * mr_item.conversion_factor) + inward_qty = frappe.db.sql("""select sum((mr_item.qty - mr_item.ordered_qty) * mr_item.conversion_factor) + from `tabMaterial Request Item` mr_item, `tabMaterial Request` mr + where mr_item.item_code=%s and mr_item.warehouse=%s + and mr.material_request_type in ('Purchase', 'Manufacture') + and mr_item.qty > mr_item.ordered_qty and mr_item.parent=mr.name + and mr.status!='Stopped' and mr.docstatus=1""", (item_code, warehouse)) + + outward_qty = frappe.db.sql("""select sum((mr_item.qty - mr_item.ordered_qty) * mr_item.conversion_factor) from `tabMaterial Request Item` mr_item, `tabMaterial Request` mr where mr_item.item_code=%s and mr_item.warehouse=%s + and mr.material_request_type in ('Material Issue', 'Material Transfer') and mr_item.qty > mr_item.ordered_qty and mr_item.parent=mr.name and mr.status!='Stopped' and mr.docstatus=1""", (item_code, warehouse)) - return flt(indented_qty[0][0]) if indented_qty else 0 + inward_qty, outward_qty = flt(inward_qty[0][0]) if inward_qty else 0, flt(outward_qty[0][0]) if outward_qty else 0 + indented_qty = inward_qty - outward_qty + + return indented_qty def get_ordered_qty(item_code, warehouse): ordered_qty = frappe.db.sql(""" @@ -145,9 +156,9 @@ def update_bin_qty(item_code, warehouse, qty_dict=None): from erpnext.stock.utils import get_bin bin = get_bin(item_code, warehouse) mismatch = False - for fld, val in qty_dict.items(): - if flt(bin.get(fld)) != flt(val): - bin.set(fld, flt(val)) + for field, value in qty_dict.items(): + if flt(bin.get(field)) != flt(value): + bin.set(field, flt(value)) mismatch = True if mismatch: From 8488ef8eb16c5ec2a0853dee9e0c2f3bbe90e29c Mon Sep 17 00:00:00 2001 From: Saqib Ansari Date: Sat, 28 Mar 2020 14:07:09 +0530 Subject: [PATCH 12/50] fix: customer group price list not fetched in pos --- .../accounts/doctype/sales_invoice/sales_invoice.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index ba1ceffd14..bd18d5799b 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -437,13 +437,16 @@ class SalesInvoice(SellingController): if (not for_validate) or (for_validate and not self.get(fieldname)): self.set(fieldname, pos.get(fieldname)) - customer_price_list = frappe.get_value("Customer", self.customer, 'default_price_list') - if pos.get("company_address"): self.company_address = pos.get("company_address") - if not customer_price_list: - self.set('selling_price_list', pos.get('selling_price_list')) + customer_price_list, customer_group = frappe.get_value("Customer", self.customer, ['default_price_list', 'customer_group']) + + customer_group_price_list = frappe.get_value("Customer Group", customer_group, 'default_price_list') + + selling_price_list = customer_price_list or customer_group_price_list or pos.get('selling_price_list') + + self.set('selling_price_list', selling_price_list) if not for_validate: self.update_stock = cint(pos.get("update_stock")) From e7c45654839c86575f1140afb6d53c8b03ea61cc Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Sat, 28 Mar 2020 14:56:45 +0530 Subject: [PATCH 13/50] fix: item code showing as mandatory even if the 'Item Naming By' is set as Naming Series in stock settings --- erpnext/public/js/utils/item_quick_entry.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/erpnext/public/js/utils/item_quick_entry.js b/erpnext/public/js/utils/item_quick_entry.js index 2947d5b98e..27ef107ace 100644 --- a/erpnext/public/js/utils/item_quick_entry.js +++ b/erpnext/public/js/utils/item_quick_entry.js @@ -8,12 +8,19 @@ frappe.ui.form.ItemQuickEntryForm = frappe.ui.form.QuickEntryForm.extend({ render_dialog: function() { this.mandatory = this.get_variant_fields().concat(this.mandatory); this.mandatory = this.mandatory.concat(this.get_attributes_fields()); + this.check_naming_series_based_on(); this._super(); this.init_post_render_dialog_operations(); this.preset_fields_for_template(); this.dialog.$wrapper.find('.edit-full').text(__('Edit in full page for more options like assets, serial nos, batches etc.')) }, + check_naming_series_based_on: function() { + if (frappe.defaults.get_default("item_naming_by") === "Naming Series") { + this.mandatory = this.mandatory.filter(d => d.fieldname !== "item_code"); + } + }, + init_post_render_dialog_operations: function() { this.dialog.fields_dict.attribute_html.$wrapper.append(frappe.render_template("item_quick_entry")); this.init_for_create_variant_trigger(); From 0ec01d98d68753736aed4c734d481896476b8c43 Mon Sep 17 00:00:00 2001 From: Saqib Ansari Date: Sat, 28 Mar 2020 16:11:23 +0530 Subject: [PATCH 14/50] fix: payment request status fixes --- .../payment_request/payment_request.json | 1837 +++-------------- .../payment_request/payment_request.py | 8 +- .../payment_request/payment_request_list.js | 8 +- 3 files changed, 346 insertions(+), 1507 deletions(-) diff --git a/erpnext/accounts/doctype/payment_request/payment_request.json b/erpnext/accounts/doctype/payment_request/payment_request.json index bff995ec5a..97ae5ffde3 100644 --- a/erpnext/accounts/doctype/payment_request/payment_request.json +++ b/erpnext/accounts/doctype/payment_request/payment_request.json @@ -1,1560 +1,387 @@ { - "allow_copy": 0, - "allow_events_in_timeline": 0, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, - "autoname": "naming_series:", - "beta": 0, - "creation": "2015-12-15 22:23:24.745065", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "", - "editable_grid": 0, - "engine": "InnoDB", + "autoname": "naming_series:", + "creation": "2015-12-15 22:23:24.745065", + "doctype": "DocType", + "engine": "InnoDB", + "field_order": [ + "payment_request_type", + "transaction_date", + "column_break_2", + "naming_series", + "mode_of_payment", + "party_details", + "party_type", + "party", + "column_break_4", + "reference_doctype", + "reference_name", + "transaction_details", + "grand_total", + "is_a_subscription", + "column_break_18", + "currency", + "subscription_section", + "subscription_plans", + "bank_account_details", + "bank_account", + "bank", + "bank_account_no", + "account", + "column_break_11", + "iban", + "branch_code", + "swift_number", + "recipient_and_message", + "print_format", + "email_to", + "subject", + "column_break_9", + "payment_gateway_account", + "status", + "make_sales_invoice", + "section_break_10", + "message", + "message_examples", + "mute_email", + "payment_url", + "section_break_7", + "payment_gateway", + "payment_account", + "payment_order", + "amended_from" + ], "fields": [ { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "Inward", - "fieldname": "payment_request_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": "Payment Request Type", - "length": 0, - "no_copy": 0, - "options": "Outward\nInward", - "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": "Inward", + "fieldname": "payment_request_type", + "fieldtype": "Select", + "label": "Payment Request Type", + "options": "Outward\nInward", + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 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": 0, - "label": "Transaction 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": "transaction_date", + "fieldtype": "Date", + "label": "Transaction Date" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break_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, - "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_2", + "fieldtype": "Column Break" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 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": 1, - "in_standard_filter": 0, - "label": "Series", - "length": 0, - "no_copy": 1, - "options": "ACC-PRQ-.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 - }, + "fieldname": "naming_series", + "fieldtype": "Select", + "in_list_view": 1, + "label": "Series", + "no_copy": 1, + "options": "ACC-PRQ-.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": "mode_of_payment", - "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": "Mode of Payment", - "length": 0, - "no_copy": 0, - "options": "Mode of Payment", - "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": "mode_of_payment", + "fieldtype": "Link", + "label": "Mode of Payment", + "options": "Mode of Payment" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "party_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": "Party 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 - }, + "fieldname": "party_details", + "fieldtype": "Section Break", + "label": "Party Details" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "party_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": "Party Type", - "length": 0, - "no_copy": 0, - "options": "DocType", - "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": "party_type", + "fieldtype": "Link", + "label": "Party Type", + "options": "DocType" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "party", - "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": "Party", - "length": 0, - "no_copy": 0, - "options": "party_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 - }, + "fieldname": "party", + "fieldtype": "Dynamic Link", + "label": "Party", + "options": "party_type" + }, { - "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 - }, + "fieldname": "column_break_4", + "fieldtype": "Column Break" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "reference_doctype", - "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": "Reference Doctype", - "length": 0, - "no_copy": 1, - "options": "DocType", - "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 - }, + "fieldname": "reference_doctype", + "fieldtype": "Link", + "in_standard_filter": 1, + "label": "Reference Doctype", + "no_copy": 1, + "options": "DocType", + "print_hide": 1, + "read_only": 1, + "report_hide": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "reference_name", - "fieldtype": "Dynamic 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": "Reference Name", - "length": 0, - "no_copy": 1, - "options": "reference_doctype", - "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": "reference_name", + "fieldtype": "Dynamic Link", + "in_global_search": 1, + "in_standard_filter": 1, + "label": "Reference Name", + "no_copy": 1, + "options": "reference_doctype", + "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": "transaction_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": "Transaction 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 - }, + "fieldname": "transaction_details", + "fieldtype": "Section Break", + "label": "Transaction Details" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "description": "Amount in customer's currency", - "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": 0, - "in_standard_filter": 0, - "label": "Amount", - "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 - }, + "description": "Amount in customer's currency", + "fieldname": "grand_total", + "fieldtype": "Currency", + "label": "Amount", + "options": "currency" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "is_a_subscription", - "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 a Subscription", - "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_a_subscription", + "fieldtype": "Check", + "label": "Is a Subscription" + }, { - "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 - }, + "fieldname": "column_break_18", + "fieldtype": "Column Break" + }, { - "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": "Transaction Currency", - "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": "currency", + "fieldtype": "Link", + "label": "Transaction Currency", + "options": "Currency", + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "collapsible_depends_on": "", - "columns": 0, - "depends_on": "eval:doc.is_a_subscription", - "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 - }, + "depends_on": "eval:doc.is_a_subscription", + "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": "subscription_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": "Subscription 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": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "subscription_plans", + "fieldtype": "Table", + "label": "Subscription Plans", + "options": "Subscription Plan Detail" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 1, - "columns": 0, - "fieldname": "bank_account_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": "Bank Account 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": "bank_account_details", + "fieldtype": "Section Break", + "label": "Bank Account Details" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "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": "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 - }, + "fieldname": "bank_account", + "fieldtype": "Link", + "label": "Bank Account", + "options": "Bank Account" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_from": "bank_account.bank", - "fieldname": "bank", - "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": "Bank", - "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 - }, + "fetch_from": "bank_account.bank", + "fieldname": "bank", + "fieldtype": "Read Only", + "label": "Bank" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_from": "bank_account.bank_account_no", - "fieldname": "bank_account_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": "Bank Account 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 - }, + "fetch_from": "bank_account.bank_account_no", + "fieldname": "bank_account_no", + "fieldtype": "Read Only", + "label": "Bank Account No" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_from": "bank_account.account", - "fieldname": "account", - "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": "Account", - "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 - }, + "fetch_from": "bank_account.account", + "fieldname": "account", + "fieldtype": "Read Only", + "label": "Account" + }, { - "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, - "fetch_from": "bank_account.iban", - "fieldname": "iban", - "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": "IBAN", - "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 - }, + "fetch_from": "bank_account.iban", + "fieldname": "iban", + "fieldtype": "Read Only", + "label": "IBAN" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_from": "bank_account.branch_code", - "fieldname": "branch_code", - "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": "Branch Code", - "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 - }, + "fetch_from": "bank_account.branch_code", + "fieldname": "branch_code", + "fieldtype": "Read Only", + "label": "Branch Code" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_from": "bank_account.swift_number", - "fieldname": "swift_number", - "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": "SWIFT Number", - "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 - }, + "fetch_from": "bank_account.swift_number", + "fieldname": "swift_number", + "fieldtype": "Read Only", + "label": "SWIFT Number" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "eval: doc.payment_request_type == 'Inward'", - "fieldname": "recipient_and_message", - "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": "Recipient Message And Payment 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 - }, + "depends_on": "eval: doc.payment_request_type == 'Inward'", + "fieldname": "recipient_and_message", + "fieldtype": "Section Break", + "label": "Recipient Message And Payment Details" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "", - "fieldname": "print_format", - "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": "Print Format", - "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": "print_format", + "fieldtype": "Select", + "label": "Print Format" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "email_to", - "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": "To", - "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": "email_to", + "fieldtype": "Data", + "in_global_search": 1, + "label": "To" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "subject", - "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": "Subject", - "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": "subject", + "fieldtype": "Data", + "in_global_search": 1, + "label": "Subject" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "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, - "translatable": 0, - "unique": 0 - }, + "fieldname": "column_break_9", + "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.payment_request_type == 'Inward'", - "fieldname": "payment_gateway_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": "Payment Gateway Account", - "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 - }, + "depends_on": "eval: doc.payment_request_type == 'Inward'", + "fieldname": "payment_gateway_account", + "fieldtype": "Link", + "label": "Payment Gateway Account", + "options": "Payment Gateway Account" + }, { - "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": 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": "\nDraft\nInitiated\nPayment Ordered\nPaid\nFailed\nCancelled", - "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 - }, + "default": "Draft", + "fieldname": "status", + "fieldtype": "Select", + "hidden": 1, + "in_standard_filter": 1, + "label": "Status", + "options": "\nDraft\nRequested\nInitiated\nPartially Paid\nPayment Ordered\nPaid\nFailed\nCancelled", + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "eval:doc.reference_doctype==\"Sales Order\"", - "fieldname": "make_sales_invoice", - "fieldtype": "Check", - "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": "Make Sales Invoice", - "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 - }, + "default": "0", + "depends_on": "eval:doc.reference_doctype==\"Sales Order\"", + "fieldname": "make_sales_invoice", + "fieldtype": "Check", + "hidden": 1, + "label": "Make Sales Invoice", + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "eval: doc.payment_request_type == 'Inward'", - "fieldname": "section_break_10", - "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 - }, + "depends_on": "eval: doc.payment_request_type == 'Inward'", + "fieldname": "section_break_10", + "fieldtype": "Section Break" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "message", - "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": "Message", - "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": "message", + "fieldtype": "Text", + "label": "Message" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "message_examples", - "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": "Message Examples", - "length": 0, - "no_copy": 0, - "options": "
Message Example
\n\n<p>Dear {{ doc.contact_person }},</p>\n\n<p>Requesting payment for {{ doc.doctype }}, {{ doc.name }} for {{ doc.grand_total }}.</p>\n\n<a href=\"{{ payment_url }}\"> click here to pay </a>\n\n
\n", - "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": "message_examples", + "fieldtype": "HTML", + "label": "Message Examples", + "options": "
Message Example
\n\n<p>Dear {{ doc.contact_person }},</p>\n\n<p>Requesting payment for {{ doc.doctype }}, {{ doc.name }} for {{ doc.grand_total }}.</p>\n\n<a href=\"{{ payment_url }}\"> click here to pay </a>\n\n
\n", + "print_hide": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "mute_email", - "fieldtype": "Check", - "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": "Mute Email", - "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 - }, + "default": "0", + "fieldname": "mute_email", + "fieldtype": "Check", + "hidden": 1, + "label": "Mute Email", + "no_copy": 1, + "print_hide": 1, + "read_only": 1, + "report_hide": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "payment_url", - "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": "payment_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": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "payment_url", + "fieldtype": "Small Text", + "hidden": 1, + "label": "payment_url", + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 1, - "collapsible_depends_on": "doc.payment_gateway_account", - "columns": 0, - "depends_on": "eval: doc.payment_request_type == 'Inward'", - "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": "Payment Gateway 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": "doc.payment_gateway_account", + "depends_on": "eval: doc.payment_request_type == 'Inward'", + "fieldname": "section_break_7", + "fieldtype": "Section Break", + "label": "Payment Gateway Details" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_from": "payment_gateway_account.payment_gateway", - "fieldname": "payment_gateway", - "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": "Payment Gateway", - "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 - }, + "fetch_from": "payment_gateway_account.payment_gateway", + "fieldname": "payment_gateway", + "fieldtype": "Read Only", + "label": "Payment Gateway" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_from": "payment_gateway_account.payment_account", - "fieldname": "payment_account", - "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": "Payment Account", - "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": "payment_gateway_account.payment_account", + "fieldname": "payment_account", + "fieldtype": "Read Only", + "label": "Payment Account", + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "payment_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": "Payment Order", - "length": 0, - "no_copy": 0, - "options": "Payment Order", - "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": "payment_order", + "fieldtype": "Link", + "label": "Payment Order", + "options": "Payment Order", + "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": 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": "Payment Request", - "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": "Payment Request", + "print_hide": 1, + "read_only": 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": "2019-02-18 18:52:34.203239", - "modified_by": "Administrator", - "module": "Accounts", - "name": "Payment Request", - "name_case": "", - "owner": "Administrator", + ], + "is_submittable": 1, + "modified": "2020-03-28 16:07:31.960798", + "modified_by": "Administrator", + "module": "Accounts", + "name": "Payment Request", + "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": "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": 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": "Accounts 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": "Accounts Manager", + "share": 1, + "submit": 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/accounts/doctype/payment_request/payment_request.py b/erpnext/accounts/doctype/payment_request/payment_request.py index 0fade8c456..49c0e36204 100644 --- a/erpnext/accounts/doctype/payment_request/payment_request.py +++ b/erpnext/accounts/doctype/payment_request/payment_request.py @@ -66,6 +66,8 @@ class PaymentRequest(Document): if self.payment_request_type == 'Outward': self.db_set('status', 'Initiated') return + elif self.payment_request_type == 'Inward': + self.db_set('status', 'Requested') send_mail = self.payment_gateway_validation() ref_doc = frappe.get_doc(self.reference_doctype, self.reference_name) @@ -422,10 +424,14 @@ def make_status_as_paid(doc, method): "docstatus": 1}) if payment_request_name: + outstanding_amt = frappe.get_value(ref.reference_doctype, ref.reference_name, 'outstanding_amount') doc = frappe.get_doc("Payment Request", payment_request_name) - if doc.status != "Paid": + if doc.status != "Paid" and outstanding_amt <= 0: doc.db_set('status', 'Paid') frappe.db.commit() + elif doc.status != "Partially Paid" and outstanding_amt != doc.grand_total: + doc.db_set('status', 'Partially Paid') + frappe.db.commit() def get_dummy_message(doc): return frappe.render_template("""{% if doc.contact_person -%} diff --git a/erpnext/accounts/doctype/payment_request/payment_request_list.js b/erpnext/accounts/doctype/payment_request/payment_request_list.js index 0caf1c2f7f..72833d235f 100644 --- a/erpnext/accounts/doctype/payment_request/payment_request_list.js +++ b/erpnext/accounts/doctype/payment_request/payment_request_list.js @@ -4,14 +4,20 @@ frappe.listview_settings['Payment Request'] = { if(doc.status == "Draft") { return [__("Draft"), "darkgrey", "status,=,Draft"]; } + if(doc.status == "Requested") { + return [__("Requested"), "green", "status,=,Requested"]; + } else if(doc.status == "Initiated") { return [__("Initiated"), "green", "status,=,Initiated"]; } + else if(doc.status == "Partially Paid") { + return [__("Partially Paid"), "orange", "status,=,Partially Paid"]; + } else if(doc.status == "Paid") { return [__("Paid"), "blue", "status,=,Paid"]; } else if(doc.status == "Cancelled") { - return [__("Cancelled"), "orange", "status,=,Cancelled"]; + return [__("Cancelled"), "red", "status,=,Cancelled"]; } } } From c33412b6ae0b5638127351c4692e9414afe30d66 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Mon, 30 Mar 2020 22:44:13 +0530 Subject: [PATCH 15/50] feat: Link blanket order and quotation --- .../doctype/blanket_order/blanket_order.js | 38 ++++++---- .../doctype/blanket_order/blanket_order.py | 70 +++++++++++-------- .../blanket_order/blanket_order_dashboard.py | 2 +- .../public/js/controllers/taxes_and_totals.js | 2 +- .../selling/doctype/quotation/quotation.py | 5 ++ .../quotation_item/quotation_item.json | 31 +++++++- 6 files changed, 100 insertions(+), 48 deletions(-) diff --git a/erpnext/manufacturing/doctype/blanket_order/blanket_order.js b/erpnext/manufacturing/doctype/blanket_order/blanket_order.js index 1cd9446c8b..4c31bd0b7d 100644 --- a/erpnext/manufacturing/doctype/blanket_order/blanket_order.js +++ b/erpnext/manufacturing/doctype/blanket_order/blanket_order.js @@ -14,27 +14,37 @@ frappe.ui.form.on('Blanket Order', { refresh: function(frm) { erpnext.hide_company(); if (frm.doc.customer && frm.doc.docstatus === 1) { - frm.add_custom_button(__('View Orders'), function() { - frappe.set_route('List', 'Sales Order', {blanket_order: frm.doc.name}); - }); - frm.add_custom_button(__("Create Sales Order"), function(){ + frm.add_custom_button(__("Sales Order"), function() { frappe.model.open_mapped_doc({ - method: "erpnext.manufacturing.doctype.blanket_order.blanket_order.make_sales_order", - frm: frm + method: "erpnext.manufacturing.doctype.blanket_order.blanket_order.make_order", + frm: frm, + args: { + doctype: 'Sales Order' + } }); - }).addClass("btn-primary"); + }, __('Create')); + + frm.add_custom_button(__("Quotation"), function() { + frappe.model.open_mapped_doc({ + method: "erpnext.manufacturing.doctype.blanket_order.blanket_order.make_order", + frm: frm, + args: { + doctype: 'Quotation' + } + }); + }, __('Create')); } if (frm.doc.supplier && frm.doc.docstatus === 1) { - frm.add_custom_button(__('View Orders'), function() { - frappe.set_route('List', 'Purchase Order', {blanket_order: frm.doc.name}); - }); - frm.add_custom_button(__("Create Purchase Order"), function(){ + frm.add_custom_button(__("Purchase Order"), function(){ frappe.model.open_mapped_doc({ - method: "erpnext.manufacturing.doctype.blanket_order.blanket_order.make_purchase_order", - frm: frm + method: "erpnext.manufacturing.doctype.blanket_order.blanket_order.make_order", + frm: frm, + args: { + doctype: 'Purchase Order' + } }); - }).addClass("btn-primary"); + }, __('Create')); } }, diff --git a/erpnext/manufacturing/doctype/blanket_order/blanket_order.py b/erpnext/manufacturing/doctype/blanket_order/blanket_order.py index 38118bd78d..5eb4c513b0 100644 --- a/erpnext/manufacturing/doctype/blanket_order/blanket_order.py +++ b/erpnext/manufacturing/doctype/blanket_order/blanket_order.py @@ -17,7 +17,7 @@ class BlanketOrder(Document): def validate_dates(self): if getdate(self.from_date) > getdate(self.to_date): - frappe.throw(_("From date cannot be greater than To date")) + frappe.throw(_("From date cannot be greater than To date")) def update_ordered_qty(self): ref_doctype = "Sales Order" if self.blanket_order_type == "Selling" else "Purchase Order" @@ -35,7 +35,14 @@ class BlanketOrder(Document): d.db_set("ordered_qty", item_ordered_qty.get(d.item_code, 0)) @frappe.whitelist() -def make_sales_order(source_name): +def make_order(source_name): + doctype = frappe.flags.args.doctype + + def update_doc(source_doc, target_doc, source_parent): + if doctype == 'Quotation': + target_doc.quotation_to = 'Customer' + target_doc.party_name = source_doc.customer + def update_item(source, target, source_parent): target_qty = source.get("qty") - source.get("ordered_qty") target.qty = target_qty if not flt(target_qty) < 0 else 0 @@ -49,10 +56,11 @@ def make_sales_order(source_name): target_doc = get_mapped_doc("Blanket Order", source_name, { "Blanket Order": { - "doctype": "Sales Order" + "doctype": doctype, + "postprocess": update_doc }, "Blanket Order Item": { - "doctype": "Sales Order Item", + "doctype": doctype + " Item", "field_map": { "rate": "blanket_order_rate", "parent": "blanket_order" @@ -62,31 +70,31 @@ def make_sales_order(source_name): }) return target_doc -@frappe.whitelist() -def make_purchase_order(source_name): - def update_item(source, target, source_parent): - target_qty = source.get("qty") - source.get("ordered_qty") - target.qty = target_qty if not flt(target_qty) < 0 else 0 - item = get_item_defaults(target.item_code, source_parent.company) - if item: - target.item_name = item.get("item_name") - target.description = item.get("description") - target.uom = item.get("stock_uom") - target.warehouse = item.get("default_warehouse") - target.against_blanket_order = 1 - target.blanket_order = source_name +# @frappe.whitelist() +# def make_purchase_order(source_name): +# def update_item(source, target, source_parent): +# target_qty = source.get("qty") - source.get("ordered_qty") +# target.qty = target_qty if not flt(target_qty) < 0 else 0 +# item = get_item_defaults(target.item_code, source_parent.company) +# if item: +# target.item_name = item.get("item_name") +# target.description = item.get("description") +# target.uom = item.get("stock_uom") +# target.warehouse = item.get("default_warehouse") +# target.against_blanket_order = 1 +# target.blanket_order = source_name - target_doc = get_mapped_doc("Blanket Order", source_name, { - "Blanket Order": { - "doctype": "Purchase Order" - }, - "Blanket Order Item": { - "doctype": "Purchase Order Item", - "field_map": { - "rate": "blanket_order_rate", - "parent": "blanket_order" - }, - "postprocess": update_item - } - }) - return target_doc \ No newline at end of file +# target_doc = get_mapped_doc("Blanket Order", source_name, { +# "Blanket Order": { +# "doctype": "Purchase Order" +# }, +# "Blanket Order Item": { +# "doctype": "Purchase Order Item", +# "field_map": { +# "rate": "blanket_order_rate", +# "parent": "blanket_order" +# }, +# "postprocess": update_item +# } +# }) +# return target_doc \ No newline at end of file diff --git a/erpnext/manufacturing/doctype/blanket_order/blanket_order_dashboard.py b/erpnext/manufacturing/doctype/blanket_order/blanket_order_dashboard.py index ed319a0cef..d9aa0ca49d 100644 --- a/erpnext/manufacturing/doctype/blanket_order/blanket_order_dashboard.py +++ b/erpnext/manufacturing/doctype/blanket_order/blanket_order_dashboard.py @@ -6,7 +6,7 @@ def get_data(): 'fieldname': 'blanket_order', 'transactions': [ { - 'items': ['Purchase Order', 'Sales Order'] + 'items': ['Purchase Order', 'Sales Order', 'Quotation'] } ] } diff --git a/erpnext/public/js/controllers/taxes_and_totals.js b/erpnext/public/js/controllers/taxes_and_totals.js index 9a5b750e8c..dbe48ec654 100644 --- a/erpnext/public/js/controllers/taxes_and_totals.js +++ b/erpnext/public/js/controllers/taxes_and_totals.js @@ -6,7 +6,7 @@ erpnext.taxes_and_totals = erpnext.payments.extend({ apply_pricing_rule_on_item: function(item){ let effective_item_rate = item.price_list_rate; - if (item.parenttype === "Sales Order" && item.blanket_order_rate) { + if (in_list(["Sales Order", "Quotation"], item.parenttype) && item.blanket_order_rate) { effective_item_rate = item.blanket_order_rate; } if(item.margin_type == "Percentage"){ diff --git a/erpnext/selling/doctype/quotation/quotation.py b/erpnext/selling/doctype/quotation/quotation.py index b79c91cef1..7c47b8ac51 100644 --- a/erpnext/selling/doctype/quotation/quotation.py +++ b/erpnext/selling/doctype/quotation/quotation.py @@ -155,6 +155,11 @@ def _make_sales_order(source_name, target_doc=None, ignore_permissions=False): def update_item(obj, target, source_parent): target.stock_qty = flt(obj.qty) * flt(obj.conversion_factor) + if obj.against_blanket_order: + target.against_blanket_order = obj.against_blanket_order + target.blanket_order = obj.blanket_order + target.blanket_order_rate = obj.blanket_order_rate + doclist = get_mapped_doc("Quotation", source_name, { "Quotation": { "doctype": "Sales Order", diff --git a/erpnext/selling/doctype/quotation_item/quotation_item.json b/erpnext/selling/doctype/quotation_item/quotation_item.json index 3ff5555e82..d50397cfad 100644 --- a/erpnext/selling/doctype/quotation_item/quotation_item.json +++ b/erpnext/selling/doctype/quotation_item/quotation_item.json @@ -55,6 +55,9 @@ "weight_uom", "reference", "warehouse", + "against_blanket_order", + "blanket_order", + "blanket_order_rate", "column_break_30", "prevdoc_doctype", "prevdoc_docname", @@ -573,12 +576,38 @@ "fieldname": "image_section", "fieldtype": "Section Break", "label": "Image" + }, + { + "depends_on": "eval:doc.against_blanket_order", + "fieldname": "blanket_order", + "fieldtype": "Link", + "label": "Blanket Order", + "no_copy": 1, + "options": "Blanket Order", + "print_hide": 1 + }, + { + "depends_on": "eval:doc.against_blanket_order", + "fieldname": "blanket_order_rate", + "fieldtype": "Currency", + "label": "Blanket Order Rate", + "no_copy": 1, + "print_hide": 1, + "read_only": 1 + }, + { + "default": "0", + "fieldname": "against_blanket_order", + "fieldtype": "Check", + "label": "Against Blanket Order", + "no_copy": 1, + "print_hide": 1 } ], "idx": 1, "istable": 1, "links": [], - "modified": "2020-03-05 14:18:58.783751", + "modified": "2020-03-30 18:40:28.782720", "modified_by": "Administrator", "module": "Selling", "name": "Quotation Item", From c014c802dd15ee4cee3633489690fcf3365cb4fa Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Mon, 30 Mar 2020 22:50:29 +0530 Subject: [PATCH 16/50] fix: Remove comments --- .../doctype/blanket_order/blanket_order.py | 31 +------------------ 1 file changed, 1 insertion(+), 30 deletions(-) diff --git a/erpnext/manufacturing/doctype/blanket_order/blanket_order.py b/erpnext/manufacturing/doctype/blanket_order/blanket_order.py index 5eb4c513b0..75b101fe24 100644 --- a/erpnext/manufacturing/doctype/blanket_order/blanket_order.py +++ b/erpnext/manufacturing/doctype/blanket_order/blanket_order.py @@ -68,33 +68,4 @@ def make_order(source_name): "postprocess": update_item } }) - return target_doc - -# @frappe.whitelist() -# def make_purchase_order(source_name): -# def update_item(source, target, source_parent): -# target_qty = source.get("qty") - source.get("ordered_qty") -# target.qty = target_qty if not flt(target_qty) < 0 else 0 -# item = get_item_defaults(target.item_code, source_parent.company) -# if item: -# target.item_name = item.get("item_name") -# target.description = item.get("description") -# target.uom = item.get("stock_uom") -# target.warehouse = item.get("default_warehouse") -# target.against_blanket_order = 1 -# target.blanket_order = source_name - -# target_doc = get_mapped_doc("Blanket Order", source_name, { -# "Blanket Order": { -# "doctype": "Purchase Order" -# }, -# "Blanket Order Item": { -# "doctype": "Purchase Order Item", -# "field_map": { -# "rate": "blanket_order_rate", -# "parent": "blanket_order" -# }, -# "postprocess": update_item -# } -# }) -# return target_doc \ No newline at end of file + return target_doc \ No newline at end of file From 4d9fe69ba59b75a8a7955fb4b2728cc9ec2a630c Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Tue, 31 Mar 2020 14:17:53 +0530 Subject: [PATCH 17/50] fix: Test cases --- .../blanket_order/test_blanket_order.py | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/erpnext/manufacturing/doctype/blanket_order/test_blanket_order.py b/erpnext/manufacturing/doctype/blanket_order/test_blanket_order.py index 455ea06137..3171defdae 100644 --- a/erpnext/manufacturing/doctype/blanket_order/test_blanket_order.py +++ b/erpnext/manufacturing/doctype/blanket_order/test_blanket_order.py @@ -7,13 +7,17 @@ import frappe import unittest from frappe.utils import add_months, today from erpnext import get_company_currency -from .blanket_order import make_sales_order, make_purchase_order +from .blanket_order import make_order class TestBlanketOrder(unittest.TestCase): + def setUp(self): + frappe.flags.args = frappe._dict() + def test_sales_order_creation(self): bo = make_blanket_order(blanket_order_type="Selling") - so = make_sales_order(bo.name) + frappe.flags.args.doctype = 'Sales Order' + so = make_order(bo.name) so.currency = get_company_currency(so.company) so.delivery_date = today() so.items[0].qty = 10 @@ -29,7 +33,8 @@ class TestBlanketOrder(unittest.TestCase): self.assertEqual(so.items[0].qty, bo.items[0].ordered_qty) # test the quantity - so1 = make_sales_order(bo.name) + frappe.flags.args.doctype = 'Sales Order' + so1 = make_order(bo.name) so1.currency = get_company_currency(so1.company) self.assertEqual(so1.items[0].qty, (bo.items[0].qty-bo.items[0].ordered_qty)) @@ -37,7 +42,8 @@ class TestBlanketOrder(unittest.TestCase): def test_purchase_order_creation(self): bo = make_blanket_order(blanket_order_type="Purchasing") - po = make_purchase_order(bo.name) + frappe.flags.args.doctype = 'Purchase Order' + po = make_order(bo.name) po.currency = get_company_currency(po.company) po.schedule_date = today() po.items[0].qty = 10 @@ -53,7 +59,8 @@ class TestBlanketOrder(unittest.TestCase): self.assertEqual(po.items[0].qty, bo.items[0].ordered_qty) # test the quantity - po1 = make_sales_order(bo.name) + frappe.flags.args.doctype = 'Purchase Order' + po1 = make_order(bo.name) po1.currency = get_company_currency(po1.company) self.assertEqual(po1.items[0].qty, (bo.items[0].qty-bo.items[0].ordered_qty)) @@ -78,7 +85,7 @@ def make_blanket_order(**args): "qty": args.quantity or 1000, "rate": args.rate or 100 }) - + bo.insert() bo.submit() return bo \ No newline at end of file From cf9347d2f5e702cfb7f097836bb29afff1d22702 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Tue, 31 Mar 2020 17:28:43 +0530 Subject: [PATCH 18/50] fix: Undo unneccessary changes --- erpnext/accounts/party.py | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/erpnext/accounts/party.py b/erpnext/accounts/party.py index 98b6d79626..4cfeb251d6 100644 --- a/erpnext/accounts/party.py +++ b/erpnext/accounts/party.py @@ -11,7 +11,7 @@ from frappe.utils import (add_days, getdate, formatdate, date_diff, add_years, get_timestamp, nowdate, flt, cstr, add_months, get_last_day) from frappe.contacts.doctype.address.address import (get_address_display, get_default_address, get_company_address) -from frappe.contacts.doctype.contact.contact import get_contact_details, get_default_contact +from frappe.contacts.doctype.contact.contact import get_contact_details from erpnext.exceptions import PartyFrozen, PartyDisabled, InvalidAccountCurrency from erpnext.accounts.utils import get_fiscal_year from erpnext import get_company_currency @@ -46,7 +46,7 @@ def _get_party_details(party=None, account=None, party_type="Customer", company= currency = party.default_currency if party.get("default_currency") else get_company_currency(company) party_address, shipping_address = set_address_details(party_details, party, party_type, doctype, company, party_address, company_address, shipping_address) - set_contact_details(party_details, party, party_type, doctype) + set_contact_details(party_details, party, party_type) set_other_values(party_details, party, party_type) set_price_list(party_details, party, party_type, price_list, pos_profile) @@ -115,11 +115,8 @@ def set_address_details(party_details, party, party_type, doctype=None, company= def get_regional_address_details(party_details, doctype, company): pass -def set_contact_details(party_details, party, party_type, doctype=None): - if doctype == 'Sales Invoice': - party_details.contact_person = get_default_billing_contact(doctype, party.name) - else: - party_details.contact_person = get_default_contact(party_type, party.name) +def set_contact_details(party_details, party, party_type): + party_details.contact_person = get_default_contact(party_type, party.name) if not party_details.contact_person: party_details.update({ @@ -617,8 +614,8 @@ def get_partywise_advanced_payment_amount(party_type, posting_date = None): if data: return frappe._dict(data) -def get_default_billing_contact(doctype, name): - """ +def get_default_contact(doctype, name): + """ Returns default contact for the given doctype and name. Can be ordered by `contact_type` to either is_primary_contact or is_billing_contact. """ @@ -626,11 +623,11 @@ def get_default_billing_contact(doctype, name): SELECT dl.parent, c.is_primary_contact, c.is_billing_contact FROM `tabDynamic Link` dl INNER JOIN tabContact c ON c.name = dl.parent - WHERE + WHERE dl.link_doctype=%s AND dl.link_name=%s AND dl.parenttype = "Contact" - ORDER BY is_billing_contact DESC, is_primary_contact DESC + ORDER BY is_primary_contact DESC, is_billing_contact DESC """, (doctype, name)) if out: try: From 8ed7535e8a2e6779e52e2424788a41693bc2ea68 Mon Sep 17 00:00:00 2001 From: Saqib Ansari Date: Tue, 31 Mar 2020 18:44:02 +0530 Subject: [PATCH 19/50] fix: travis --- erpnext/accounts/doctype/payment_request/payment_request.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/erpnext/accounts/doctype/payment_request/payment_request.py b/erpnext/accounts/doctype/payment_request/payment_request.py index 49c0e36204..aa0e67c5f2 100644 --- a/erpnext/accounts/doctype/payment_request/payment_request.py +++ b/erpnext/accounts/doctype/payment_request/payment_request.py @@ -424,12 +424,11 @@ def make_status_as_paid(doc, method): "docstatus": 1}) if payment_request_name: - outstanding_amt = frappe.get_value(ref.reference_doctype, ref.reference_name, 'outstanding_amount') doc = frappe.get_doc("Payment Request", payment_request_name) - if doc.status != "Paid" and outstanding_amt <= 0: + if doc.status != "Paid" and ref.outstanding_amount <= ref.allocated_amount: doc.db_set('status', 'Paid') frappe.db.commit() - elif doc.status != "Partially Paid" and outstanding_amt != doc.grand_total: + elif doc.status != "Partially Paid" and ref.outstanding_amount != ref.allocated_amount: doc.db_set('status', 'Partially Paid') frappe.db.commit() From 9a7851096c607d3a90c18e3c633c930856ed049c Mon Sep 17 00:00:00 2001 From: Saqib Ansari Date: Tue, 31 Mar 2020 18:48:35 +0530 Subject: [PATCH 20/50] fix: check if selling price exists then set it --- erpnext/accounts/doctype/sales_invoice/sales_invoice.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index bd18d5799b..a42166241e 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -446,7 +446,8 @@ class SalesInvoice(SellingController): selling_price_list = customer_price_list or customer_group_price_list or pos.get('selling_price_list') - self.set('selling_price_list', selling_price_list) + if selling_price_list: + self.set('selling_price_list', selling_price_list) if not for_validate: self.update_stock = cint(pos.get("update_stock")) From 6f0dc8257ccb4953e0aa84bb5c00cf478e854420 Mon Sep 17 00:00:00 2001 From: marination Date: Wed, 1 Apr 2020 11:04:14 +0530 Subject: [PATCH 21/50] fix: Typo in stock level validation in Stock Ledger --- erpnext/stock/stock_ledger.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py index b100f45327..7567a1ae75 100644 --- a/erpnext/stock/stock_ledger.py +++ b/erpnext/stock/stock_ledger.py @@ -428,7 +428,7 @@ class update_entries_after(object): frappe.get_desk_link(self.exceptions[0]["voucher_type"], self.exceptions[0]["voucher_no"])) if self.verbose: - frappe.throw(msg, NegativeStockError, title='Insufficent Stock') + frappe.throw(msg, NegativeStockError, title='Insufficient Stock') else: raise NegativeStockError(msg) From e48bcb30e7ebd891a477f21362eb4cc73330ba91 Mon Sep 17 00:00:00 2001 From: Anupam K Date: Thu, 2 Apr 2020 01:04:01 +0530 Subject: [PATCH 22/50] Sum of years not needed. --- .../customer_acquisition_and_loyalty.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/selling/report/customer_acquisition_and_loyalty/customer_acquisition_and_loyalty.py b/erpnext/selling/report/customer_acquisition_and_loyalty/customer_acquisition_and_loyalty.py index 4509904249..aabc503a1b 100644 --- a/erpnext/selling/report/customer_acquisition_and_loyalty/customer_acquisition_and_loyalty.py +++ b/erpnext/selling/report/customer_acquisition_and_loyalty/customer_acquisition_and_loyalty.py @@ -48,7 +48,7 @@ def execute(filters=None): new = new_customers_in.get(key, [0,0.0]) repeat = repeat_customers_in.get(key, [0,0.0]) - out.append([year, calendar.month_name[month], + out.append([str(year), calendar.month_name[month], new[0], repeat[0], new[0] + repeat[0], new[1], repeat[1], new[1] + repeat[1]]) From 625acab057332db0af52f5a8e75755928db01323 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Thu, 2 Apr 2020 11:18:22 +0530 Subject: [PATCH 23/50] fix: Add duplicate item validation --- .../manufacturing/doctype/blanket_order/blanket_order.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/erpnext/manufacturing/doctype/blanket_order/blanket_order.py b/erpnext/manufacturing/doctype/blanket_order/blanket_order.py index 75b101fe24..f2cb7f3bcc 100644 --- a/erpnext/manufacturing/doctype/blanket_order/blanket_order.py +++ b/erpnext/manufacturing/doctype/blanket_order/blanket_order.py @@ -19,6 +19,15 @@ class BlanketOrder(Document): if getdate(self.from_date) > getdate(self.to_date): frappe.throw(_("From date cannot be greater than To date")) + self.validate_duplicate_items() + + def validate_duplicate_items(self): + item_list = [] + for item in self.items: + if item.item_code in item_list: + frappe.throw(_("Note: Item {0} added multiple times").format(frappe.bold(item.item_code))) + item_list.append(item.item_code) + def update_ordered_qty(self): ref_doctype = "Sales Order" if self.blanket_order_type == "Selling" else "Purchase Order" item_ordered_qty = frappe._dict(frappe.db.sql(""" From b20dbff72627294ab6134bfe20178aef351de83e Mon Sep 17 00:00:00 2001 From: Anupam K Date: Thu, 2 Apr 2020 11:37:44 +0530 Subject: [PATCH 24/50] Sum of years not needed. --- .../customer_acquisition_and_loyalty.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/selling/report/customer_acquisition_and_loyalty/customer_acquisition_and_loyalty.py b/erpnext/selling/report/customer_acquisition_and_loyalty/customer_acquisition_and_loyalty.py index aabc503a1b..28dd056407 100644 --- a/erpnext/selling/report/customer_acquisition_and_loyalty/customer_acquisition_and_loyalty.py +++ b/erpnext/selling/report/customer_acquisition_and_loyalty/customer_acquisition_and_loyalty.py @@ -4,7 +4,7 @@ from __future__ import unicode_literals import frappe from frappe import _ -from frappe.utils import getdate, cint +from frappe.utils import getdate, cint, cstr import calendar def execute(filters=None): @@ -48,7 +48,7 @@ def execute(filters=None): new = new_customers_in.get(key, [0,0.0]) repeat = repeat_customers_in.get(key, [0,0.0]) - out.append([str(year), calendar.month_name[month], + out.append([cstr(year), calendar.month_name[month], new[0], repeat[0], new[0] + repeat[0], new[1], repeat[1], new[1] + repeat[1]]) From 872fcb6caed285701c88512b56d578f339378b5a Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Thu, 2 Apr 2020 18:11:46 +0530 Subject: [PATCH 25/50] fix: Travis --- .../doctype/purchase_invoice_item/purchase_invoice_item.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json b/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json index ef90b942b5..9c974260a2 100644 --- a/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json +++ b/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json @@ -761,7 +761,7 @@ "depends_on": "is_fixed_asset", "fetch_from": "item_code.asset_category", "fieldname": "asset_category", - "fieldtype": "Data", + "fieldtype": "Link", "label": "Asset Category", "options": "Asset Category", "read_only": 1 @@ -777,7 +777,7 @@ "idx": 1, "istable": 1, "links": [], - "modified": "2020-03-11 14:20:17.297284", + "modified": "2020-04-01 14:20:17.297284", "modified_by": "Administrator", "module": "Accounts", "name": "Purchase Invoice Item", From 9a39bcd031381262478b3b850918571a9cd000a0 Mon Sep 17 00:00:00 2001 From: marination Date: Thu, 2 Apr 2020 19:36:21 +0530 Subject: [PATCH 26/50] fix: Fixed Test Cases for Material Request - Reduce quantity on Material Transfer/Issue - No effect on Customer Provided Material Request --- .../material_request/test_material_request.py | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/erpnext/stock/doctype/material_request/test_material_request.py b/erpnext/stock/doctype/material_request/test_material_request.py index 79cdc1ad18..b925aedd1a 100644 --- a/erpnext/stock/doctype/material_request/test_material_request.py +++ b/erpnext/stock/doctype/material_request/test_material_request.py @@ -276,8 +276,8 @@ class TestMaterialRequest(unittest.TestCase): current_requested_qty_item1 = self._get_requested_qty("_Test Item Home Desktop 100", "_Test Warehouse - _TC") current_requested_qty_item2 = self._get_requested_qty("_Test Item Home Desktop 200", "_Test Warehouse - _TC") - self.assertEqual(current_requested_qty_item1, existing_requested_qty_item1 + 54.0) - self.assertEqual(current_requested_qty_item2, existing_requested_qty_item2 + 3.0) + self.assertEqual(current_requested_qty_item1, existing_requested_qty_item1 - 54.0) + self.assertEqual(current_requested_qty_item2, existing_requested_qty_item2 - 3.0) from erpnext.stock.doctype.material_request.material_request import make_stock_entry @@ -331,8 +331,8 @@ class TestMaterialRequest(unittest.TestCase): current_requested_qty_item1 = self._get_requested_qty("_Test Item Home Desktop 100", "_Test Warehouse - _TC") current_requested_qty_item2 = self._get_requested_qty("_Test Item Home Desktop 200", "_Test Warehouse - _TC") - self.assertEqual(current_requested_qty_item1, existing_requested_qty_item1 + 27.0) - self.assertEqual(current_requested_qty_item2, existing_requested_qty_item2 + 1.5) + self.assertEqual(current_requested_qty_item1, existing_requested_qty_item1 - 27.0) + self.assertEqual(current_requested_qty_item2, existing_requested_qty_item2 - 1.5) # check if per complete is as expected for Stock Entry cancelled se.cancel() @@ -344,8 +344,8 @@ class TestMaterialRequest(unittest.TestCase): current_requested_qty_item1 = self._get_requested_qty("_Test Item Home Desktop 100", "_Test Warehouse - _TC") current_requested_qty_item2 = self._get_requested_qty("_Test Item Home Desktop 200", "_Test Warehouse - _TC") - self.assertEqual(current_requested_qty_item1, existing_requested_qty_item1 + 54.0) - self.assertEqual(current_requested_qty_item2, existing_requested_qty_item2 + 3.0) + self.assertEqual(current_requested_qty_item1, existing_requested_qty_item1 - 54.0) + self.assertEqual(current_requested_qty_item2, existing_requested_qty_item2 - 3.0) def test_completed_qty_for_over_transfer(self): existing_requested_qty_item1 = self._get_requested_qty("_Test Item Home Desktop 100", "_Test Warehouse - _TC") @@ -425,8 +425,8 @@ class TestMaterialRequest(unittest.TestCase): current_requested_qty_item1 = self._get_requested_qty("_Test Item Home Desktop 100", "_Test Warehouse - _TC") current_requested_qty_item2 = self._get_requested_qty("_Test Item Home Desktop 200", "_Test Warehouse - _TC") - self.assertEqual(current_requested_qty_item1, existing_requested_qty_item1 + 54.0) - self.assertEqual(current_requested_qty_item2, existing_requested_qty_item2 + 3.0) + self.assertEqual(current_requested_qty_item1, existing_requested_qty_item1 - 54.0) + self.assertEqual(current_requested_qty_item2, existing_requested_qty_item2 - 3.0) def test_incorrect_mapping_of_stock_entry(self): # submit material request of type Transfer @@ -512,7 +512,7 @@ class TestMaterialRequest(unittest.TestCase): mr.submit() #testing bin value after material request is submitted - self.assertEqual(_get_requested_qty(), existing_requested_qty + 54.0) + self.assertEqual(_get_requested_qty(), existing_requested_qty - 54.0) # receive items to allow issue self._insert_stock_entry(60, 6, "_Test Warehouse - _TC") @@ -609,6 +609,8 @@ class TestMaterialRequest(unittest.TestCase): def test_customer_provided_parts_mr(self): from erpnext.stock.doctype.material_request.material_request import make_stock_entry create_item('CUST-0987', is_customer_provided_item = 1, customer = '_Test Customer', is_purchase_item = 0) + existing_requested_qty = self._get_requested_qty("_Test Customer", "_Test Warehouse - _TC") + mr = make_material_request(item_code='CUST-0987', material_request_type='Customer Provided') se = make_stock_entry(mr.name) se.insert() @@ -617,7 +619,10 @@ class TestMaterialRequest(unittest.TestCase): self.assertEqual(se.get("items")[0].material_request, mr.name) mr = frappe.get_doc("Material Request", mr.name) mr.submit() + current_requested_qty = self._get_requested_qty("_Test Customer", "_Test Warehouse - _TC") + self.assertEqual(mr.per_ordered, 100) + self.assertEqual(existing_requested_qty, current_requested_qty) def make_material_request(**args): args = frappe._dict(args) From d9a17a9be170f52207e174ef6247577fd03691a9 Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Thu, 2 Apr 2020 19:57:11 +0530 Subject: [PATCH 27/50] fix (tests): reload doctype --- erpnext/patches.txt | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 8aec8bddb9..5f5df6c476 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -626,10 +626,11 @@ 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') -execute:frappe.reload_doc('desk', 'doctype','dashboard_chart') +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') +execute:frappe.reload_doc('desk', 'doctype', 'dashboard_chart_field') erpnext.patches.v12_0.add_default_dashboards erpnext.patches.v12_0.remove_bank_remittance_custom_fields erpnext.patches.v12_0.generate_leave_ledger_entries From d29dd58e894afa16889b71ab525d8e5fc1aed499 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Thu, 2 Apr 2020 21:29:59 +0530 Subject: [PATCH 28/50] fix: Validation --- erpnext/manufacturing/doctype/blanket_order/blanket_order.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/erpnext/manufacturing/doctype/blanket_order/blanket_order.py b/erpnext/manufacturing/doctype/blanket_order/blanket_order.py index f2cb7f3bcc..d7556add80 100644 --- a/erpnext/manufacturing/doctype/blanket_order/blanket_order.py +++ b/erpnext/manufacturing/doctype/blanket_order/blanket_order.py @@ -14,13 +14,12 @@ from erpnext.stock.doctype.item.item import get_item_defaults class BlanketOrder(Document): def validate(self): self.validate_dates() + self.validate_duplicate_items() def validate_dates(self): if getdate(self.from_date) > getdate(self.to_date): frappe.throw(_("From date cannot be greater than To date")) - self.validate_duplicate_items() - def validate_duplicate_items(self): item_list = [] for item in self.items: From 438e0433a3116520d91386f6e0dc726a55f05f83 Mon Sep 17 00:00:00 2001 From: Saqib Date: Fri, 3 Apr 2020 10:02:56 +0530 Subject: [PATCH 29/50] fix: cannot set warehouse on deleting all so items and updating them (#21078) * fix: cannot set warehouse on deleting all so items and updating them * fix: travis * fix: docname is editable in update items dialog --- erpnext/controllers/accounts_controller.py | 15 +++--- erpnext/public/js/utils.js | 3 +- erpnext/stock/get_item_details.py | 60 ++++++++++++++-------- 3 files changed, 49 insertions(+), 29 deletions(-) diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index d661bcbf34..76eb56f523 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -19,6 +19,7 @@ from erpnext.accounts.doctype.pricing_rule.utils import (apply_pricing_rule_on_t from erpnext.exceptions import InvalidCurrency from six import text_type from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions +from erpnext.stock.get_item_details import get_item_warehouse force_item_fields = ("item_group", "brand", "stock_uom", "is_fixed_asset", "item_tax_rate", "pricing_rules") @@ -1126,16 +1127,16 @@ def set_sales_order_defaults(parent_doctype, parent_doctype_name, child_docname, """ Returns a Sales Order Item child item containing the default values """ - p_doctype = frappe.get_doc(parent_doctype, parent_doctype_name) - child_item = frappe.new_doc('Sales Order Item', p_doctype, child_docname) + p_doc = frappe.get_doc(parent_doctype, parent_doctype_name) + child_item = frappe.new_doc('Sales Order Item', p_doc, child_docname) item = frappe.get_doc("Item", item_code) child_item.item_code = item.item_code child_item.item_name = item.item_name child_item.description = item.description - child_item.reqd_by_date = p_doctype.delivery_date + child_item.reqd_by_date = p_doc.delivery_date child_item.uom = item.stock_uom child_item.conversion_factor = get_conversion_factor(item_code, item.stock_uom).get("conversion_factor") or 1.0 - child_item.warehouse = p_doctype.set_warehouse or p_doctype.items[0].warehouse + child_item.warehouse = get_item_warehouse(item, p_doc, overwrite_warehouse=True) return child_item @@ -1143,13 +1144,13 @@ def set_purchase_order_defaults(parent_doctype, parent_doctype_name, child_docna """ Returns a Purchase Order Item child item containing the default values """ - p_doctype = frappe.get_doc(parent_doctype, parent_doctype_name) - child_item = frappe.new_doc('Purchase Order Item', p_doctype, child_docname) + p_doc = frappe.get_doc(parent_doctype, parent_doctype_name) + child_item = frappe.new_doc('Purchase Order Item', p_doc, child_docname) item = frappe.get_doc("Item", item_code) child_item.item_code = item.item_code child_item.item_name = item.item_name child_item.description = item.description - child_item.schedule_date = p_doctype.schedule_date + child_item.schedule_date = p_doc.schedule_date child_item.uom = item.stock_uom child_item.conversion_factor = get_conversion_factor(item_code, item.stock_uom).get("conversion_factor") or 1.0 child_item.base_rate = 1 # Initiallize value will update in parent validation diff --git a/erpnext/public/js/utils.js b/erpnext/public/js/utils.js index 4eb3175186..4d44eae086 100755 --- a/erpnext/public/js/utils.js +++ b/erpnext/public/js/utils.js @@ -453,7 +453,8 @@ erpnext.utils.update_child_items = function(opts) { fields: [{ fieldtype:'Data', fieldname:"docname", - hidden: 0, + read_only: 1, + hidden: 1, }, { fieldtype:'Link', fieldname:"item_code", diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py index 53964f24c4..9c5a8e1be8 100644 --- a/erpnext/stock/get_item_details.py +++ b/erpnext/stock/get_item_details.py @@ -240,26 +240,13 @@ def get_basic_details(args, item, overwrite_warehouse=True): item_group_defaults = get_item_group_defaults(item.name, args.company) brand_defaults = get_brand_defaults(item.name, args.company) - 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 {} - 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 + defaults = frappe._dict({ + 'item_defaults': item_defaults, + 'item_group_defaults': item_group_defaults, + 'brand_defaults': brand_defaults + }) + + warehouse = get_item_warehouse(item, args, overwrite_warehouse, defaults) if args.get('doctype') == "Material Request" and not args.get('material_request_type'): args['material_request_type'] = frappe.db.get_value('Material Request', @@ -272,7 +259,7 @@ def get_basic_details(args, item, overwrite_warehouse=True): expense_account = get_asset_category_account(fieldname = "fixed_asset_account", item = args.item_code, company= args.company) #Set the UOM to the Default Sales UOM or Default Purchase UOM if configured in the Item Master - if not args.uom: + if not args.get('uom'): if args.get('doctype') in sales_doctypes: args.uom = item.sales_uom if item.sales_uom else item.stock_uom elif (args.get('doctype') in ['Purchase Order', 'Purchase Receipt', 'Purchase Invoice']) or \ @@ -362,6 +349,37 @@ def get_basic_details(args, item, overwrite_warehouse=True): return out +def get_item_warehouse(item, args, overwrite_warehouse, defaults={}): + if not defaults: + defaults = frappe._dict({ + 'item_defaults' : get_item_defaults(item.name, args.company), + 'item_group_defaults' : get_item_group_defaults(item.name, args.company), + 'brand_defaults' : get_brand_defaults(item.name, args.company) + }) + + if overwrite_warehouse or not args.warehouse: + warehouse = ( + args.get("set_warehouse") or + defaults.item_defaults.get("default_warehouse") or + defaults.item_group_defaults.get("default_warehouse") or + defaults.brand_defaults.get("default_warehouse") or + args.get('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.get('warehouse') + + return warehouse + def update_barcode_value(out): from erpnext.accounts.doctype.sales_invoice.pos import get_barcode_data barcode_data = get_barcode_data([out]) From 66c4a087038e75bc0e53cf5744fcb960916e93a7 Mon Sep 17 00:00:00 2001 From: Marica Date: Fri, 3 Apr 2020 10:07:06 +0530 Subject: [PATCH 30/50] fix: Update Received Qty in Material Request as per Stock UOM (#21054) * fix: Update Received Qty in Material Request as per Stock UOM * fix: Process each PR only once * fix: minor suggested changes Co-authored-by: Nabin Hait --- erpnext/patches.txt | 1 + ...ty_in_material_request_as_per_stock_uom.py | 30 +++++++++++++++++++ .../purchase_receipt/purchase_receipt.py | 8 ++--- 3 files changed, 35 insertions(+), 4 deletions(-) create mode 100644 erpnext/patches/v12_0/set_received_qty_in_material_request_as_per_stock_uom.py diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 8aec8bddb9..bd50ff48f7 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -660,3 +660,4 @@ erpnext.patches.v12_0.set_job_offer_applicant_email erpnext.patches.v12_0.create_irs_1099_field_united_states erpnext.patches.v12_0.move_bank_account_swift_number_to_bank erpnext.patches.v12_0.rename_bank_reconciliation_fields # 2020-01-22 +erpnext.patches.v12_0.set_received_qty_in_material_request_as_per_stock_uom \ No newline at end of file diff --git a/erpnext/patches/v12_0/set_received_qty_in_material_request_as_per_stock_uom.py b/erpnext/patches/v12_0/set_received_qty_in_material_request_as_per_stock_uom.py new file mode 100644 index 0000000000..88c3e2e302 --- /dev/null +++ b/erpnext/patches/v12_0/set_received_qty_in_material_request_as_per_stock_uom.py @@ -0,0 +1,30 @@ +from __future__ import unicode_literals +import frappe + +def execute(): + purchase_receipts = frappe.db.sql(""" + SELECT + parent from `tabPurchase Receipt Item` + WHERE + material_request is not null + AND docstatus=1 + """,as_dict=1) + + purchase_receipts = set([d.parent for d in purchase_receipts]) + + for pr in purchase_receipts: + doc = frappe.get_doc("Purchase Receipt", pr) + doc.status_updater = [ + { + 'source_dt': 'Purchase Receipt Item', + 'target_dt': 'Material Request Item', + 'join_field': 'material_request_item', + 'target_field': 'received_qty', + 'target_parent_dt': 'Material Request', + 'target_parent_field': 'per_received', + 'target_ref_field': 'stock_qty', + 'source_field': 'stock_qty', + 'percent_join_field': 'material_request' + } + ] + doc.update_qty() diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py index 3b43690658..c2b38927f7 100644 --- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py @@ -50,8 +50,8 @@ class PurchaseReceipt(BuyingController): 'target_field': 'received_qty', 'target_parent_dt': 'Material Request', 'target_parent_field': 'per_received', - 'target_ref_field': 'qty', - 'source_field': 'qty', + 'target_ref_field': 'stock_qty', + 'source_field': 'stock_qty', 'percent_join_field': 'material_request' }] if cint(self.is_return): @@ -357,7 +357,7 @@ class PurchaseReceipt(BuyingController): if warehouse_with_no_account: frappe.msgprint(_("No accounting entries for the following warehouses") + ": \n" + "\n".join(warehouse_with_no_account)) - + return process_gl_map(gl_entries) def get_asset_gl_entry(self, gl_entries): @@ -628,7 +628,7 @@ def get_item_account_wise_additional_cost(purchase_document): if not landed_cost_vouchers: return - + item_account_wise_cost = {} for lcv in landed_cost_vouchers: From 3251e1304c9c46b5c4f74fd35765eda1ba090136 Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Fri, 3 Apr 2020 10:08:19 +0530 Subject: [PATCH 31/50] fix: lms quiz type error (#21152) --- erpnext/public/js/education/lms/quiz.js | 2 +- erpnext/www/lms/content.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/public/js/education/lms/quiz.js b/erpnext/public/js/education/lms/quiz.js index 52481291e0..91cbbf4d66 100644 --- a/erpnext/public/js/education/lms/quiz.js +++ b/erpnext/public/js/education/lms/quiz.js @@ -29,7 +29,7 @@ class Quiz { this.questions.push(question) this.wrapper.appendChild(question_wrapper); }) - if (data.activity.is_complete) { + if (data.activity && data.activity.is_complete) { this.disable() let indicator = 'red' let message = 'Your are not allowed to attempt the quiz again.' diff --git a/erpnext/www/lms/content.html b/erpnext/www/lms/content.html index 5607c0814d..cdc71412c4 100644 --- a/erpnext/www/lms/content.html +++ b/erpnext/www/lms/content.html @@ -63,7 +63,7 @@
-

{{ content.name }} ({{ position + 1 }}/{{length}})

+

{{ content.name }} ({{ position + 1 }}/{{length}})

{% endmacro %} From 63bdf5dc74055b70873f1b977b3434b988ef0484 Mon Sep 17 00:00:00 2001 From: Saqib Date: Fri, 3 Apr 2020 19:35:55 +0530 Subject: [PATCH 32/50] fix: [ux] credit to & debit to error message (#21132) Co-authored-by: Nabin Hait --- .../doctype/purchase_invoice/purchase_invoice.py | 8 ++++++-- .../accounts/doctype/sales_invoice/sales_invoice.py | 10 +++++++--- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py index 87d40fca1b..24f157529a 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -146,10 +146,14 @@ class PurchaseInvoice(BuyingController): ["account_type", "report_type", "account_currency"], as_dict=True) if account.report_type != "Balance Sheet": - frappe.throw(_("Credit To account must be a Balance Sheet account")) + frappe.throw(_("Please ensure {} account is a Balance Sheet account. \ + You can change the parent account to a Balance Sheet account or select a different account.") + .format(frappe.bold("Credit To")), title=_("Invalid Account")) if self.supplier and account.account_type != "Payable": - frappe.throw(_("Credit To account must be a Payable account")) + frappe.throw(_("Please ensure {} account is a Payable account. \ + Change the account type to Payable or select a different account.") + .format(frappe.bold("Credit To")), title=_("Invalid Account")) self.party_account_currency = account.account_currency diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index a42166241e..dc0c025177 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -478,13 +478,17 @@ class SalesInvoice(SellingController): ["account_type", "report_type", "account_currency"], as_dict=True) if not account: - frappe.throw(_("Debit To is required")) + frappe.throw(_("Debit To is required"), title=_("Account Missing")) if account.report_type != "Balance Sheet": - frappe.throw(_("Debit To account must be a Balance Sheet account")) + frappe.throw(_("Please ensure {} account is a Balance Sheet account. \ + You can change the parent account to a Balance Sheet account or select a different account.") + .format(frappe.bold("Debit To")), title=_("Invalid Account")) if self.customer and account.account_type != "Receivable": - frappe.throw(_("Debit To account must be a Receivable account")) + frappe.throw(_("Please ensure {} account is a Receivable account. \ + Change the account type to Receivable or select a different account.") + .format(frappe.bold("Debit To")), title=_("Invalid Account")) self.party_account_currency = account.account_currency From 6c8efdef096a7ec358857614b8a47ddecc208d3c Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Sat, 4 Apr 2020 20:05:17 +0530 Subject: [PATCH 33/50] fix: User permissions in GSTR 3B report --- erpnext/patches.txt | 2 +- .../v11_0/add_permissions_in_gst_settings.py | 7 ++----- .../gstr_3b_report/gstr_3b_report.html | 2 +- .../gstr_3b_report/gstr_3b_report.json | 19 ++++--------------- erpnext/regional/india/setup.py | 10 ++++++++-- 5 files changed, 16 insertions(+), 24 deletions(-) diff --git a/erpnext/patches.txt b/erpnext/patches.txt index b6e6cb38ed..9ddd7cc24d 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -581,7 +581,7 @@ erpnext.patches.v11_0.rename_bom_wo_fields erpnext.patches.v12_0.set_default_homepage_type erpnext.patches.v11_0.rename_additional_salary_component_additional_salary erpnext.patches.v11_0.renamed_from_to_fields_in_project -erpnext.patches.v11_0.add_permissions_in_gst_settings +erpnext.patches.v11_0.add_permissions_in_gst_settings #2020-04-04 erpnext.patches.v11_1.setup_guardian_role execute:frappe.delete_doc('DocType', 'Notification Control') erpnext.patches.v12_0.set_gst_category diff --git a/erpnext/patches/v11_0/add_permissions_in_gst_settings.py b/erpnext/patches/v11_0/add_permissions_in_gst_settings.py index e8fcf33bed..121a20288c 100644 --- a/erpnext/patches/v11_0/add_permissions_in_gst_settings.py +++ b/erpnext/patches/v11_0/add_permissions_in_gst_settings.py @@ -1,12 +1,9 @@ import frappe -from frappe.permissions import add_permission, update_permission_property +from erpnext.regional.india.setup import add_permissions def execute(): company = frappe.get_all('Company', filters = {'country': 'India'}) if not company: return - for doctype in ('GST HSN Code', 'GST Settings'): - add_permission(doctype, 'Accounts Manager', 0) - update_permission_property(doctype, 'Accounts Manager', 0, 'write', 1) - update_permission_property(doctype, 'Accounts Manager', 0, 'create', 1) \ No newline at end of file + add_permissions() \ No newline at end of file diff --git a/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.html b/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.html index 2da79a6364..35f9cf674c 100644 --- a/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.html +++ b/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.html @@ -29,7 +29,7 @@ - (a) {{__("Outward taxable supplies(other than zero rated, nil rated and exempted")}} + (a) {{__("Outward taxable supplies(other than zero rated, nil rated and exempted)")}} {{ flt(data.sup_details.osup_det.txval, 2) }} {{ flt(data.sup_details.osup_det.iamt, 2) }} {{ flt(data.sup_details.osup_det.camt, 2) }} 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 548d40b974..1f208df1f2 100644 --- a/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.json +++ b/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.json @@ -1,4 +1,5 @@ { + "actions": [], "autoname": "format:GSTR3B-{month}-{year}-{company_address}", "creation": "2019-02-04 11:35:55.964639", "doctype": "DocType", @@ -48,25 +49,13 @@ "read_only": 1 } ], - "modified": "2019-08-10 22:30:26.727038", + "links": [], + "modified": "2020-04-04 19:32:30.772908", "modified_by": "Administrator", "module": "Regional", "name": "GSTR 3B Report", "owner": "Administrator", - "permissions": [ - { - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "System Manager", - "share": 1, - "write": 1 - } - ], + "permissions": [], "sort_field": "modified", "sort_order": "DESC", "track_changes": 1 diff --git a/erpnext/regional/india/setup.py b/erpnext/regional/india/setup.py index 970a831e0e..75f29b8380 100644 --- a/erpnext/regional/india/setup.py +++ b/erpnext/regional/india/setup.py @@ -77,13 +77,19 @@ def add_custom_roles_for_reports(): )).insert() def add_permissions(): - for doctype in ('GST HSN Code', 'GST Settings'): + for doctype in ('GST HSN Code', 'GST Settings', 'GSTR 3B Report'): add_permission(doctype, 'All', 0) - for role in ('Accounts Manager', 'System Manager', 'Item Manager', 'Stock Manager'): + for role in ('Accounts Manager', 'Accounts User', 'System Manager'): add_permission(doctype, role, 0) update_permission_property(doctype, role, 0, 'write', 1) update_permission_property(doctype, role, 0, 'create', 1) + if doctype == 'GST HSN Code': + for role in ('Item Manager', 'Stock Manager'): + add_permission(doctype, role, 0) + update_permission_property(doctype, role, 0, 'write', 1) + update_permission_property(doctype, role, 0, 'create', 1) + def add_print_formats(): frappe.reload_doc("regional", "print_format", "gst_tax_invoice") frappe.reload_doc("accounts", "print_format", "gst_pos_invoice") From 75ef458b343d2f316ddb437803c1e7e138cdfb50 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Mon, 6 Apr 2020 10:15:38 +0530 Subject: [PATCH 34/50] fix: update attendace from leave application (#21155) --- 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 96e4cb5bb3..f78e17fb18 100755 --- a/erpnext/hr/doctype/leave_application/leave_application.py +++ b/erpnext/hr/doctype/leave_application/leave_application.py @@ -130,7 +130,7 @@ class LeaveApplication(Document): if self.status == "Approved": for dt in daterange(getdate(self.from_date), getdate(self.to_date)): date = dt.strftime("%Y-%m-%d") - status = "Half Day" if date == self.half_day_date else "On Leave" + status = "Half Day" if getdate(date) == getdate(self.half_day_date) else "On Leave" attendance_name = frappe.db.exists('Attendance', dict(employee = self.employee, attendance_date = date, docstatus = ('!=', 2))) From 05ac7213b3c26a1c4d25273e0d83b6f93bdf9b1b Mon Sep 17 00:00:00 2001 From: rohitwaghchaure Date: Mon, 6 Apr 2020 10:17:57 +0530 Subject: [PATCH 35/50] fix: allow to make BOM against template item (#21146) * fix: allow to make BOM against template item * Update queries.py Co-authored-by: Nabin Hait --- erpnext/controllers/queries.py | 9 ++++- erpnext/manufacturing/doctype/bom/bom.js | 46 +++++++++++++++++++++--- erpnext/manufacturing/doctype/bom/bom.py | 4 +++ 3 files changed, 54 insertions(+), 5 deletions(-) diff --git a/erpnext/controllers/queries.py b/erpnext/controllers/queries.py index 163ef72ee1..c14bb669a4 100644 --- a/erpnext/controllers/queries.py +++ b/erpnext/controllers/queries.py @@ -179,6 +179,12 @@ def item_query(doctype, txt, searchfield, start, page_len, filters, as_dict=Fals # scan description only if items are less than 50000 description_cond = 'or tabItem.description LIKE %(txt)s' + extra_cond = " and tabItem.has_variants=0" + if (filters and isinstance(filters, dict) + and filters.get("doctype") == "BOM"): + extra_cond = "" + del filters["doctype"] + return frappe.db.sql("""select tabItem.name, if(length(tabItem.item_name) > 40, concat(substr(tabItem.item_name, 1, 40), "..."), item_name) as item_name, @@ -188,11 +194,11 @@ def item_query(doctype, txt, searchfield, start, page_len, filters, as_dict=Fals {columns} from tabItem where tabItem.docstatus < 2 - and tabItem.has_variants=0 and tabItem.disabled=0 and (tabItem.end_of_life > %(today)s or ifnull(tabItem.end_of_life, '0000-00-00')='0000-00-00') and ({scond} or tabItem.item_code IN (select parent from `tabItem Barcode` where barcode LIKE %(txt)s) {description_cond}) + {extra_cond} {fcond} {mcond} order by if(locate(%(_txt)s, name), locate(%(_txt)s, name), 99999), @@ -203,6 +209,7 @@ def item_query(doctype, txt, searchfield, start, page_len, filters, as_dict=Fals key=searchfield, columns=columns, scond=searchfields, + extra_cond=extra_cond, fcond=get_filters_cond(doctype, filters, conditions).replace('%', '%%'), mcond=get_match_cond(doctype).replace('%', '%%'), description_cond = description_cond), diff --git a/erpnext/manufacturing/doctype/bom/bom.js b/erpnext/manufacturing/doctype/bom/bom.js index 0051ad9dff..ebfb762640 100644 --- a/erpnext/manufacturing/doctype/bom/bom.js +++ b/erpnext/manufacturing/doctype/bom/bom.js @@ -29,7 +29,10 @@ frappe.ui.form.on("BOM", { frm.set_query("item", function() { return { - query: "erpnext.controllers.queries.item_query" + query: "erpnext.controllers.queries.item_query", + filters: { + "doctype": "BOM" + } }; }); @@ -119,23 +122,58 @@ frappe.ui.form.on("BOM", { }); } } + + + if (frm.doc.__onload && frm.doc.__onload["has_variants"]) { + frm.set_intro(__('This is a Template BOM and will be used to make the work order for {0} of the item {1}', + [ + `variants`, + `${frm.doc.item}`, + ]), true); + + frm.$wrapper.find(".variants-intro").on("click", () => { + frappe.set_route("List", "Item", {"variant_of": frm.doc.item}); + }); + } }, make_work_order: function(frm) { - const fields = [{ + const fields = []; + + if (frm.doc.__onload && frm.doc.__onload["has_variants"]) { + fields.push({ + fieldtype: 'Link', + label: __('Variant Item'), + fieldname: 'item', + options: "Item", + reqd: 1, + get_query: function() { + return { + query: "erpnext.controllers.queries.item_query", + filters: { + "variant_of": frm.doc.item + } + }; + } + }); + } + + fields.push({ fieldtype: 'Float', label: __('Qty To Manufacture'), fieldname: 'qty', reqd: 1, default: 1 - }]; + }); frappe.prompt(fields, data => { + let item = data.item || frm.doc.item; + frappe.call({ method: "erpnext.manufacturing.doctype.work_order.work_order.make_work_order", args: { bom_no: frm.doc.name, - item: frm.doc.item, + item: item, qty: data.qty || 0.0, project: frm.doc.project }, diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py index b3e602bdfa..6ccd12aed3 100644 --- a/erpnext/manufacturing/doctype/bom/bom.py +++ b/erpnext/manufacturing/doctype/bom/bom.py @@ -59,6 +59,10 @@ class BOM(WebsiteGenerator): self.name = name + def onload(self): + super(BOM, self).onload() + if self.get("item") and cint(frappe.db.get_value("Item", self.item, "has_variants")): + self.set_onload("has_variants", True) def validate(self): self.route = frappe.scrub(self.name).replace('_', '-') From 1958749382080f0698fde18c5980e87d2b3790f4 Mon Sep 17 00:00:00 2001 From: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com> Date: Mon, 6 Apr 2020 10:21:50 +0530 Subject: [PATCH 36/50] fix(minor): Minor anti pattern fixes in Exchange rate revaluation doctype (#21147) * fix(minor): Minor anti pattern fixes in Exchange rate revaluation doctype * fix: Codacy --- .../exchange_rate_revaluation.js | 14 +++----------- .../exchange_rate_revaluation_dashboard.py | 11 +++++++++++ 2 files changed, 14 insertions(+), 11 deletions(-) create mode 100644 erpnext/accounts/doctype/exchange_rate_revaluation/exchange_rate_revaluation_dashboard.py diff --git a/erpnext/accounts/doctype/exchange_rate_revaluation/exchange_rate_revaluation.js b/erpnext/accounts/doctype/exchange_rate_revaluation/exchange_rate_revaluation.js index 0d5456ece6..1092f4c8f1 100644 --- a/erpnext/accounts/doctype/exchange_rate_revaluation/exchange_rate_revaluation.js +++ b/erpnext/accounts/doctype/exchange_rate_revaluation/exchange_rate_revaluation.js @@ -30,18 +30,10 @@ frappe.ui.form.on('Exchange Rate Revaluation', { frm.doc.accounts.forEach(d=> { total_amt = total_amt + d['new_balance_in_base_currency']; }); - if(total_amt === r.sum) { - frm.add_custom_button(__("Journal Entry"), function(){ - frappe.route_options = { - 'reference_type': 'Exchange Rate Revaluation', - 'reference_name': frm.doc.name - }; - frappe.set_route("List", "Journal Entry"); - }, __("View")); - } else { - frm.add_custom_button(__('Create Journal Entry'), function() { + if(total_amt !== r.sum) { + frm.add_custom_button(__('Journal Entry'), function() { return frm.events.make_jv(frm); - }); + }, __('Create')); } }, 'Journal Entry'); } diff --git a/erpnext/accounts/doctype/exchange_rate_revaluation/exchange_rate_revaluation_dashboard.py b/erpnext/accounts/doctype/exchange_rate_revaluation/exchange_rate_revaluation_dashboard.py new file mode 100644 index 0000000000..b5cfa04ed6 --- /dev/null +++ b/erpnext/accounts/doctype/exchange_rate_revaluation/exchange_rate_revaluation_dashboard.py @@ -0,0 +1,11 @@ +from __future__ import unicode_literals + +def get_data(): + return { + 'fieldname': 'reference_name', + 'transactions': [ + { + 'items': ['Journal Entry'] + } + ] + } From aa775f87b23a8486388a6127b7812859f1acd61b Mon Sep 17 00:00:00 2001 From: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com> Date: Mon, 6 Apr 2020 10:23:06 +0530 Subject: [PATCH 37/50] fix: Setting to toggle customer and supplier warehouse for inter warehouse transfer (#21142) * fix: Setting to toggle customer and supplier warehouse for inter warehouse transfer * fix: Use cint --- .../stock_settings/stock_settings.json | 889 ++---------------- .../doctype/stock_settings/stock_settings.py | 11 + 2 files changed, 97 insertions(+), 803 deletions(-) diff --git a/erpnext/stock/doctype/stock_settings/stock_settings.json b/erpnext/stock/doctype/stock_settings/stock_settings.json index f43390f19d..c9a3527e91 100644 --- a/erpnext/stock/doctype/stock_settings/stock_settings.json +++ b/erpnext/stock/doctype/stock_settings/stock_settings.json @@ -1,955 +1,238 @@ { - "allow_copy": 0, - "allow_events_in_timeline": 0, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, - "autoname": "", - "beta": 0, + "actions": [], "creation": "2013-06-24 16:37:54", - "custom": 0, "description": "Settings", - "docstatus": 0, "doctype": "DocType", - "editable_grid": 0, + "engine": "InnoDB", + "field_order": [ + "item_naming_by", + "item_group", + "stock_uom", + "default_warehouse", + "sample_retention_warehouse", + "column_break_4", + "valuation_method", + "over_delivery_receipt_allowance", + "action_if_quality_inspection_is_not_submitted", + "show_barcode_field", + "clean_description_html", + "section_break_7", + "auto_insert_price_list_rate_if_missing", + "allow_negative_stock", + "column_break_10", + "automatically_set_serial_nos_based_on_fifo", + "set_qty_in_transactions_based_on_serial_no_input", + "auto_material_request", + "auto_indent", + "reorder_email_notify", + "inter_warehouse_transfer_settings_section", + "allow_from_dn", + "allow_from_pr", + "freeze_stock_entries", + "stock_frozen_upto", + "stock_frozen_upto_days", + "stock_auth_role", + "batch_id_sb", + "use_naming_series", + "naming_series_prefix" + ], "fields": [ { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "default": "Item Code", - "fetch_if_empty": 0, "fieldname": "item_naming_by", "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": "Item Naming By", - "length": 0, - "no_copy": 0, - "options": "Item Code\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 + "options": "Item Code\nNaming Series" }, { - "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": "item_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": 0, "label": "Default Item Group", - "length": 0, - "no_copy": 0, - "options": "Item 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": "Item 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": "stock_uom", "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": "Default Stock UOM", - "length": 0, - "no_copy": 0, - "options": "UOM", - "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": "UOM" }, { - "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_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": "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, - "fetch_if_empty": 0, "fieldname": "sample_retention_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": "Sample Retention 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, - "fetch_if_empty": 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, - "print_hide": 0, - "print_hide_if_no_value": 0, - "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": "valuation_method", "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": "Default Valuation Method", - "length": 0, - "no_copy": 0, - "options": "FIFO\nMoving Average", - "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": "FIFO\nMoving Average" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "description": "Percentage you are allowed to receive or deliver more against the quantity ordered. For example: If you have ordered 100 units. and your Allowance is 10% then you are allowed to receive 110 units.", - "fetch_if_empty": 0, "fieldname": "over_delivery_receipt_allowance", "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": "Over Delivery/Receipt Allowance (%)", - "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": "Over Delivery/Receipt Allowance (%)" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "default": "Stop", - "fetch_if_empty": 0, "fieldname": "action_if_quality_inspection_is_not_submitted", "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": "Action if Quality inspection is not submitted", - "length": 0, - "no_copy": 0, - "options": "Stop\nWarn", - "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": "Stop\nWarn" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "default": "1", - "fetch_if_empty": 0, "fieldname": "show_barcode_field", "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 Barcode Field", - "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": "Show Barcode Field" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "default": "1", - "fetch_if_empty": 0, "fieldname": "clean_description_html", "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": "Convert Item Description to Clean HTML", - "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": "Convert Item Description to Clean HTML" }, { - "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_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, - "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, - "fetch_if_empty": 0, + "default": "0", "fieldname": "auto_insert_price_list_rate_if_missing", "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": "Auto insert Price List rate if missing", - "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": "Auto insert Price List rate if missing" }, { - "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_stock", "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 Stock", - "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 Stock" }, { - "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 + "fieldtype": "Column Break" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "default": "1", - "fetch_if_empty": 0, "fieldname": "automatically_set_serial_nos_based_on_fifo", "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": "Automatically Set Serial Nos based on FIFO", - "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": "Automatically Set Serial Nos based on FIFO" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "default": "1", - "fetch_if_empty": 0, "fieldname": "set_qty_in_transactions_based_on_serial_no_input", "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 Qty in Transactions based on Serial No Input", - "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": "Set Qty in Transactions based on Serial No Input" }, { - "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_material_request", "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 Material Request", - "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": "Auto Material Request" }, { - "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": "auto_indent", "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": "Raise Material Request when stock reaches re-order level", - "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": "Raise Material Request when stock reaches re-order level" }, { - "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": "reorder_email_notify", "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": "Notify by Email on creation of automatic Material Request", - "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": "Notify by Email on creation of automatic Material Request" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "freeze_stock_entries", "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": "Freeze Stock Entries", - "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": "Freeze Stock Entries" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "stock_frozen_upto", "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": "Stock Frozen Upto", - "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": "Stock Frozen Upto" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "stock_frozen_upto_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": "Freeze Stocks Older Than [Days]", - "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": "Freeze Stocks Older Than [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": "stock_auth_role", "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": "Role Allowed to edit frozen stock", - "length": 0, - "no_copy": 0, - "options": "Role", - "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": "Role" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "batch_id_sb", "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": "Batch Identification", - "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": "Batch Identification" }, { - "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": "use_naming_series", "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": "Use Naming Series", - "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": "Use Naming Series" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "default": "BATCH-", "depends_on": "eval:doc.use_naming_series==1", - "fetch_if_empty": 0, "fieldname": "naming_series_prefix", "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": "Naming Series Prefix", - "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": "Naming Series Prefix" + }, + { + "fieldname": "inter_warehouse_transfer_settings_section", + "fieldtype": "Section Break", + "label": "Inter Warehouse Transfer Settings" + }, + { + "default": "0", + "fieldname": "allow_from_dn", + "fieldtype": "Check", + "label": "Allow Material Transfer From Delivery Note and Sales Invoice" + }, + { + "default": "0", + "fieldname": "allow_from_pr", + "fieldtype": "Check", + "label": "Allow Material Transfer From Purchase Receipt and Purchase Invoice" } ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, "icon": "icon-cog", "idx": 1, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, "issingle": 1, - "istable": 0, - "max_attachments": 0, - "modified": "2019-07-04 01:19:07.738045", + "links": [], + "modified": "2020-04-01 18:11:25.417678", "modified_by": "Administrator", "module": "Stock", "name": "Stock 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": "Stock 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": 0, - "sort_order": "ASC", - "track_changes": 0, - "track_seen": 0, - "track_views": 0 + "sort_field": "modified", + "sort_order": "ASC" } \ No newline at end of file diff --git a/erpnext/stock/doctype/stock_settings/stock_settings.py b/erpnext/stock/doctype/stock_settings/stock_settings.py index 93b5eee75c..4c7828b873 100644 --- a/erpnext/stock/doctype/stock_settings/stock_settings.py +++ b/erpnext/stock/doctype/stock_settings/stock_settings.py @@ -8,6 +8,8 @@ import frappe from frappe import _ from frappe.model.document import Document from frappe.utils.html_utils import clean_html +from frappe.utils import cint +from frappe.custom.doctype.property_setter.property_setter import make_property_setter class StockSettings(Document): def validate(self): @@ -61,6 +63,15 @@ class StockSettings(Document): # changed to text frappe.enqueue('erpnext.stock.doctype.stock_settings.stock_settings.clean_all_descriptions', now=frappe.flags.in_test) + def on_update(self): + self.toggle_warehouse_field_for_inter_warehouse_transfer() + + def toggle_warehouse_field_for_inter_warehouse_transfer(self): + make_property_setter("Sales Invoice Item", "target_warehouse", "hidden", 1 - cint(self.allow_from_dn), "Check") + make_property_setter("Delivery Note Item", "target_warehouse", "hidden", 1 - cint(self.allow_from_dn), "Check") + make_property_setter("Purchase Invoice Item", "from_warehouse", "hidden", 1 - cint(self.allow_from_pr), "Check") + make_property_setter("Purchase Receipt Item", "from_warehouse", "hidden", 1 - cint(self.allow_from_pr), "Check") + def clean_all_descriptions(): for item in frappe.get_all('Item', ['name', 'description']): From 4de24168065998337065b1db44d254f11c971446 Mon Sep 17 00:00:00 2001 From: Saqib Ansari Date: Mon, 6 Apr 2020 12:34:38 +0530 Subject: [PATCH 38/50] fix: change request status on payment entry cancel --- .../doctype/payment_entry/payment_entry.py | 5 ++++ .../payment_request/payment_request.py | 27 +++++++++++++------ .../payment_request/test_payment_request.py | 17 ++++++++++++ erpnext/hooks.py | 2 +- 4 files changed, 42 insertions(+), 9 deletions(-) diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py index 55d275831e..a453e95b2b 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.py +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py @@ -81,7 +81,12 @@ class PaymentEntry(AccountsController): self.update_advance_paid() self.update_expense_claim() self.delink_advance_entry_references() + self.set_payment_req_status() self.set_status() + + def set_payment_req_status(self): + from erpnext.accounts.doctype.payment_request.payment_request import update_payment_req_status + update_payment_req_status(self, None) def update_outstanding_amounts(self): self.set_missing_ref_details(force=True) diff --git a/erpnext/accounts/doctype/payment_request/payment_request.py b/erpnext/accounts/doctype/payment_request/payment_request.py index bef6b7b17d..5a0d092796 100644 --- a/erpnext/accounts/doctype/payment_request/payment_request.py +++ b/erpnext/accounts/doctype/payment_request/payment_request.py @@ -417,20 +417,31 @@ def make_payment_entry(docname): doc = frappe.get_doc("Payment Request", docname) return doc.create_payment_entry(submit=False).as_dict() -def make_status_as_paid(doc, method): +def update_payment_req_status(doc, method): + from erpnext.accounts.doctype.payment_entry.payment_entry import get_reference_details + for ref in doc.references: payment_request_name = frappe.db.get_value("Payment Request", {"reference_doctype": ref.reference_doctype, "reference_name": ref.reference_name, "docstatus": 1}) if payment_request_name: - doc = frappe.get_doc("Payment Request", payment_request_name) - if doc.status != "Paid" and ref.outstanding_amount <= ref.allocated_amount: - doc.db_set('status', 'Paid') - frappe.db.commit() - elif doc.status != "Partially Paid" and ref.outstanding_amount != ref.allocated_amount: - doc.db_set('status', 'Partially Paid') - frappe.db.commit() + ref_details = get_reference_details(ref.reference_doctype, ref.reference_name, doc.party_account_currency) + pay_req_doc = frappe.get_doc('Payment Request', payment_request_name) + status = pay_req_doc.status + + if status != "Paid" and not ref_details.outstanding_amount: + status = 'Paid' + elif status != "Partially Paid" and ref_details.outstanding_amount != ref_details.total_amount: + status = 'Partially Paid' + elif ref_details.outstanding_amount == ref_details.total_amount: + if pay_req_doc.payment_request_type == 'Outward': + status = 'Initiated' + elif pay_req_doc.payment_request_type == 'Inward': + status = 'Requested' + + pay_req_doc.db_set('status', status) + frappe.db.commit() def get_dummy_message(doc): return frappe.render_template("""{% if doc.contact_person -%} diff --git a/erpnext/accounts/doctype/payment_request/test_payment_request.py b/erpnext/accounts/doctype/payment_request/test_payment_request.py index 188ab0aecf..8a10e2cbd9 100644 --- a/erpnext/accounts/doctype/payment_request/test_payment_request.py +++ b/erpnext/accounts/doctype/payment_request/test_payment_request.py @@ -101,6 +101,23 @@ class TestPaymentRequest(unittest.TestCase): self.assertEqual(expected_gle[gle.account][2], gle.credit) self.assertEqual(expected_gle[gle.account][3], gle.against_voucher) + def test_status(self): + si_usd = create_sales_invoice(customer="_Test Customer USD", debit_to="_Test Receivable USD - _TC", + currency="USD", conversion_rate=50) + + pr = make_payment_request(dt="Sales Invoice", dn=si_usd.name, recipient_id="saurabh@erpnext.com", + mute_email=1, payment_gateway="_Test Gateway - USD", submit_doc=1, return_doc=1) + + pe = pr.create_payment_entry() + pr.load_from_db() + + self.assertEqual(pr.status, 'Paid') + + pe.cancel() + pr.load_from_db() + + self.assertEqual(pr.status, 'Requested') + def test_multiple_payment_entries_against_sales_order(self): # Make Sales Order, grand_total = 1000 so = make_sales_order() diff --git a/erpnext/hooks.py b/erpnext/hooks.py index 54f1a1e452..0a61aed67e 100644 --- a/erpnext/hooks.py +++ b/erpnext/hooks.py @@ -243,7 +243,7 @@ doc_events = { "on_trash": "erpnext.regional.check_deletion_permission" }, "Payment Entry": { - "on_submit": ["erpnext.regional.create_transaction_log", "erpnext.accounts.doctype.payment_request.payment_request.make_status_as_paid"], + "on_submit": ["erpnext.regional.create_transaction_log", "erpnext.accounts.doctype.payment_request.payment_request.update_payment_req_status"], "on_trash": "erpnext.regional.check_deletion_permission" }, 'Address': { From c01ec7606d259f937b56a79e9b4bbe1547ebfdd6 Mon Sep 17 00:00:00 2001 From: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com> Date: Mon, 6 Apr 2020 12:43:07 +0530 Subject: [PATCH 39/50] fix: Currency validation for default company accounts (#21094) * fix: Currency validation for default company accounts * fix: Improve message --- erpnext/setup/doctype/company/company.py | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/erpnext/setup/doctype/company/company.py b/erpnext/setup/doctype/company/company.py index 956deef928..8bcaa28707 100644 --- a/erpnext/setup/doctype/company/company.py +++ b/erpnext/setup/doctype/company/company.py @@ -16,6 +16,7 @@ from frappe.utils.nestedset import NestedSet from past.builtins import cmp import functools +from erpnext.accounts.doctype.account.account import get_account_currency class Company(NestedSet): nsm_parent_field = 'parent_company' @@ -73,18 +74,22 @@ class Company(NestedSet): def validate_default_accounts(self): accounts = [ - "default_bank_account", "default_cash_account", - "default_receivable_account", "default_payable_account", - "default_expense_account", "default_income_account", - "stock_received_but_not_billed", "stock_adjustment_account", - "expenses_included_in_valuation", "default_payroll_payable_account" + ["Default Bank Account", "default_bank_account"], ["Default Cash Account", "default_cash_account"], + ["Default Receivable Account", "default_receivable_account"], ["Default Payable Account", "default_payable_account"], + ["Default Expense Account", "default_expense_account"], ["Default Income Account", "default_income_account"], + ["Stock Received But Not Billed Account", "stock_received_but_not_billed"], ["Stock Adjustment Account", "stock_adjustment_account"], + ["Expense Included In Valuation Account", "expenses_included_in_valuation"], ["Default Payroll Payable Account", "default_payroll_payable_account"] ] - for field in accounts: - if self.get(field): - for_company = frappe.db.get_value("Account", self.get(field), "company") + for account in accounts: + if self.get(account[1]): + for_company = frappe.db.get_value("Account", self.get(account[1]), "company") if for_company != self.name: - frappe.throw(_("Account {0} does not belong to company: {1}").format(self.get(field), self.name)) + frappe.throw(_("Account {0} does not belong to company: {1}").format(self.get(account[1]), self.name)) + + if get_account_currency(self.get(account[1])) != self.default_currency: + frappe.throw(_("""{0} currency must be same as company's default currency. + Please select another account""").format(frappe.bold(account[0]))) def validate_currency(self): if self.is_new(): From 433e58d131fb96bf7b514f8770ce8c0cc5394e32 Mon Sep 17 00:00:00 2001 From: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com> Date: Mon, 6 Apr 2020 14:07:20 +0530 Subject: [PATCH 40/50] feat: Add report summary in financial statements (#20876) * feat: Add report summary API for Balance Sheet and PL report * fix: Add summary cards in Cash flow report * feat: Add report summary in consolidated financial statements * fix: Remove accumulated values filter from P&L and cashflow report * fix: set company default currency in profit and loss statement if no data Co-authored-by: Prssanna Desai --- .../report/balance_sheet/balance_sheet.py | 55 ++++++++++++++++++- .../accounts/report/cash_flow/cash_flow.js | 5 -- .../accounts/report/cash_flow/cash_flow.py | 30 ++++++++-- .../consolidated_financial_statement.js | 14 ++++- .../consolidated_financial_statement.py | 32 +++++++---- .../accounts/report/financial_statements.py | 4 +- .../profit_and_loss_statement.js | 5 -- .../profit_and_loss_statement.py | 30 +++++----- 8 files changed, 131 insertions(+), 44 deletions(-) diff --git a/erpnext/accounts/report/balance_sheet/balance_sheet.py b/erpnext/accounts/report/balance_sheet/balance_sheet.py index 97ce4f21e8..cb1fdc1a79 100644 --- a/erpnext/accounts/report/balance_sheet/balance_sheet.py +++ b/erpnext/accounts/report/balance_sheet/balance_sheet.py @@ -58,7 +58,10 @@ def execute(filters=None): chart = get_chart_data(filters, columns, asset, liability, equity) - return columns, data, message, chart + report_summary = get_report_summary(period_list, asset, liability, equity, provisional_profit_loss, + total_credit, currency, filters) + + return columns, data, message, chart, report_summary def get_provisional_profit_loss(asset, liability, equity, period_list, company, currency=None, consolidated=False): provisional_profit_loss = {} @@ -120,6 +123,56 @@ def check_opening_balance(asset, liability, equity): return _("Previous Financial Year is not closed"),opening_balance return None,None +def get_report_summary(period_list, asset, liability, equity, provisional_profit_loss, total_credit, currency, + filters, consolidated=False): + + net_asset, net_liability, net_equity, net_provisional_profit_loss = 0.0, 0.0, 0.0, 0.0 + + if filters.get('accumulated_values'): + period_list = [period_list[-1]] + + for period in period_list: + key = period if consolidated else period.key + if asset: + net_asset += asset[-2].get(key) + if liability: + net_liability += liability[-2].get(key) + if equity: + net_equity += equity[-2].get(key) + if provisional_profit_loss: + net_provisional_profit_loss += provisional_profit_loss.get(key) + + return [ + { + "value": net_asset, + "label": "Total Asset", + "indicator": "Green", + "datatype": "Currency", + "currency": currency + }, + { + "value": net_liability, + "label": "Total Liability", + "datatype": "Currency", + "indicator": "Red", + "currency": currency + }, + { + "value": net_equity, + "label": "Total Equity", + "datatype": "Currency", + "indicator": "Blue", + "currency": currency + }, + { + "value": net_provisional_profit_loss, + "label": "Provisional Profit / Loss (Credit)", + "indicator": "Green" if net_provisional_profit_loss > 0 else "Red", + "datatype": "Currency", + "currency": currency + } + ] + def get_chart_data(filters, columns, asset, liability, equity): labels = [d.get("label") for d in columns[2:]] diff --git a/erpnext/accounts/report/cash_flow/cash_flow.js b/erpnext/accounts/report/cash_flow/cash_flow.js index 89244c3781..904874f645 100644 --- a/erpnext/accounts/report/cash_flow/cash_flow.js +++ b/erpnext/accounts/report/cash_flow/cash_flow.js @@ -12,11 +12,6 @@ frappe.require("assets/erpnext/js/financial_statements.js", function() { frappe.query_reports["Cash Flow"]["filters"].splice(5, 1); frappe.query_reports["Cash Flow"]["filters"].push( - { - "fieldname": "accumulated_values", - "label": __("Accumulated Values"), - "fieldtype": "Check" - }, { "fieldname": "include_default_book_entries", "label": __("Include Default Book Entries"), diff --git a/erpnext/accounts/report/cash_flow/cash_flow.py b/erpnext/accounts/report/cash_flow/cash_flow.py index e349a6aaaf..be6e93cae0 100644 --- a/erpnext/accounts/report/cash_flow/cash_flow.py +++ b/erpnext/accounts/report/cash_flow/cash_flow.py @@ -8,6 +8,7 @@ from frappe.utils import cint, cstr from erpnext.accounts.report.financial_statements import (get_period_list, get_columns, get_data) from erpnext.accounts.report.profit_and_loss_statement.profit_and_loss_statement import get_net_profit_loss from erpnext.accounts.utils import get_fiscal_year +from six import iteritems def execute(filters=None): @@ -29,6 +30,7 @@ def execute(filters=None): net_profit_loss = get_net_profit_loss(income, expense, period_list, filters.company) data = [] + summary_data = {} company_currency = frappe.get_cached_value('Company', filters.company, "default_currency") for cash_flow_account in cash_flow_accounts: @@ -64,14 +66,16 @@ def execute(filters=None): section_data.append(account_data) add_total_row_account(data, section_data, cash_flow_account['section_footer'], - period_list, company_currency) + period_list, company_currency, summary_data) - add_total_row_account(data, data, _("Net Change in Cash"), period_list, company_currency) + add_total_row_account(data, data, _("Net Change in Cash"), period_list, company_currency, summary_data) columns = get_columns(filters.periodicity, period_list, filters.accumulated_values, filters.company) chart = get_chart_data(columns, data) - return columns, data, None, chart + report_summary = get_report_summary(summary_data, company_currency) + + return columns, data, None, chart, report_summary def get_cash_flow_accounts(): operation_accounts = { @@ -157,7 +161,7 @@ def get_start_date(period, accumulated_values, company): return start_date -def add_total_row_account(out, data, label, period_list, currency, consolidated = False): +def add_total_row_account(out, data, label, period_list, currency, summary_data, consolidated = False): total_row = { "account_name": "'" + _("{0}").format(label) + "'", "account": "'" + _("{0}").format(label) + "'", @@ -176,6 +180,24 @@ def add_total_row_account(out, data, label, period_list, currency, consolidated out.append(total_row) out.append({}) + summary_data[label] = total_row["total"] + +def get_report_summary(summary_data, currency): + report_summary = [] + + for label, value in iteritems(summary_data): + report_summary.append( + { + "value": value, + "label": label, + "datatype": "Currency", + "currency": currency + } + ) + + return report_summary + + def get_chart_data(columns, data): labels = [d.get("label") for d in columns[2:]] datasets = [{'name':account.get('account').replace("'", ""), 'values': [account.get('total')]} for account in data if account.get('parent_account') == None and account.get('currency')] diff --git a/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.js b/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.js index 48a030a99e..92c5ee9124 100644 --- a/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.js +++ b/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.js @@ -61,5 +61,17 @@ frappe.query_reports["Consolidated Financial Statement"] = { "fieldtype": "Check", "default": 1 } - ] + ], + "formatter": function(value, row, column, data, default_formatter) { + value = default_formatter(value, row, column, data); + + if (!data.parent_account) { + value = $(`${value}`); + + var $value = $(value).css("font-weight", "bold"); + + value = $value.wrap("

").parent().html(); + } + return value; + } } diff --git a/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py b/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py index 4a79b6a340..461291b453 100644 --- a/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py +++ b/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py @@ -8,11 +8,11 @@ from frappe.utils import flt, cint from erpnext.accounts.report.utils import get_currency, convert_to_presentation_currency from erpnext.accounts.report.financial_statements import get_fiscal_year_data, sort_accounts from erpnext.accounts.report.balance_sheet.balance_sheet import (get_provisional_profit_loss, - check_opening_balance, get_chart_data) + check_opening_balance, get_chart_data, get_report_summary as get_bs_summary) from erpnext.accounts.report.profit_and_loss_statement.profit_and_loss_statement import (get_net_profit_loss, - get_chart_data as get_pl_chart_data) + get_chart_data as get_pl_chart_data, get_report_summary as get_pl_summary) from erpnext.accounts.report.cash_flow.cash_flow import (get_cash_flow_accounts, get_account_type_based_gl_data, - add_total_row_account) + add_total_row_account, get_report_summary as get_cash_flow_summary) def execute(filters=None): columns, data, message, chart = [], [], [], [] @@ -25,17 +25,17 @@ def execute(filters=None): columns = get_columns(companies_column) if filters.get('report') == "Balance Sheet": - data, message, chart = get_balance_sheet_data(fiscal_year, companies, columns, filters) + data, message, chart, report_summary = get_balance_sheet_data(fiscal_year, companies, columns, filters) elif filters.get('report') == "Profit and Loss Statement": - data, message, chart = get_profit_loss_data(fiscal_year, companies, columns, filters) + data, message, chart, report_summary = get_profit_loss_data(fiscal_year, companies, columns, filters) else: if cint(frappe.db.get_single_value('Accounts Settings', 'use_custom_cash_flow')): from erpnext.accounts.report.cash_flow.custom_cash_flow import execute as execute_custom return execute_custom(filters=filters) - data = get_cash_flow_data(fiscal_year, companies, filters) + data, report_summary = get_cash_flow_data(fiscal_year, companies, filters) - return columns, data, message, chart + return columns, data, message, chart, report_summary def get_balance_sheet_data(fiscal_year, companies, columns, filters): asset = get_data(companies, "Asset", "Debit", fiscal_year, filters=filters) @@ -75,9 +75,12 @@ def get_balance_sheet_data(fiscal_year, companies, columns, filters): if total_credit: data.append(total_credit) + report_summary = get_bs_summary(companies, asset, liability, equity, provisional_profit_loss, total_credit, + company_currency, filters, True) + chart = get_chart_data(filters, columns, asset, liability, equity) - return data, message, chart + return data, message, chart, report_summary def get_profit_loss_data(fiscal_year, companies, columns, filters): income, expense, net_profit_loss = get_income_expense_data(companies, fiscal_year, filters) @@ -90,7 +93,9 @@ def get_profit_loss_data(fiscal_year, companies, columns, filters): chart = get_pl_chart_data(filters, columns, income, expense, net_profit_loss) - return data, None, chart + report_summary = get_pl_summary(companies, '', income, expense, net_profit_loss, True) + + return data, None, chart, report_summary def get_income_expense_data(companies, fiscal_year, filters): company_currency = get_company_currency(filters) @@ -108,6 +113,7 @@ def get_cash_flow_data(fiscal_year, companies, filters): income, expense, net_profit_loss = get_income_expense_data(companies, fiscal_year, filters) data = [] + summary_data = {} company_currency = get_company_currency(filters) for cash_flow_account in cash_flow_accounts: @@ -142,11 +148,13 @@ def get_cash_flow_data(fiscal_year, companies, filters): section_data.append(account_data) add_total_row_account(data, section_data, cash_flow_account['section_footer'], - companies, company_currency, True) + companies, company_currency, summary_data, True) - add_total_row_account(data, data, _("Net Change in Cash"), companies, company_currency, True) + add_total_row_account(data, data, _("Net Change in Cash"), companies, company_currency, summary_data, True) - return data + report_summary = get_cash_flow_summary(summary_data, company_currency) + + return data, report_summary def get_account_type_based_data(account_type, companies, fiscal_year, filters): data = {} diff --git a/erpnext/accounts/report/financial_statements.py b/erpnext/accounts/report/financial_statements.py index 080a7c9223..e760b79096 100644 --- a/erpnext/accounts/report/financial_statements.py +++ b/erpnext/accounts/report/financial_statements.py @@ -151,7 +151,7 @@ def get_data( calculate_values( accounts_by_name, gl_entries_by_account, period_list, accumulated_values, ignore_accumulated_values_for_fy) - accumulate_values_into_parents(accounts, accounts_by_name, period_list, accumulated_values) + accumulate_values_into_parents(accounts, accounts_by_name, period_list) out = prepare_data(accounts, balance_must_be, period_list, company_currency) out = filter_out_zero_value_rows(out, parent_children_map) @@ -191,7 +191,7 @@ def calculate_values( d["opening_balance"] = d.get("opening_balance", 0.0) + flt(entry.debit) - flt(entry.credit) -def accumulate_values_into_parents(accounts, accounts_by_name, period_list, accumulated_values): +def accumulate_values_into_parents(accounts, accounts_by_name, period_list): """accumulate children's values in parent accounts""" for d in reversed(accounts): if d.parent_account: diff --git a/erpnext/accounts/report/profit_and_loss_statement/profit_and_loss_statement.js b/erpnext/accounts/report/profit_and_loss_statement/profit_and_loss_statement.js index baa0bda700..2b946c0540 100644 --- a/erpnext/accounts/report/profit_and_loss_statement/profit_and_loss_statement.js +++ b/erpnext/accounts/report/profit_and_loss_statement/profit_and_loss_statement.js @@ -15,11 +15,6 @@ frappe.require("assets/erpnext/js/financial_statements.js", function() { return frappe.db.get_link_options('Project', txt); } }, - { - "fieldname": "accumulated_values", - "label": __("Accumulated Values"), - "fieldtype": "Check" - }, { "fieldname": "include_default_book_entries", "label": __("Include Default Book Entries"), 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 b96fe69ba8..81fb1e012e 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 @@ -31,20 +31,22 @@ def execute(filters=None): chart = get_chart_data(filters, columns, income, expense, net_profit_loss) - report_summary = get_report_summary(columns, income, expense, net_profit_loss, filters.periodicity, period_list) + default_currency = frappe.get_cached_value('Company', filters.company, "default_currency") + report_summary = get_report_summary(period_list, filters.periodicity, income, expense, net_profit_loss, default_currency) return columns, data, None, chart, report_summary -def get_report_summary(columns, income, expense, net_profit_loss, period_list, periodicity): - income_data, expense_data, net_profit = [], [], [] +def get_report_summary(period_list, periodicity, income, expense, net_profit_loss, default_currency, consolidated=False): + net_income, net_expense, net_profit = 0.0, 0.0, 0.0 - for p in columns[2:]: + for period in period_list: + key = period if consolidated else period.key if income: - income_data.append(income[-2].get(p.get("fieldname"))) + net_income += income[-2].get(key) if expense: - expense_data.append(expense[-2].get(p.get("fieldname"))) + net_expense += expense[-2].get(key) if net_profit_loss: - net_profit.append(net_profit_loss.get(p.get("fieldname"))) + net_profit += net_profit_loss.get(key) if (len(period_list) == 1 and periodicity== 'Yearly'): profit_label = _("Profit This Year") @@ -57,23 +59,23 @@ def get_report_summary(columns, income, expense, net_profit_loss, period_list, p return [ { - "value": net_profit[-1], - "indicator": "Green" if net_profit[-1] > 0 else "Red", + "value": net_profit, + "indicator": "Green" if net_profit > 0 else "Red", "label": profit_label, "datatype": "Currency", - "currency": net_profit_loss.get("currency") + "currency": net_profit_loss.get("currency") if net_profit_loss else default_currency }, { - "value": income_data[-1], + "value": net_income, "label": income_label, "datatype": "Currency", - "currency": income[-1].get('currency') + "currency": income[-1].get('currency') if income else default_currency }, { - "value": expense_data[-1], + "value": net_expense, "label": expense_label, "datatype": "Currency", - "currency": expense[-1].get('currency') + "currency": expense[-1].get('currency') if expense else default_currency } ] From 5317907e15ff05356fdefb3d11eb4012e75fb378 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Mon, 6 Apr 2020 17:46:34 +0530 Subject: [PATCH 41/50] fix: material request type manufacture shows items with Is Purchase Item enabled --- erpnext/public/js/controllers/buying.js | 6 ----- .../material_request/material_request.js | 24 ++++++++++++++----- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/erpnext/public/js/controllers/buying.js b/erpnext/public/js/controllers/buying.js index 3d4c4a6459..27a9de95e0 100644 --- a/erpnext/public/js/controllers/buying.js +++ b/erpnext/public/js/controllers/buying.js @@ -85,12 +85,6 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({ filters:{ 'is_sub_contracted_item': 1 } } } - else if (me.frm.doc.material_request_type == "Customer Provided") { - return{ - query: "erpnext.controllers.queries.item_query", - filters:{ 'customer': me.frm.doc.customer } - } - } else { return{ query: "erpnext.controllers.queries.item_query", diff --git a/erpnext/stock/doctype/material_request/material_request.js b/erpnext/stock/doctype/material_request/material_request.js index 6b26d38377..6110ea822c 100644 --- a/erpnext/stock/doctype/material_request/material_request.js +++ b/erpnext/stock/doctype/material_request/material_request.js @@ -19,11 +19,6 @@ frappe.ui.form.on('Material Request', { frm.set_indicator_formatter('item_code', function(doc) { return (doc.qty<=doc.ordered_qty) ? "green" : "orange"; }); - frm.set_query("item_code", "items", function() { - return { - query: "erpnext.controllers.queries.item_query" - }; - }); }, onload: function(frm) { @@ -145,7 +140,8 @@ frappe.ui.form.on('Material Request', { }, get_item_data: function(frm, item) { - if (!item.item_code) return; + if (item && !item.item_code) { return; } + frm.call({ method: "erpnext.stock.get_item_details.get_item_details", child: item, @@ -360,6 +356,22 @@ erpnext.buying.MaterialRequestController = erpnext.buying.BuyingController.exten set_schedule_date(this.frm); }, + onload: function(doc, cdt, cdn) { + this.frm.set_query("item_code", "items", function() { + if (doc.material_request_type == "Customer Provided") { + return{ + query: "erpnext.controllers.queries.item_query", + filters:{ 'customer': me.frm.doc.customer } + } + } else if (doc.material_request_type != "Manufacture") { + return{ + query: "erpnext.controllers.queries.item_query", + filters: {'is_purchase_item': 1} + } + } + }); + }, + items_add: function(doc, cdt, cdn) { var row = frappe.get_doc(cdt, cdn); if(doc.schedule_date) { From 96dd2079f3b65322a1bb0dd0afc693a575b6ecc8 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 6 Apr 2020 19:18:37 +0530 Subject: [PATCH 42/50] chore(deps): [security] bump minimist from 1.2.0 to 1.2.5 (#20937) Bumps [minimist](https://github.com/substack/minimist) from 1.2.0 to 1.2.5. **This update includes a security fix.** - [Release notes](https://github.com/substack/minimist/releases) - [Commits](https://github.com/substack/minimist/compare/1.2.0...1.2.5) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> Co-authored-by: Nabin Hait --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 9b315180fe..c5509d6e1a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1133,9 +1133,9 @@ minimatch@^3.0.4: brace-expansion "^1.1.7" minimist@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" - integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= + version "1.2.5" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" + integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== ms@2.0.0: version "2.0.0" From e05013ede3494424d59be058da3c6e3f7341eea1 Mon Sep 17 00:00:00 2001 From: marination Date: Mon, 6 Apr 2020 22:13:13 +0530 Subject: [PATCH 43/50] feat: Scan Barcode in Purchase Receipt --- erpnext/public/js/controllers/transaction.js | 2 ++ .../stock/doctype/purchase_receipt/purchase_receipt.json | 8 +++++++- erpnext/stock/get_item_details.py | 6 +++--- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js index 4397fe49c3..2c436b2bde 100644 --- a/erpnext/public/js/controllers/transaction.js +++ b/erpnext/public/js/controllers/transaction.js @@ -473,6 +473,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ item_code: item.item_code, barcode: item.barcode, serial_no: item.serial_no, + batch_no: item.batch_no, set_warehouse: me.frm.doc.set_warehouse, warehouse: item.warehouse, customer: me.frm.doc.customer || me.frm.doc.party_name, @@ -637,6 +638,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ // Add the new list to the serial no. field in grid with each in new line item.serial_no = valid_serial_nos.join('\n'); + item.conversion_factor = item.conversion_factor || 1; refresh_field("serial_no", item.name, item.parentfield); if(!doc.is_return && cint(user_defaults.set_qty_in_transactions_based_on_serial_no_input)) { diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json index 35446ecb1f..e38bb38b19 100755 --- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json +++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json @@ -47,6 +47,7 @@ "is_subcontracted", "supplier_warehouse", "items_section", + "scan_barcode", "items", "pricing_rule_details", "pricing_rules", @@ -1070,13 +1071,18 @@ "label": "Inter Company Reference", "options": "Delivery Note", "read_only": 1 + }, + { + "fieldname": "scan_barcode", + "fieldtype": "Data", + "label": "Scan Barcode" } ], "icon": "fa fa-truck", "idx": 261, "is_submittable": 1, "links": [], - "modified": "2019-12-30 19:12:49.709711", + "modified": "2020-04-06 16:31:37.444891", "modified_by": "Administrator", "module": "Stock", "name": "Purchase Receipt", diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py index 9c5a8e1be8..b1bfc90588 100644 --- a/erpnext/stock/get_item_details.py +++ b/erpnext/stock/get_item_details.py @@ -245,7 +245,7 @@ def get_basic_details(args, item, overwrite_warehouse=True): 'item_group_defaults': item_group_defaults, 'brand_defaults': brand_defaults }) - + warehouse = get_item_warehouse(item, args, overwrite_warehouse, defaults) if args.get('doctype') == "Material Request" and not args.get('material_request_type'): @@ -279,7 +279,7 @@ def get_basic_details(args, item, overwrite_warehouse=True): "cost_center": get_default_cost_center(args, item_defaults, item_group_defaults, brand_defaults), 'has_serial_no': item.has_serial_no, 'has_batch_no': item.has_batch_no, - "batch_no": None, + "batch_no": args.get("batch_no"), "uom": args.uom, "min_order_qty": flt(item.min_order_qty) if args.doctype == "Material Request" else "", "qty": flt(args.qty) or 1.0, @@ -377,7 +377,7 @@ def get_item_warehouse(item, args, overwrite_warehouse, defaults={}): else: warehouse = args.get('warehouse') - + return warehouse def update_barcode_value(out): From 4791e313dbaaba052247747ee3ccfbf9f98d3cd2 Mon Sep 17 00:00:00 2001 From: Kanchan Chauhan Date: Mon, 6 Apr 2020 22:20:42 +0530 Subject: [PATCH 44/50] fix: Mandatory field missing to create address from lead --- erpnext/crm/doctype/lead/lead.json | 17 +++++++++++------ erpnext/crm/doctype/lead/lead.py | 4 ++-- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/erpnext/crm/doctype/lead/lead.json b/erpnext/crm/doctype/lead/lead.json index b3197ae60c..514f878c9c 100644 --- a/erpnext/crm/doctype/lead/lead.json +++ b/erpnext/crm/doctype/lead/lead.json @@ -1,12 +1,10 @@ { - "actions": [], "allow_events_in_timeline": 1, "allow_import": 1, "autoname": "naming_series:", "creation": "2013-04-10 11:45:37", "doctype": "DocType", "document_type": "Document", - "email_append_to": 1, "engine": "InnoDB", "field_order": [ "organization_lead", @@ -34,6 +32,7 @@ "notes", "address_info", "address_html", + "address_type", "address_title", "address_line1", "address_line2", @@ -433,13 +432,20 @@ "fieldname": "contact_section", "fieldtype": "Section Break", "label": "Contact" + }, + { + "default": "Billing", + "depends_on": "eval: doc.__islocal", + "fieldname": "address_type", + "fieldtype": "Select", + "label": "Address Type", + "options": "Billing\nShipping\nOffice\nPersonal\nPlant\nPostal\nShop\nSubsidiary\nWarehouse\nCurrent\nPermanent\nOther" } ], "icon": "fa fa-user", "idx": 5, "image_field": "image", - "links": [], - "modified": "2020-01-13 16:16:48.885228", + "modified": "2020-04-06 20:26:11.687110", "modified_by": "Administrator", "module": "CRM", "name": "Lead", @@ -508,9 +514,8 @@ } ], "search_fields": "lead_name,lead_owner,status", - "sender_field": "email_id", "show_name_in_global_search": 1, "sort_field": "modified", "sort_order": "DESC", "title_field": "title" -} +} \ No newline at end of file diff --git a/erpnext/crm/doctype/lead/lead.py b/erpnext/crm/doctype/lead/lead.py index 985abfbc85..74b358219d 100644 --- a/erpnext/crm/doctype/lead/lead.py +++ b/erpnext/crm/doctype/lead/lead.py @@ -126,7 +126,7 @@ class Lead(SellingController): self.title = self.lead_name def create_address(self): - address_fields = ["address_title", "address_line1", "address_line2", + address_fields = ["address_type", "address_title", "address_line1", "address_line2", "city", "county", "state", "country", "pincode"] info_fields = ["email_id", "phone", "fax"] @@ -209,7 +209,7 @@ class Lead(SellingController): self.contact_doc.save() def flush_address_and_contact_fields(self): - fields = ['address_line1', 'address_line2', 'address_title', + fields = ['address_type', 'address_line1', 'address_line2', 'address_title', 'city', 'county', 'country', 'fax', 'pincode', 'state'] for field in fields: From 48307513c16d57506be8503b907f4df5c0af5a3a Mon Sep 17 00:00:00 2001 From: Himanshu Warekar Date: Tue, 7 Apr 2020 09:06:03 +0530 Subject: [PATCH 45/50] fix: update modified for opportunity --- erpnext/crm/doctype/opportunity/opportunity.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/crm/doctype/opportunity/opportunity.json b/erpnext/crm/doctype/opportunity/opportunity.json index 98a350a5c1..6a54c5fc6e 100644 --- a/erpnext/crm/doctype/opportunity/opportunity.json +++ b/erpnext/crm/doctype/opportunity/opportunity.json @@ -423,7 +423,7 @@ "icon": "fa fa-info-sign", "idx": 195, "links": [], - "modified": "2020-03-20 12:28:45.228994", + "modified": "2020-04-07 09:05:39.391109", "modified_by": "Administrator", "module": "CRM", "name": "Opportunity", From 8ef0609fc7f78ecf2ce6164a464529621bcb9a32 Mon Sep 17 00:00:00 2001 From: Vishal Dhayagude Date: Tue, 7 Apr 2020 12:07:01 +0530 Subject: [PATCH 46/50] fix: Make Sales Invoice paid when it create from shopping cart (#20879) Co-authored-by: Saqib --- erpnext/accounts/doctype/payment_request/payment_request.py | 1 + 1 file changed, 1 insertion(+) diff --git a/erpnext/accounts/doctype/payment_request/payment_request.py b/erpnext/accounts/doctype/payment_request/payment_request.py index 5a0d092796..53ff2225d3 100644 --- a/erpnext/accounts/doctype/payment_request/payment_request.py +++ b/erpnext/accounts/doctype/payment_request/payment_request.py @@ -90,6 +90,7 @@ class PaymentRequest(Document): if (hasattr(ref_doc, "order_type") and getattr(ref_doc, "order_type") == "Shopping Cart"): from erpnext.selling.doctype.sales_order.sales_order import make_sales_invoice si = make_sales_invoice(self.reference_name, ignore_permissions=True) + si.allocate_advances_automatically = True si = si.insert(ignore_permissions=True) si.submit() From 24a2c9b97893ce272fad75800db8575a03ddbe50 Mon Sep 17 00:00:00 2001 From: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com> Date: Tue, 7 Apr 2020 12:16:25 +0530 Subject: [PATCH 47/50] feat: Date range in financial statements (#21020) * feat: Date range in financial statements * feat: Add date range filter in consolidated financial statement * fix: Handle API changes in query_report Co-authored-by: Saqib --- .../report/balance_sheet/balance_sheet.py | 1 + .../accounts/report/cash_flow/cash_flow.js | 2 +- .../accounts/report/cash_flow/cash_flow.py | 3 +- .../consolidated_financial_statement.js | 33 +++++++++++++++++++ .../consolidated_financial_statement.py | 29 +++++++++------- .../accounts/report/financial_statements.py | 31 ++++++++++++----- .../profit_and_loss_statement.py | 3 +- erpnext/public/js/financial_statements.js | 33 +++++++++++++++++++ 8 files changed, 112 insertions(+), 23 deletions(-) diff --git a/erpnext/accounts/report/balance_sheet/balance_sheet.py b/erpnext/accounts/report/balance_sheet/balance_sheet.py index cb1fdc1a79..a858c1998f 100644 --- a/erpnext/accounts/report/balance_sheet/balance_sheet.py +++ b/erpnext/accounts/report/balance_sheet/balance_sheet.py @@ -9,6 +9,7 @@ from erpnext.accounts.report.financial_statements import (get_period_list, get_c def execute(filters=None): period_list = get_period_list(filters.from_fiscal_year, filters.to_fiscal_year, + filters.period_start_date, filters.period_end_date, filters.filter_based_on, filters.periodicity, company=filters.company) currency = filters.presentation_currency or frappe.get_cached_value('Company', filters.company, "default_currency") diff --git a/erpnext/accounts/report/cash_flow/cash_flow.js b/erpnext/accounts/report/cash_flow/cash_flow.js index 904874f645..e5d0c89918 100644 --- a/erpnext/accounts/report/cash_flow/cash_flow.js +++ b/erpnext/accounts/report/cash_flow/cash_flow.js @@ -9,7 +9,7 @@ frappe.require("assets/erpnext/js/financial_statements.js", function() { // filter. It won't be used in cash flow for now so we pop it. Please take // of this if you are working here. - frappe.query_reports["Cash Flow"]["filters"].splice(5, 1); + frappe.query_reports["Cash Flow"]["filters"].splice(8, 1); frappe.query_reports["Cash Flow"]["filters"].push( { diff --git a/erpnext/accounts/report/cash_flow/cash_flow.py b/erpnext/accounts/report/cash_flow/cash_flow.py index be6e93cae0..cf0946beab 100644 --- a/erpnext/accounts/report/cash_flow/cash_flow.py +++ b/erpnext/accounts/report/cash_flow/cash_flow.py @@ -17,7 +17,8 @@ def execute(filters=None): return execute_custom(filters=filters) period_list = get_period_list(filters.from_fiscal_year, filters.to_fiscal_year, - filters.periodicity, filters.accumulated_values, filters.company) + filters.period_start_date, filters.period_end_date, filters.filter_based_on, + filters.periodicity, company=filters.company) cash_flow_accounts = get_cash_flow_accounts() diff --git a/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.js b/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.js index 92c5ee9124..38fd5fa278 100644 --- a/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.js +++ b/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.js @@ -12,6 +12,39 @@ frappe.query_reports["Consolidated Financial Statement"] = { "default": frappe.defaults.get_user_default("Company"), "reqd": 1 }, + { + "fieldname":"filter_based_on", + "label": __("Filter Based On"), + "fieldtype": "Select", + "options": ["Fiscal Year", "Date Range"], + "default": ["Fiscal Year"], + "reqd": 1, + on_change: function() { + let filter_based_on = frappe.query_report.get_filter_value('filter_based_on'); + frappe.query_report.toggle_filter_display('from_fiscal_year', filter_based_on === 'Date Range'); + frappe.query_report.toggle_filter_display('to_fiscal_year', filter_based_on === 'Date Range'); + frappe.query_report.toggle_filter_display('period_start_date', filter_based_on === 'Fiscal Year'); + frappe.query_report.toggle_filter_display('period_end_date', filter_based_on === 'Fiscal Year'); + + frappe.query_report.refresh(); + } + }, + { + "fieldname":"period_start_date", + "label": __("Start Date"), + "fieldtype": "Date", + "default": frappe.datetime.nowdate(), + "hidden": 1, + "reqd": 1 + }, + { + "fieldname":"period_end_date", + "label": __("End Date"), + "fieldtype": "Date", + "default": frappe.datetime.add_months(frappe.datetime.nowdate(), 12), + "hidden": 1, + "reqd": 1 + }, { "fieldname":"from_fiscal_year", "label": __("Start Year"), diff --git a/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py b/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py index 461291b453..b62238b59b 100644 --- a/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py +++ b/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py @@ -4,7 +4,7 @@ from __future__ import unicode_literals import frappe, erpnext from frappe import _ -from frappe.utils import flt, cint +from frappe.utils import flt, cint, getdate from erpnext.accounts.report.utils import get_currency, convert_to_presentation_currency from erpnext.accounts.report.financial_statements import get_fiscal_year_data, sort_accounts from erpnext.accounts.report.balance_sheet.balance_sheet import (get_provisional_profit_loss, @@ -208,17 +208,24 @@ def get_data(companies, root_type, balance_must_be, fiscal_year, filters=None, i company_currency = get_company_currency(filters) + if filters.filter_based_on == 'Fiscal Year': + start_date = fiscal_year.year_start_date + end_date = fiscal_year.year_end_date + else: + start_date = filters.period_start_date + end_date = filters.period_end_date + gl_entries_by_account = {} for root in frappe.db.sql("""select lft, rgt from tabAccount where root_type=%s and ifnull(parent_account, '') = ''""", root_type, as_dict=1): - set_gl_entries_by_account(fiscal_year.year_start_date, - fiscal_year.year_end_date, root.lft, root.rgt, filters, + set_gl_entries_by_account(start_date, + end_date, root.lft, root.rgt, filters, gl_entries_by_account, accounts_by_name, ignore_closing_entries=False) - calculate_values(accounts_by_name, gl_entries_by_account, companies, fiscal_year, filters) + calculate_values(accounts_by_name, gl_entries_by_account, companies, start_date, filters) accumulate_values_into_parents(accounts, accounts_by_name, companies) - out = prepare_data(accounts, fiscal_year, balance_must_be, companies, company_currency) + out = prepare_data(accounts, start_date, end_date, balance_must_be, companies, company_currency) if out: add_total_row(out, root_type, balance_must_be, companies, company_currency) @@ -229,7 +236,7 @@ def get_company_currency(filters=None): return (filters.get('presentation_currency') or frappe.get_cached_value('Company', filters.company, "default_currency")) -def calculate_values(accounts_by_name, gl_entries_by_account, companies, fiscal_year, filters): +def calculate_values(accounts_by_name, gl_entries_by_account, companies, start_date, filters): for entries in gl_entries_by_account.values(): for entry in entries: key = entry.account_number or entry.account_name @@ -241,7 +248,7 @@ def calculate_values(accounts_by_name, gl_entries_by_account, companies, fiscal_ and entry.company in companies.get(company)): d[company] = d.get(company, 0.0) + flt(entry.debit) - flt(entry.credit) - if entry.posting_date < fiscal_year.year_start_date: + if entry.posting_date < getdate(start_date): d["opening_balance"] = d.get("opening_balance", 0.0) + flt(entry.debit) - flt(entry.credit) def accumulate_values_into_parents(accounts, accounts_by_name, companies): @@ -295,10 +302,8 @@ def get_accounts(root_type, filters): `tabAccount` where company = %s and root_type = %s """ , (filters.get('company'), root_type), as_dict=1) -def prepare_data(accounts, fiscal_year, balance_must_be, companies, company_currency): +def prepare_data(accounts, start_date, end_date, balance_must_be, companies, company_currency): data = [] - year_start_date = fiscal_year.year_start_date - year_end_date = fiscal_year.year_end_date for d in accounts: # add to output @@ -309,8 +314,8 @@ def prepare_data(accounts, fiscal_year, balance_must_be, companies, company_curr "account": _(d.account_name), "parent_account": _(d.parent_account), "indent": flt(d.indent), - "year_start_date": year_start_date, - "year_end_date": year_end_date, + "year_start_date": start_date, + "year_end_date": end_date, "currency": company_currency, "opening_balance": d.get("opening_balance", 0.0) * (1 if balance_must_be == "Debit" else -1) }) diff --git a/erpnext/accounts/report/financial_statements.py b/erpnext/accounts/report/financial_statements.py index e760b79096..81effd0668 100644 --- a/erpnext/accounts/report/financial_statements.py +++ b/erpnext/accounts/report/financial_statements.py @@ -18,17 +18,20 @@ from frappe.utils import (flt, getdate, get_first_day, add_months, add_days, for from six import itervalues from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions, get_dimension_with_children -def get_period_list(from_fiscal_year, to_fiscal_year, periodicity, accumulated_values=False, +def get_period_list(from_fiscal_year, to_fiscal_year, period_start_date, period_end_date, filter_based_on, periodicity, accumulated_values=False, company=None, reset_period_on_fy_change=True): """Get a list of dict {"from_date": from_date, "to_date": to_date, "key": key, "label": label} Periodicity can be (Yearly, Quarterly, Monthly)""" - fiscal_year = get_fiscal_year_data(from_fiscal_year, to_fiscal_year) - validate_fiscal_year(fiscal_year, from_fiscal_year, to_fiscal_year) - - # start with first day, so as to avoid year to_dates like 2-April if ever they occur] - year_start_date = getdate(fiscal_year.year_start_date) - year_end_date = getdate(fiscal_year.year_end_date) + if filter_based_on == 'Fiscal Year': + fiscal_year = get_fiscal_year_data(from_fiscal_year, to_fiscal_year) + validate_fiscal_year(fiscal_year, from_fiscal_year, to_fiscal_year) + year_start_date = getdate(fiscal_year.year_start_date) + year_end_date = getdate(fiscal_year.year_end_date) + else: + validate_dates(period_start_date, period_end_date) + year_start_date = getdate(period_start_date) + year_end_date = getdate(period_end_date) months_to_add = { "Yearly": 12, @@ -42,6 +45,9 @@ def get_period_list(from_fiscal_year, to_fiscal_year, periodicity, accumulated_v start_date = year_start_date months = get_months(year_start_date, year_end_date) + if (months // months_to_add) != (months / months_to_add): + months += months_to_add + for i in range(months // months_to_add): period = frappe._dict({ "from_date": start_date @@ -103,9 +109,18 @@ def get_fiscal_year_data(from_fiscal_year, to_fiscal_year): def validate_fiscal_year(fiscal_year, from_fiscal_year, to_fiscal_year): - if not fiscal_year.get('year_start_date') and not fiscal_year.get('year_end_date'): + if not fiscal_year.get('year_start_date') or not fiscal_year.get('year_end_date'): + frappe.throw(_("Start Year and End Year are mandatory")) + + if getdate(fiscal_year.get('year_end_date')) < getdate(fiscal_year.get('year_start_date')): frappe.throw(_("End Year cannot be before Start Year")) +def validate_dates(from_date, to_date): + if not from_date or not to_date: + frappe.throw("From Date and To Date are mandatory") + + if to_date < from_date: + frappe.throw("To Date cannot be less than From Date") def get_months(start_date, end_date): diff = (12 * end_date.year + end_date.month) - (12 * start_date.year + start_date.month) 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 81fb1e012e..7caa7648b1 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 @@ -9,7 +9,8 @@ from erpnext.accounts.report.financial_statements import (get_period_list, get_c def execute(filters=None): period_list = get_period_list(filters.from_fiscal_year, filters.to_fiscal_year, - filters.periodicity, filters.accumulated_values, filters.company) + filters.period_start_date, filters.period_end_date, filters.filter_based_on, filters.periodicity, + company=filters.company) income = get_data(filters.company, "Income", "Credit", period_list, filters = filters, accumulated_values=filters.accumulated_values, diff --git a/erpnext/public/js/financial_statements.js b/erpnext/public/js/financial_statements.js index dead309a5d..296c6280d8 100644 --- a/erpnext/public/js/financial_statements.js +++ b/erpnext/public/js/financial_statements.js @@ -78,6 +78,39 @@ function get_filters(){ "fieldtype": "Link", "options": "Finance Book" }, + { + "fieldname":"filter_based_on", + "label": __("Filter Based On"), + "fieldtype": "Select", + "options": ["Fiscal Year", "Date Range"], + "default": ["Fiscal Year"], + "reqd": 1, + on_change: function() { + let filter_based_on = frappe.query_report.get_filter_value('filter_based_on'); + frappe.query_report.toggle_filter_display('from_fiscal_year', filter_based_on === 'Date Range'); + frappe.query_report.toggle_filter_display('to_fiscal_year', filter_based_on === 'Date Range'); + frappe.query_report.toggle_filter_display('period_start_date', filter_based_on === 'Fiscal Year'); + frappe.query_report.toggle_filter_display('period_end_date', filter_based_on === 'Fiscal Year'); + + frappe.query_report.refresh(); + } + }, + { + "fieldname":"period_start_date", + "label": __("Start Date"), + "fieldtype": "Date", + "default": frappe.datetime.nowdate(), + "hidden": 1, + "reqd": 1 + }, + { + "fieldname":"period_end_date", + "label": __("End Date"), + "fieldtype": "Date", + "default": frappe.datetime.add_months(frappe.datetime.nowdate(), 12), + "hidden": 1, + "reqd": 1 + }, { "fieldname":"from_fiscal_year", "label": __("Start Year"), From 24e79b14e1a6d57a0f60995cb0b7e16073c585cc Mon Sep 17 00:00:00 2001 From: Vishal Dhayagude Date: Tue, 7 Apr 2020 12:18:47 +0530 Subject: [PATCH 48/50] fix(shopping cart): UX Improvements (#21034) * fix: nontype error for resolved and moved place order button at bottom left * fix: removed inline style * fix: Request for quotation move to lower right * fix: move buttons Co-authored-by: Naren Co-authored-by: Saqib --- erpnext/public/scss/website.scss | 4 ++++ .../templates/includes/order/order_taxes.html | 20 ++++++++-------- erpnext/templates/pages/cart.html | 24 +++++++++++-------- 3 files changed, 28 insertions(+), 20 deletions(-) diff --git a/erpnext/public/scss/website.scss b/erpnext/public/scss/website.scss index 7b9a70d232..735b417da1 100644 --- a/erpnext/public/scss/website.scss +++ b/erpnext/public/scss/website.scss @@ -78,3 +78,7 @@ z-index: 0; } } + +.place-order-container { + text-align: right; +} \ No newline at end of file diff --git a/erpnext/templates/includes/order/order_taxes.html b/erpnext/templates/includes/order/order_taxes.html index 4a32aa4744..ebec838d03 100644 --- a/erpnext/templates/includes/order/order_taxes.html +++ b/erpnext/templates/includes/order/order_taxes.html @@ -10,16 +10,16 @@ {% endif %} {% for d in doc.taxes %} -{% if d.base_tax_amount > 0 %} - - - {{ d.description }} - - - {{ d.get_formatted("base_tax_amount") }} - - -{% endif %} + {% if d.base_tax_amount %} + + + {{ d.description }} + + + {{ d.get_formatted("base_tax_amount") }} + + + {% endif %} {% endfor %} {% if doc.doctype == 'Quotation' %} diff --git a/erpnext/templates/pages/cart.html b/erpnext/templates/pages/cart.html index 912702e386..3033d1587d 100644 --- a/erpnext/templates/pages/cart.html +++ b/erpnext/templates/pages/cart.html @@ -12,16 +12,6 @@ {% block header_actions %} -{% if doc.items and cart_settings.enable_checkout %} - -{% endif %} -{% if doc.items and not cart_settings.enable_checkout %} - -{% endif %} {% endblock %} {% block page_content %} @@ -55,6 +45,20 @@

{{ _('Your cart is Empty') }}

{% endif %} + {% if doc.items %} +
+ {% if cart_settings.enable_checkout %} + + {% else %} + + {% endif %} +
+ {% endif %} + {% if doc.items %} {% if doc.tc_name %}