From 01b37ad704d22508b37e416870ca9dd2eae693dd Mon Sep 17 00:00:00 2001
From: Anupam K
Date: Tue, 25 Aug 2020 00:46:35 +0530
Subject: [PATCH 001/386] fix: multiselect recipients in Email Digest
---
erpnext/patches.txt | 1 +
.../v13_0/update_recipient_email_digest.py | 20 +
.../doctype/email_digest/email_digest.js | 97 +-
.../doctype/email_digest/email_digest.json | 1716 +++--------------
.../doctype/email_digest/email_digest.py | 32 +-
.../email_digest_recipient/__init__.py | 0
.../email_digest_recipient.json | 33 +
.../email_digest_recipient.py | 10 +
8 files changed, 384 insertions(+), 1525 deletions(-)
create mode 100644 erpnext/patches/v13_0/update_recipient_email_digest.py
create mode 100644 erpnext/setup/doctype/email_digest_recipient/__init__.py
create mode 100644 erpnext/setup/doctype/email_digest_recipient/email_digest_recipient.json
create mode 100644 erpnext/setup/doctype/email_digest_recipient/email_digest_recipient.py
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index e17e949b3b..049fef65eb 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -722,3 +722,4 @@ erpnext.patches.v13_0.stock_entry_enhancements
erpnext.patches.v12_0.update_state_code_for_daman_and_diu
erpnext.patches.v12_0.rename_lost_reason_detail
erpnext.patches.v13_0.update_start_end_date_for_old_shift_assignment
+erpnext.patches.v13_0.update_recipient_email_digest
diff --git a/erpnext/patches/v13_0/update_recipient_email_digest.py b/erpnext/patches/v13_0/update_recipient_email_digest.py
new file mode 100644
index 0000000000..583a04d03c
--- /dev/null
+++ b/erpnext/patches/v13_0/update_recipient_email_digest.py
@@ -0,0 +1,20 @@
+# Copyright (c) 2020, Frappe and Contributors
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+import frappe
+
+def execute():
+ frappe.reload_doc("setup", "doctype", "Email Digest")
+ email_digests = frappe.db.get_list('Email Digest', fields=['name', 'recipient_list'])
+ for email_digest in email_digests:
+ if email_digest.recipient_list:
+ for recipient in email_digest.recipient_list.split("\n"):
+ doc = frappe.get_doc({
+ 'doctype': 'Email Digest Recipient',
+ 'parenttype': 'Email Digest',
+ 'parentfield': 'recipients',
+ 'parent': email_digest.name,
+ 'recipient': recipient
+ })
+ doc.insert()
diff --git a/erpnext/setup/doctype/email_digest/email_digest.js b/erpnext/setup/doctype/email_digest/email_digest.js
index 1071ea2020..73fce45429 100644
--- a/erpnext/setup/doctype/email_digest/email_digest.js
+++ b/erpnext/setup/doctype/email_digest/email_digest.js
@@ -1,78 +1,31 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
-cur_frm.cscript.refresh = function(doc, dt, dn) {
- doc = locals[dt][dn];
- cur_frm.add_custom_button(__('View Now'), function() {
- frappe.call({
- method: 'erpnext.setup.doctype.email_digest.email_digest.get_digest_msg',
- args: {
- name: doc.name
- },
- callback: function(r) {
- var d = new frappe.ui.Dialog({
- title: __('Email Digest: ') + dn,
- width: 800
- });
- $(d.body).html(r.message);
- d.show();
- }
- });
- }, "fa fa-eye-open", "btn-default");
-
- if (!cur_frm.is_new()) {
- cur_frm.add_custom_button(__('Send Now'), function() {
- return cur_frm.call('send', null, (r) => {
- frappe.show_alert(__('Message Sent'));
+frappe.ui.form.on("Email Digest", {
+ refresh: function(frm) {
+ frm.add_custom_button(__('View Now'), function() {
+ frappe.call({
+ method: 'erpnext.setup.doctype.email_digest.email_digest.get_digest_msg',
+ args: {
+ name: frm.doc.name
+ },
+ callback: function(r) {
+ var d = new frappe.ui.Dialog({
+ title: __('Email Digest: ') + frm.doc.name,
+ width: 800
+ });
+ $(d.body).html(r.message);
+ d.show();
+ }
});
});
+
+ if (!frm.is_new()) {
+ frm.add_custom_button(__('Send Now'), function() {
+ return frm.call('send', null, (r) => {
+ frappe.show_alert({message:__("Message Sent"), indicator:'green'});
+ });
+ });
+ }
}
-};
-
-cur_frm.cscript.addremove_recipients = function(doc, dt, dn) {
- // Get user list
-
- return cur_frm.call('get_users', null, function(r) {
- // Open a dialog and display checkboxes against email addresses
- doc = locals[dt][dn];
- var d = new frappe.ui.Dialog({
- title: __('Add/Remove Recipients'),
- width: 400
- });
-
- $.each(r.user_list, function(i, v) {
- var fullname = frappe.user.full_name(v.name);
- if(fullname !== v.name) fullname = fullname + " <" + v.name + ">";
-
- if(v.enabled==0) {
- fullname = repl(" %(name)s (" + __("disabled user") + ") ", {name: v.name});
- }
-
- $('\
- '+ fullname +'
').appendTo(d.body);
- });
-
- // Display add recipients button
- d.set_primary_action("Update", function() {
- cur_frm.cscript.add_to_rec_list(doc, d.body, r.user_list.length);
- });
-
- cur_frm.rec_dialog = d;
- d.show();
- });
-}
-
-cur_frm.cscript.add_to_rec_list = function(doc, dialog, length) {
- // add checked users to list of recipients
- var rec_list = [];
- $(dialog).find('input:checked').each(function(i, input) {
- rec_list.push($(input).attr('data-id'));
- });
-
- doc.recipient_list = rec_list.join('\n');
- cur_frm.rec_dialog.hide();
- cur_frm.save();
- cur_frm.refresh_fields();
-}
+});
\ No newline at end of file
diff --git a/erpnext/setup/doctype/email_digest/email_digest.json b/erpnext/setup/doctype/email_digest/email_digest.json
index 125aca17c7..06c98e5ff9 100644
--- a/erpnext/setup/doctype/email_digest/email_digest.json
+++ b/erpnext/setup/doctype/email_digest/email_digest.json
@@ -1,1482 +1,338 @@
{
- "allow_copy": 0,
- "allow_events_in_timeline": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "autoname": "Prompt",
- "beta": 0,
- "creation": "2018-09-16 22:00:00",
- "custom": 0,
- "description": "Send regular summary reports via Email.",
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "System",
- "editable_grid": 0,
+ "actions": [],
+ "autoname": "Prompt",
+ "creation": "2018-09-16 22:00:00",
+ "description": "Send regular summary reports via Email.",
+ "doctype": "DocType",
+ "document_type": "System",
+ "engine": "InnoDB",
+ "field_order": [
+ "settings",
+ "column_break0",
+ "enabled",
+ "company",
+ "frequency",
+ "next_send",
+ "column_break1",
+ "recipients",
+ "accounts",
+ "accounts_module",
+ "income",
+ "expenses_booked",
+ "income_year_to_date",
+ "expense_year_to_date",
+ "column_break_16",
+ "bank_balance",
+ "credit_balance",
+ "invoiced_amount",
+ "payables",
+ "work_in_progress",
+ "sales_orders_to_bill",
+ "purchase_orders_to_bill",
+ "operation",
+ "column_break_21",
+ "sales_order",
+ "purchase_order",
+ "sales_orders_to_deliver",
+ "purchase_orders_to_receive",
+ "sales_invoice",
+ "purchase_invoice",
+ "column_break_operation",
+ "new_quotations",
+ "pending_quotations",
+ "issue",
+ "project",
+ "purchase_orders_items_overdue",
+ "other",
+ "tools",
+ "calendar_events",
+ "todo_list",
+ "notifications",
+ "column_break_32",
+ "add_quote"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "settings",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Email Digest Settings",
- "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": "settings",
+ "fieldtype": "Section Break",
+ "label": "Email Digest Settings"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break0",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "column_break0",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "enabled",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Enabled",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "default": "0",
+ "fieldname": "enabled",
+ "fieldtype": "Check",
+ "in_list_view": 1,
+ "label": "Enabled"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "company",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 1,
- "label": "For Company",
- "length": 0,
- "no_copy": 0,
- "options": "Company",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 1,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "in_standard_filter": 1,
+ "label": "For Company",
+ "options": "Company",
+ "remember_last_selected_value": 1,
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "frequency",
- "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": "How frequently?",
- "length": 0,
- "no_copy": 0,
- "options": "Daily\nWeekly\nMonthly",
- "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": "frequency",
+ "fieldtype": "Select",
+ "in_list_view": 1,
+ "in_standard_filter": 1,
+ "label": "How frequently?",
+ "options": "Daily\nWeekly\nMonthly",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:doc.enabled",
- "fieldname": "next_send",
- "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": "Next email will be sent on:",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "depends_on": "eval:doc.enabled",
+ "fieldname": "next_send",
+ "fieldtype": "Data",
+ "label": "Next email will be sent on:",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break1",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "column_break1",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "Note: Email will not be sent to disabled users",
- "fieldname": "recipient_list",
- "fieldtype": "Code",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Recipients",
- "length": 0,
- "no_copy": 0,
- "options": "Email",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "accounts",
+ "fieldtype": "Section Break",
+ "label": "Accounts"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "addremove_recipients",
- "fieldtype": "Button",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Add/Remove Recipients",
- "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": "accounts_module",
+ "fieldtype": "Column Break",
+ "hidden": 1,
+ "label": "Profit & Loss"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "accounts",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Accounts",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "default": "0",
+ "fieldname": "income",
+ "fieldtype": "Check",
+ "label": "New Income"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "accounts_module",
- "fieldtype": "Column Break",
- "hidden": 1,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Profit & Loss",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "default": "0",
+ "fieldname": "expenses_booked",
+ "fieldtype": "Check",
+ "label": "New Expenses"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "",
- "fieldname": "income",
- "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": "New Income",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "default": "0",
+ "fieldname": "income_year_to_date",
+ "fieldtype": "Check",
+ "label": "Annual Income"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "",
- "fieldname": "expenses_booked",
- "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": "New Expenses",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "default": "0",
+ "fieldname": "expense_year_to_date",
+ "fieldtype": "Check",
+ "label": "Annual Expenses"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "income_year_to_date",
- "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": "Annual Income",
- "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_16",
+ "fieldtype": "Column Break",
+ "label": "Balance Sheet"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "expense_year_to_date",
- "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": "Annual Expenses",
- "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": "bank_balance",
+ "fieldtype": "Check",
+ "label": "Bank Balance"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "",
- "fieldname": "column_break_16",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Balance Sheet",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "default": "0",
+ "fieldname": "credit_balance",
+ "fieldtype": "Check",
+ "label": "Bank Credit Balance"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "",
- "fieldname": "bank_balance",
- "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": "Bank Balance",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "default": "0",
+ "fieldname": "invoiced_amount",
+ "fieldtype": "Check",
+ "label": "Receivables"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "credit_balance",
- "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": "Bank Credit Balance",
- "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": "payables",
+ "fieldtype": "Check",
+ "label": "Payables"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "",
- "fieldname": "invoiced_amount",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Receivables",
- "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": "work_in_progress",
+ "fieldtype": "Column Break",
+ "label": "Work in Progress"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "",
- "fieldname": "payables",
- "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": "Payables",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "default": "0",
+ "fieldname": "sales_orders_to_bill",
+ "fieldtype": "Check",
+ "label": "Sales Orders to Bill"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "work_in_progress",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Work in Progress",
- "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": "purchase_orders_to_bill",
+ "fieldtype": "Check",
+ "label": "Purchase Orders to Bill"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "sales_orders_to_bill",
- "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": "Sales Orders to Bill",
- "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": "operation",
+ "fieldtype": "Section Break",
+ "label": "Operations"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "purchase_orders_to_bill",
- "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": "Purchase Orders to Bill",
- "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_21",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "operation",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Operations",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "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": "sales_order",
+ "fieldtype": "Check",
+ "label": "New Sales Orders"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_21",
- "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
- },
+ "default": "0",
+ "fieldname": "purchase_order",
+ "fieldtype": "Check",
+ "label": "New Purchase Orders"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "sales_order",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "New Sales Orders",
- "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": "sales_orders_to_deliver",
+ "fieldtype": "Check",
+ "label": "Sales Orders to Deliver"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "purchase_order",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "New Purchase Orders",
- "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": "purchase_orders_to_receive",
+ "fieldtype": "Check",
+ "label": "Purchase Orders to Receive"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "sales_orders_to_deliver",
- "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": "Sales Orders to Deliver",
- "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": "sales_invoice",
+ "fieldtype": "Check",
+ "label": "New Sales Invoice"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "purchase_orders_to_receive",
- "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": "Purchase Orders to Receive",
- "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": "purchase_invoice",
+ "fieldtype": "Check",
+ "label": "New Purchase Invoice"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "sales_invoice",
- "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": "New Sales Invoice",
- "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_operation",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "purchase_invoice",
- "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": "New Purchase Invoice",
- "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": "new_quotations",
+ "fieldtype": "Check",
+ "label": "New Quotations"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_operation",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "default": "0",
+ "fieldname": "pending_quotations",
+ "fieldtype": "Check",
+ "label": "Open Quotations"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "new_quotations",
- "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": "New Quotations",
- "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": "issue",
+ "fieldtype": "Check",
+ "label": "Open Issues"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "pending_quotations",
- "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": "Open Quotations",
- "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": "project",
+ "fieldtype": "Check",
+ "label": "Open Projects"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "issue",
- "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": "Open Issues",
- "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": "purchase_orders_items_overdue",
+ "fieldtype": "Check",
+ "label": "Purchase Orders Items Overdue"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "project",
- "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": "Open Projects",
- "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": "other",
+ "fieldtype": "Section Break",
+ "label": "Other"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "purchase_orders_items_overdue",
- "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": "Purchase Orders Items Overdue",
- "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": "tools",
+ "fieldtype": "Column Break",
+ "label": "Tools"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "other",
- "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": "Other",
- "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": "calendar_events",
+ "fieldtype": "Check",
+ "label": "Upcoming Calendar Events"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "tools",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Tools",
- "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": "todo_list",
+ "fieldtype": "Check",
+ "label": "Open To Do"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "calendar_events",
- "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": "Upcoming Calendar Events",
- "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": "notifications",
+ "fieldtype": "Check",
+ "label": "Open Notifications"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "todo_list",
- "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": "Open To Do",
- "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_32",
+ "fieldtype": "Column Break",
+ "label": " "
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "notifications",
- "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": "Open Notifications",
- "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": "add_quote",
+ "fieldtype": "Check",
+ "label": "Add Quote"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_32",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": " ",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "add_quote",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Add Quote",
- "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
+ "description": "Note: Email will not be sent to disabled users",
+ "fieldname": "recipients",
+ "fieldtype": "Table MultiSelect",
+ "label": "Recipients",
+ "options": "Email Digest Recipient",
+ "reqd": 1
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "icon": "fa fa-envelope",
- "idx": 1,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "menu_index": 0,
- "modified": "2019-01-16 09:52:15.149908",
- "modified_by": "Administrator",
- "module": "Setup",
- "name": "Email Digest",
- "owner": "Administrator",
+ ],
+ "icon": "fa fa-envelope",
+ "idx": 1,
+ "index_web_pages_for_search": 1,
+ "links": [],
+ "modified": "2020-08-24 23:49:00.081695",
+ "modified_by": "Administrator",
+ "module": "Setup",
+ "name": "Email Digest",
+ "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": "System Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "System Manager",
+ "share": 1,
"write": 1
- },
+ },
{
- "amend": 0,
- "cancel": 0,
- "create": 0,
- "delete": 0,
- "email": 0,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 1,
- "print": 0,
- "read": 1,
- "report": 0,
- "role": "System Manager",
- "set_user_permissions": 0,
- "share": 0,
- "submit": 0,
- "write": 0
+ "permlevel": 1,
+ "read": 1,
+ "role": "System Manager"
}
- ],
- "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/setup/doctype/email_digest/email_digest.py b/erpnext/setup/doctype/email_digest/email_digest.py
index b30bd7814b..90f90913ba 100644
--- a/erpnext/setup/doctype/email_digest/email_digest.py
+++ b/erpnext/setup/doctype/email_digest/email_digest.py
@@ -24,40 +24,26 @@ class EmailDigest(Document):
self._accounts = {}
self.currency = frappe.db.get_value('Company', self.company, "default_currency")
- def get_users(self):
- """get list of users"""
- user_list = frappe.db.sql("""
- select name, enabled from tabUser
- where name not in ({})
- and user_type != "Website User"
- order by enabled desc, name asc""".format(", ".join(["%s"]*len(STANDARD_USERS))), STANDARD_USERS, as_dict=1)
-
- if self.recipient_list:
- recipient_list = self.recipient_list.split("\n")
- else:
- recipient_list = []
- for p in user_list:
- p["checked"] = p["name"] in recipient_list and 1 or 0
-
- frappe.response['user_list'] = user_list
-
def send(self):
# send email only to enabled users
valid_users = [p[0] for p in frappe.db.sql("""select name from `tabUser`
where enabled=1""")]
- recipients = list(filter(lambda r: r in valid_users,
- self.recipient_list.split("\n")))
+ recipients = frappe.db.get_list('Email Digest Recipient',
+ filters={
+ 'parent': self.name
+ },
+ fields=['recipient'])
original_user = frappe.session.user
if recipients:
- for user_id in recipients:
- frappe.set_user(user_id)
- frappe.set_user_lang(user_id)
+ for user in recipients:
+ frappe.set_user(user.recipient)
+ frappe.set_user_lang(user.recipient)
msg_for_this_recipient = self.get_msg_html()
if msg_for_this_recipient:
frappe.sendmail(
- recipients=user_id,
+ recipients=user.recipient,
subject=_("{0} Digest").format(self.frequency),
message=msg_for_this_recipient,
reference_doctype = self.doctype,
diff --git a/erpnext/setup/doctype/email_digest_recipient/__init__.py b/erpnext/setup/doctype/email_digest_recipient/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/setup/doctype/email_digest_recipient/email_digest_recipient.json b/erpnext/setup/doctype/email_digest_recipient/email_digest_recipient.json
new file mode 100644
index 0000000000..8b2a6dcf49
--- /dev/null
+++ b/erpnext/setup/doctype/email_digest_recipient/email_digest_recipient.json
@@ -0,0 +1,33 @@
+{
+ "actions": [],
+ "creation": "2020-06-08 12:19:40.428949",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "recipient"
+ ],
+ "fields": [
+ {
+ "fieldname": "recipient",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Recipient",
+ "options": "User",
+ "reqd": 1
+ }
+ ],
+ "index_web_pages_for_search": 1,
+ "istable": 1,
+ "links": [],
+ "modified": "2020-08-24 23:10:23.217572",
+ "modified_by": "Administrator",
+ "module": "Setup",
+ "name": "Email Digest Recipient",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/setup/doctype/email_digest_recipient/email_digest_recipient.py b/erpnext/setup/doctype/email_digest_recipient/email_digest_recipient.py
new file mode 100644
index 0000000000..968c51c345
--- /dev/null
+++ b/erpnext/setup/doctype/email_digest_recipient/email_digest_recipient.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+# import frappe
+from frappe.model.document import Document
+
+class EmailDigestRecipient(Document):
+ pass
From ddfc1042396a0c71a0cab74954451dd73a1604cf Mon Sep 17 00:00:00 2001
From: Anupam K
Date: Mon, 31 Aug 2020 16:54:16 +0530
Subject: [PATCH 002/386] fix: patch
---
erpnext/patches/v13_0/update_recipient_email_digest.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/erpnext/patches/v13_0/update_recipient_email_digest.py b/erpnext/patches/v13_0/update_recipient_email_digest.py
index 583a04d03c..d9aa03f0fd 100644
--- a/erpnext/patches/v13_0/update_recipient_email_digest.py
+++ b/erpnext/patches/v13_0/update_recipient_email_digest.py
@@ -6,6 +6,7 @@ import frappe
def execute():
frappe.reload_doc("setup", "doctype", "Email Digest")
+ frappe.reload_doc("setup", "doctype", "Email Digest Recipient")
email_digests = frappe.db.get_list('Email Digest', fields=['name', 'recipient_list'])
for email_digest in email_digests:
if email_digest.recipient_list:
From d4e2a3324f6fea0dd32b472acb2a9e3e94c9e081 Mon Sep 17 00:00:00 2001
From: Anupam
Date: Tue, 13 Oct 2020 12:26:25 +0530
Subject: [PATCH 003/386] fix: review fixes
---
.../doctype/email_digest/email_digest.py | 33 ++++++++-----------
1 file changed, 14 insertions(+), 19 deletions(-)
diff --git a/erpnext/setup/doctype/email_digest/email_digest.py b/erpnext/setup/doctype/email_digest/email_digest.py
index 90f90913ba..6c66d03028 100644
--- a/erpnext/setup/doctype/email_digest/email_digest.py
+++ b/erpnext/setup/doctype/email_digest/email_digest.py
@@ -28,27 +28,22 @@ class EmailDigest(Document):
# send email only to enabled users
valid_users = [p[0] for p in frappe.db.sql("""select name from `tabUser`
where enabled=1""")]
- recipients = frappe.db.get_list('Email Digest Recipient',
- filters={
- 'parent': self.name
- },
- fields=['recipient'])
-
original_user = frappe.session.user
- if recipients:
- for user in recipients:
- frappe.set_user(user.recipient)
- frappe.set_user_lang(user.recipient)
- msg_for_this_recipient = self.get_msg_html()
- if msg_for_this_recipient:
- frappe.sendmail(
- recipients=user.recipient,
- subject=_("{0} Digest").format(self.frequency),
- message=msg_for_this_recipient,
- reference_doctype = self.doctype,
- reference_name = self.name,
- unsubscribe_message = _("Unsubscribe from this Email Digest"))
+ if self.recipients:
+ for user in self.recipients:
+ if user.recipient in valid_users:
+ frappe.set_user(user.recipient)
+ frappe.set_user_lang(user.recipient)
+ msg_for_this_recipient = self.get_msg_html()
+ if msg_for_this_recipient:
+ frappe.sendmail(
+ recipients=user.recipient,
+ subject=_("{0} Digest").format(self.frequency),
+ message=msg_for_this_recipient,
+ reference_doctype = self.doctype,
+ reference_name = self.name,
+ unsubscribe_message = _("Unsubscribe from this Email Digest"))
frappe.set_user(original_user)
frappe.set_user_lang(original_user)
From c1ba35b25b056053c886b732cd59ab6c08ba1484 Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Sun, 20 Jun 2021 12:42:06 +0530
Subject: [PATCH 004/386] feat: Organizational Chart
---
erpnext/hr/doctype/employee/employee.py | 5 +-
.../hr/page/organizational_chart/__init__.py | 0
.../page/organizational_chart/node_card.html | 27 ++
.../organizational_chart.js | 409 ++++++++++++++++++
.../organizational_chart.json | 26 ++
.../organizational_chart.py | 49 +++
erpnext/public/build.json | 3 +-
erpnext/public/scss/organizational_chart.scss | 209 +++++++++
8 files changed, 725 insertions(+), 3 deletions(-)
create mode 100644 erpnext/hr/page/organizational_chart/__init__.py
create mode 100644 erpnext/hr/page/organizational_chart/node_card.html
create mode 100644 erpnext/hr/page/organizational_chart/organizational_chart.js
create mode 100644 erpnext/hr/page/organizational_chart/organizational_chart.json
create mode 100644 erpnext/hr/page/organizational_chart/organizational_chart.py
create mode 100644 erpnext/public/scss/organizational_chart.scss
diff --git a/erpnext/hr/doctype/employee/employee.py b/erpnext/hr/doctype/employee/employee.py
index ed7d588434..7917e3abf5 100755
--- a/erpnext/hr/doctype/employee/employee.py
+++ b/erpnext/hr/doctype/employee/employee.py
@@ -476,13 +476,14 @@ def get_employee_emails(employee_list):
return employee_emails
@frappe.whitelist()
-def get_children(doctype, parent=None, company=None, is_root=False, is_tree=False):
+def get_children(doctype, parent=None, company=None, is_root=False, is_tree=False, fields=None):
filters = [['status', '!=', 'Left']]
if company and company != 'All Companies':
filters.append(['company', '=', company])
- fields = ['name as value', 'employee_name as title']
+ if not fields:
+ fields = ['name as value', 'employee_name as title']
if is_root:
parent = ''
diff --git a/erpnext/hr/page/organizational_chart/__init__.py b/erpnext/hr/page/organizational_chart/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/hr/page/organizational_chart/node_card.html b/erpnext/hr/page/organizational_chart/node_card.html
new file mode 100644
index 0000000000..057c45ee86
--- /dev/null
+++ b/erpnext/hr/page/organizational_chart/node_card.html
@@ -0,0 +1,27 @@
+
\ No newline at end of file
diff --git a/erpnext/hr/page/organizational_chart/organizational_chart.js b/erpnext/hr/page/organizational_chart/organizational_chart.js
new file mode 100644
index 0000000000..04bd9422bd
--- /dev/null
+++ b/erpnext/hr/page/organizational_chart/organizational_chart.js
@@ -0,0 +1,409 @@
+frappe.pages['organizational-chart'].on_page_load = function(wrapper) {
+ frappe.ui.make_app_page({
+ parent: wrapper,
+ title: __('Organizational Chart'),
+ single_column: true
+ });
+
+ let organizational_chart = new OrganizationalChart(wrapper);
+ $(wrapper).bind('show', ()=> {
+ organizational_chart.show();
+ });
+};
+
+class OrganizationalChart {
+
+ constructor(wrapper) {
+ this.wrapper = $(wrapper);
+ this.page = wrapper.page;
+
+ this.page.main.css({
+ 'min-height': '300px',
+ 'max-height': '600px',
+ 'overflow': 'auto',
+ 'position': 'relative'
+ });
+ this.page.main.addClass('frappe-card');
+
+ this.nodes = {};
+ this.setup_node_class();
+ }
+
+ setup_node_class() {
+ let me = this;
+ this.Node = class {
+ constructor({
+ id, parent, parent_id, image, name, title, expandable, connections, is_root // eslint-disable-line
+ }) {
+ // to setup values passed via constructor
+ $.extend(this, arguments[0]);
+
+ this.expanded = 0;
+
+ me.nodes[this.id] = this;
+ me.make_node_element(this);
+ me.setup_node_click_action(this);
+ }
+ }
+ }
+
+ make_node_element(node) {
+ let node_card = frappe.render_template('node_card', {
+ id: node.id,
+ name: node.name,
+ title: node.title,
+ image: node.image,
+ parent: node.parent_id,
+ connections: node.connections
+ });
+
+ node.parent.append(node_card);
+ node.$link = $(`#${node.id}`);
+ }
+
+ show() {
+ frappe.breadcrumbs.add('HR');
+
+ let me = this;
+ let company = this.page.add_field({
+ fieldtype: 'Link',
+ options: 'Company',
+ fieldname: 'company',
+ placeholder: __('Select Company'),
+ default: frappe.defaults.get_default('company'),
+ only_select: true,
+ reqd: 1,
+ change: () => {
+ me.company = undefined;
+
+ if (company.get_value() && me.company != company.get_value()) {
+ me.company = company.get_value();
+
+ // svg for connectors
+ me.make_svg_markers()
+
+ if (me.$hierarchy)
+ me.$hierarchy.remove();
+
+ // setup hierarchy
+ me.$hierarchy = $(
+ ``);
+
+ me.page.main.append(me.$hierarchy);
+ me.render_root_node();
+ }
+ }
+ });
+
+ company.refresh();
+ $(`[data-fieldname="company"]`).trigger('change');
+ }
+
+ make_svg_markers() {
+ $('#arrows').remove();
+
+ this.page.main.prepend(`
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `);
+ }
+
+ render_root_node() {
+ this.method = 'erpnext.hr.page.organizational_chart.organizational_chart.get_children';
+
+ let me = this;
+
+ frappe.call({
+ method: me.method,
+ args: {
+ company: me.company
+ },
+ callback: function(r) {
+ if (r.message.length) {
+ let data = r.message[0];
+
+ let root_node = new me.Node({
+ id: data.name,
+ parent: me.$hierarchy.find('.root-level'),
+ parent_id: undefined,
+ image: data.image,
+ name: data.employee_name,
+ title: data.designation,
+ expandable: true,
+ connections: data.connections,
+ is_root: true,
+ });
+
+ me.expand_node(root_node);
+ }
+ }
+ })
+ }
+
+ expand_node(node) {
+ let is_sibling = this.selected_node && this.selected_node.parent_id === node.parent_id;
+ this.set_selected_node(node);
+ this.show_active_path(node);
+ this.collapse_previous_level_nodes(node);
+
+ // since the previous node collapses, all connections to that node need to be rebuilt
+ // if a sibling node is clicked, connections don't need to be rebuilt
+ if (!is_sibling) {
+ // rebuild outgoing connections
+ this.refresh_connectors(node.parent_id);
+
+ // rebuild incoming connections
+ let grandparent = $(`#${node.parent_id}`).attr('data-parent');
+ this.refresh_connectors(grandparent)
+ }
+
+ if (node.expandable && !node.expanded) {
+ return this.load_children(node);
+ }
+ }
+
+ collapse_node() {
+ if (this.selected_node.expandable) {
+ this.selected_node.$children.hide();
+ $(`path[data-parent="${this.selected_node.id}"]`).hide();
+ this.selected_node.expanded = false;
+ }
+ }
+
+ show_active_path(node) {
+ // mark node parent on active path
+ $(`#${node.parent_id}`).addClass('active-path');
+ }
+
+ load_children(node) {
+ frappe.run_serially([
+ () => this.get_child_nodes(node.id),
+ (child_nodes) => this.render_child_nodes(node, child_nodes)
+ ]);
+ }
+
+ get_child_nodes(node_id) {
+ let me = this;
+ return new Promise(resolve => {
+ frappe.call({
+ method: this.method,
+ args: {
+ parent: node_id,
+ company: me.company
+ },
+ callback: (r) => {
+ resolve(r.message);
+ }
+ });
+ });
+ }
+
+ render_child_nodes(node, child_nodes) {
+ const last_level = this.$hierarchy.find('.level:last').index();
+ const current_level = $(`#${node.id}`).parent().parent().parent().index();
+
+ if (last_level === current_level) {
+ this.$hierarchy.append(`
+
+ `);
+ }
+
+ if (!node.$children) {
+ node.$children = $('')
+ .hide()
+ .appendTo(this.$hierarchy.find('.level:last'));
+
+ node.$children.empty();
+
+ if (child_nodes) {
+ $.each(child_nodes, (_i, data) => {
+ this.add_node(node, data);
+
+ setTimeout(() => {
+ this.add_connector(node.id, data.name);
+ }, 250);
+ });
+ }
+ }
+
+ node.$children.show();
+ $(`path[data-parent="${node.id}"]`).show();
+ node.expanded = true;
+ }
+
+ add_node(node, data) {
+ var $li = $(' ');
+
+ return new this.Node({
+ id: data.name,
+ parent: $li.appendTo(node.$children),
+ parent_id: node.id,
+ image: data.image,
+ name: data.employee_name,
+ title: data.designation,
+ expandable: data.expandable,
+ connections: data.connections,
+ children: undefined
+ });
+ }
+
+ add_connector(parent_id, child_id) {
+ let parent_node = document.querySelector(`#${parent_id}`);
+ let child_node = document.querySelector(`#${child_id}`);
+
+ // variable for the namespace
+ const svgns = 'http://www.w3.org/2000/svg';
+ let path = document.createElementNS(svgns, 'path');
+
+ // we need to connect right side of the parent to the left side of the child node
+ let pos_parent_right = {
+ x: parent_node.offsetLeft + parent_node.offsetWidth,
+ y: parent_node.offsetTop + parent_node.offsetHeight / 2
+ };
+ let pos_child_left = {
+ x: child_node.offsetLeft - 5,
+ y: child_node.offsetTop + child_node.offsetHeight / 2
+ };
+
+ let connector =
+ "M" +
+ (pos_parent_right.x) + "," + (pos_parent_right.y) + " " +
+ "C" +
+ (pos_parent_right.x + 100) + "," + (pos_parent_right.y) + " " +
+ (pos_child_left.x - 100) + "," + (pos_child_left.y) + " " +
+ (pos_child_left.x) + "," + (pos_child_left.y);
+
+ path.setAttribute("d", connector);
+ path.setAttribute("data-parent", parent_id);
+ path.setAttribute("data-child", child_id);
+
+ if ($(`#${parent_id}`).hasClass('active')) {
+ path.setAttribute("class", "active-connector");
+ path.setAttribute("marker-start", "url(#arrowstart-active)");
+ path.setAttribute("marker-end", "url(#arrowhead-active)");
+ } else if ($(`#${parent_id}`).hasClass('active-path')) {
+ path.setAttribute("class", "collapsed-connector");
+ path.setAttribute("marker-start", "url(#arrowstart-collapsed)");
+ path.setAttribute("marker-end", "url(#arrowhead-collapsed)");
+ }
+
+ $('#connectors').append(path);
+ }
+
+ set_selected_node(node) {
+ // remove .active class from the current node
+ $('.active').removeClass('active');
+
+ // add active class to the newly selected node
+ this.selected_node = node;
+ node.$link.addClass('active');
+ }
+
+ collapse_previous_level_nodes(node) {
+ let node_parent = $(`#${node.parent_id}`);
+
+ let previous_level_nodes = node_parent.parent().parent().children('li');
+ if (node_parent.parent().hasClass('root-level')) {
+ previous_level_nodes = node_parent.parent().children('li');
+ }
+
+ let node_card = undefined;
+
+ previous_level_nodes.each(function() {
+ node_card = $(this).find('.node-card');
+
+ if (!node_card.hasClass('active-path')) {
+ node_card.addClass('collapsed');
+ }
+ });
+ }
+
+ refresh_connectors(node_parent) {
+ if (!node_parent) return;
+
+ $(`path[data-parent="${node_parent}"]`).remove();
+
+ frappe.run_serially([
+ () => this.get_child_nodes(node_parent),
+ (child_nodes) => {
+ if (child_nodes) {
+ $.each(child_nodes, (_i, data) => {
+ this.add_connector(node_parent, data.name);
+ });
+ }
+ }
+ ]);
+ }
+
+ setup_node_click_action(node) {
+ let me = this;
+ let node_element = $(`#${node.id}`);
+
+ node_element.click(function() {
+ let is_sibling = me.selected_node.parent_id === node.parent_id;
+
+ if (is_sibling) {
+ me.collapse_node();
+ } else if (node_element.is(':visible')
+ && (node_element.hasClass('collapsed') || node_element.hasClass('active-path'))) {
+ me.remove_levels_after_node(node);
+ me.remove_orphaned_connectors();
+ }
+
+ me.expand_node(node);
+ });
+ }
+
+ remove_levels_after_node(node) {
+ let level = $(`#${node.id}`).parent().parent().parent();
+
+ if ($(`#${node.id}`).parent().hasClass('root-level')) {
+ level = $(`#${node.id}`).parent();
+ }
+
+ level = $('.hierarchy > li:eq('+ level.index() + ')');
+ level.nextAll('li').remove();
+
+ let nodes = level.find('.node-card');
+ let node_object = undefined;
+
+ $.each(nodes, (_i, element) => {
+ node_object = this.nodes[element.id];
+ node_object.expanded = 0;
+ node_object.$children = undefined;
+ });
+
+ nodes.removeClass('collapsed active-path');
+ }
+
+ remove_orphaned_connectors() {
+ let paths = $('#connectors > path');
+ $.each(paths, (_i, path) => {
+ let parent = $(path).data('parent');
+ let child = $(path).data('child');
+
+ if ($(parent).length || $(child).length)
+ return;
+
+ $(path).remove();
+ })
+ }
+}
diff --git a/erpnext/hr/page/organizational_chart/organizational_chart.json b/erpnext/hr/page/organizational_chart/organizational_chart.json
new file mode 100644
index 0000000000..d802781320
--- /dev/null
+++ b/erpnext/hr/page/organizational_chart/organizational_chart.json
@@ -0,0 +1,26 @@
+{
+ "content": null,
+ "creation": "2021-05-25 10:53:10.107241",
+ "docstatus": 0,
+ "doctype": "Page",
+ "idx": 0,
+ "modified": "2021-05-25 10:53:18.201931",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "organizational-chart",
+ "owner": "Administrator",
+ "page_name": "Organizational Chart",
+ "roles": [
+ {
+ "role": "HR User"
+ },
+ {
+ "role": "HR Manager"
+ }
+ ],
+ "script": null,
+ "standard": "Yes",
+ "style": null,
+ "system_page": 0,
+ "title": "Organizational Chart"
+}
\ No newline at end of file
diff --git a/erpnext/hr/page/organizational_chart/organizational_chart.py b/erpnext/hr/page/organizational_chart/organizational_chart.py
new file mode 100644
index 0000000000..be2964530b
--- /dev/null
+++ b/erpnext/hr/page/organizational_chart/organizational_chart.py
@@ -0,0 +1,49 @@
+from __future__ import unicode_literals
+import frappe
+
+@frappe.whitelist()
+def get_children(parent=None, company=None, is_root=False, is_tree=False, fields=None):
+
+ filters = [['status', '!=', 'Left']]
+ if company and company != 'All Companies':
+ filters.append(['company', '=', company])
+
+ if not fields:
+ fields = ['employee_name', 'name', 'reports_to', 'image', 'designation']
+
+ if is_root:
+ parent = ''
+ if parent and company and parent!=company:
+ filters.append(['reports_to', '=', parent])
+ else:
+ filters.append(['reports_to', '=', ''])
+
+ employees = frappe.get_list('Employee', fields=fields,
+ filters=filters, order_by='name')
+
+ for employee in employees:
+ is_expandable = frappe.get_all('Employee', filters=[
+ ['reports_to', '=', employee.get('name')]
+ ])
+ employee.connections = get_connections(employee.name)
+ employee.expandable = 1 if is_expandable else 0
+
+ return employees
+
+
+def get_connections(employee):
+ num_connections = 0
+
+ connections = frappe.get_list('Employee', filters=[
+ ['reports_to', '=', employee]
+ ])
+ num_connections += len(connections)
+
+ while connections:
+ for entry in connections:
+ connections = frappe.get_list('Employee', filters=[
+ ['reports_to', '=', entry.name]
+ ])
+ num_connections += len(connections)
+
+ return num_connections
\ No newline at end of file
diff --git a/erpnext/public/build.json b/erpnext/public/build.json
index 7a3cb838a9..d3ebcdf7e7 100644
--- a/erpnext/public/build.json
+++ b/erpnext/public/build.json
@@ -3,7 +3,8 @@
"public/less/erpnext.less",
"public/less/hub.less",
"public/scss/call_popup.scss",
- "public/scss/point-of-sale.scss"
+ "public/scss/point-of-sale.scss",
+ "public/scss/organizational_chart.scss"
],
"css/marketplace.css": [
"public/less/hub.less"
diff --git a/erpnext/public/scss/organizational_chart.scss b/erpnext/public/scss/organizational_chart.scss
new file mode 100644
index 0000000000..62f6ddcb6e
--- /dev/null
+++ b/erpnext/public/scss/organizational_chart.scss
@@ -0,0 +1,209 @@
+.node-card {
+ background: white;
+ stroke: 1px solid var(--gray-200);
+ box-shadow: var(--shadow-base);
+ border-radius: 0.5rem;
+ padding: 0.75rem;
+ margin-left: 3rem;
+ width: 18rem;
+
+ .btn-edit-node {
+ display: none;
+ }
+
+ .edit-chart-node {
+ display: none;
+ }
+
+ .node-edit-icon {
+ display: none;
+ }
+}
+
+.node-image {
+ width: 3.0rem;
+ height: 3.0rem;
+}
+
+.node-name {
+ font-size: 1rem;
+ line-height: 1.72;
+}
+
+.node-title {
+ font-size: 0.75rem;
+ line-height: 1.35;
+}
+
+.node-connections {
+ font-size: 0.75rem;
+ line-height: 1.35;
+}
+
+.node-card.active {
+ background: var(--blue-50);
+ border: 1px solid var(--blue-500);
+ box-shadow: var(--shadow-md);
+ border-radius: 0.5rem;
+ padding: 0.75rem;
+ width: 18rem;
+ height: 5rem;
+
+ .btn-edit-node {
+ display: flex;
+ background: var(--blue-100);
+ color: var(--blue-500);
+ padding: .25rem .5rem;
+ font-size: .75rem;
+ justify-content: center;
+ box-shadow: var(--shadow-sm);
+ }
+
+ .edit-chart-node {
+ display: block;
+ }
+
+ .node-edit-icon {
+ display: block;
+ }
+
+ .edit-chart-node {
+ margin-right: 0.25rem;
+ }
+
+ .node-edit-icon > .icon{
+ stroke: var(--blue-500);
+ }
+
+ .node-name {
+ align-items: center;
+ justify-content: space-between;
+ margin-bottom: 2px;
+ }
+}
+
+.node-card.active-path {
+ background: var(--blue-100);
+ border: 1px solid var(--blue-300);
+ box-shadow: var(--shadow-sm);
+ border-radius: 0.5rem;
+ padding: 0.75rem;
+ width: 15rem;
+ height: 3.0rem;
+
+ .btn-edit-node {
+ display: none !important;
+ }
+
+ .edit-chart-node {
+ display: none;
+ }
+
+ .node-edit-icon {
+ display: none;
+ }
+
+ .node-info {
+ display: none;
+ }
+
+ .node-title {
+ display: none;
+ }
+
+ .node-connections {
+ display: none;
+ }
+
+ .node-name {
+ font-size: 0.85rem;
+ line-height: 1.35;
+ }
+
+ .node-image {
+ width: 1.5rem;
+ height: 1.5rem;
+ }
+
+ .node-meta {
+ align-items: baseline;
+ }
+}
+
+.node-card.collapsed {
+ background: white;
+ stroke: 1px solid var(--gray-200);
+ box-shadow: var(--shadow-sm);
+ border-radius: 0.5rem;
+ padding: 0.75rem;
+ width: 15rem;
+ height: 3.0rem;
+
+ .btn-edit-node {
+ display: none !important;
+ }
+
+ .edit-chart-node {
+ display: none;
+ }
+
+ .node-edit-icon {
+ display: none;
+ }
+
+ .node-info {
+ display: none;
+ }
+
+ .node-title {
+ display: none;
+ }
+
+ .node-connections {
+ display: none;
+ }
+
+ .node-name {
+ font-size: 0.85rem;
+ line-height: 1.35;
+ }
+
+ .node-image {
+ width: 1.5rem;
+ height: 1.5rem;
+ }
+
+ .node-meta {
+ align-items: baseline;
+ }
+}
+
+// horizontal hierarchy tree view
+.hierarchy {
+ display: flex;
+ padding-top: 30px;
+}
+
+.hierarchy li {
+ list-style-type: none;
+}
+
+.child-node {
+ margin: 0px 0px 16px 0px;
+}
+
+.level {
+ margin-right: 8px;
+}
+
+#arrows {
+ position: absolute;
+}
+
+.active-connector {
+ stroke: var(--blue-500);
+}
+
+.collapsed-connector {
+ stroke: var(--blue-300);
+}
From cce19db826be54b401a9514cb6517810c98e6f7c Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Mon, 21 Jun 2021 21:55:50 +0530
Subject: [PATCH 005/386] feat: org chart mobile interactions
---
.../page/organizational_chart/node_card.html | 4 +-
.../organizational_chart.js | 329 +++++++++++++++++-
.../organizational_chart.py | 6 +-
erpnext/public/scss/organizational_chart.scss | 70 ++++
4 files changed, 404 insertions(+), 5 deletions(-)
diff --git a/erpnext/hr/page/organizational_chart/node_card.html b/erpnext/hr/page/organizational_chart/node_card.html
index 057c45ee86..e42e54f690 100644
--- a/erpnext/hr/page/organizational_chart/node_card.html
+++ b/erpnext/hr/page/organizational_chart/node_card.html
@@ -17,9 +17,9 @@
{{ title }}
{% if connections == 1 %}
- · {{ connections }} {{ __("Connection") }}
+ · {{ connections }}
{% else %}
- · {{ connections }} {{ __("Connections") }}
+ · {{ connections }}
{% endif %}
diff --git a/erpnext/hr/page/organizational_chart/organizational_chart.js b/erpnext/hr/page/organizational_chart/organizational_chart.js
index 04bd9422bd..5739a112de 100644
--- a/erpnext/hr/page/organizational_chart/organizational_chart.js
+++ b/erpnext/hr/page/organizational_chart/organizational_chart.js
@@ -5,13 +5,20 @@ frappe.pages['organizational-chart'].on_page_load = function(wrapper) {
single_column: true
});
- let organizational_chart = new OrganizationalChart(wrapper);
+ // let organizational_chart = undefined;
+ // if (frappe.is_mobile()) {
+ // organizational_chart = new OrgChartMobile(wrapper);
+ // } else {
+ // organizational_chart = new OrgChart(wrapper);
+ // }
+
+ let organizational_chart = new OrgChartMobile(wrapper);
$(wrapper).bind('show', ()=> {
organizational_chart.show();
});
};
-class OrganizationalChart {
+class OrgChart {
constructor(wrapper) {
this.wrapper = $(wrapper);
@@ -407,3 +414,321 @@ class OrganizationalChart {
})
}
}
+
+
+class OrgChartMobile {
+
+ constructor(wrapper) {
+ this.wrapper = $(wrapper);
+ this.page = wrapper.page;
+
+ this.page.main.css({
+ 'min-height': '300px',
+ 'max-height': '600px',
+ 'overflow': 'auto',
+ 'position': 'relative'
+ });
+ this.page.main.addClass('frappe-card');
+
+ this.nodes = {};
+ this.setup_node_class();
+ }
+
+ setup_node_class() {
+ let me = this;
+ this.Node = class {
+ constructor({
+ id, parent, parent_id, image, name, title, expandable, connections, is_root // eslint-disable-line
+ }) {
+ // to setup values passed via constructor
+ $.extend(this, arguments[0]);
+
+ this.expanded = 0;
+
+ me.nodes[this.id] = this;
+ me.make_node_element(this);
+ me.setup_node_click_action(this);
+ }
+ }
+ }
+
+ make_node_element(node) {
+ let node_card = frappe.render_template('node_card', {
+ id: node.id,
+ name: node.name,
+ title: node.title,
+ image: node.image,
+ parent: node.parent_id,
+ connections: node.connections,
+ is_mobile: 1
+ });
+
+ node.parent.append(node_card);
+ node.$link = $(`#${node.id}`);
+ node.$link.addClass('mobile-node');
+ }
+
+ show() {
+ frappe.breadcrumbs.add('HR');
+
+ let me = this;
+ let company = this.page.add_field({
+ fieldtype: 'Link',
+ options: 'Company',
+ fieldname: 'company',
+ placeholder: __('Select Company'),
+ default: frappe.defaults.get_default('company'),
+ only_select: true,
+ reqd: 1,
+ change: () => {
+ me.company = undefined;
+
+ if (company.get_value() && me.company != company.get_value()) {
+ me.company = company.get_value();
+
+ if (me.$hierarchy)
+ me.$hierarchy.remove();
+
+ // setup hierarchy
+ me.$hierarchy = $(
+ ``);
+
+ me.page.main.append(me.$hierarchy);
+ me.render_root_node();
+ }
+ }
+ });
+
+ company.refresh();
+ $(`[data-fieldname="company"]`).trigger('change');
+ }
+
+ render_root_node() {
+ this.method = 'erpnext.hr.page.organizational_chart.organizational_chart.get_children';
+
+ let me = this;
+
+ frappe.call({
+ method: me.method,
+ args: {
+ company: me.company
+ },
+ callback: function(r) {
+ if (r.message.length) {
+ let data = r.message[0];
+
+ let root_node = new me.Node({
+ id: data.name,
+ parent: me.$hierarchy.find('.root-level'),
+ parent_id: undefined,
+ image: data.image,
+ name: data.employee_name,
+ title: data.designation,
+ expandable: true,
+ connections: data.connections,
+ is_root: true,
+ });
+
+ me.expand_node(root_node);
+ }
+ }
+ })
+ }
+
+ expand_node(node) {
+ this.set_selected_node(node);
+ this.show_active_path(node);
+
+ if (node.expandable && !node.expanded) {
+ return this.load_children(node);
+ }
+ }
+
+ collapse_node() {
+ let node = this.selected_node;
+ if (node.expandable) {
+ node.$children.hide();
+ node.expanded = false;
+
+ // add a collapsed level to show the collapsed parent
+ // and a button beside it to move to that level
+ let node_parent = node.$link.parent();
+ node_parent.prepend(
+ `
`
+ );
+
+ node_parent
+ .find('.collapsed-level')
+ .append(node.$link);
+
+ frappe.run_serially([
+ () => this.get_child_nodes(node.parent_id, node.id),
+ (child_nodes) => this.get_node_group(child_nodes, node.id),
+ (node_group) => {
+ node_parent.find('.collapsed-level')
+ .append(node_group);
+ }
+ ]);
+ }
+ }
+
+ show_active_path(node) {
+ // mark node parent on active path
+ $(`#${node.parent_id}`).addClass('active-path');
+ }
+
+ load_children(node) {
+ frappe.run_serially([
+ () => this.get_child_nodes(node.id),
+ (child_nodes) => this.render_child_nodes(node, child_nodes)
+ ]);
+ }
+
+ get_child_nodes(node_id, exclude_node=null) {
+ let me = this;
+ return new Promise(resolve => {
+ frappe.call({
+ method: this.method,
+ args: {
+ parent: node_id,
+ company: me.company,
+ exclude_node: exclude_node
+ },
+ callback: (r) => {
+ resolve(r.message);
+ }
+ });
+ });
+ }
+
+ render_child_nodes(node, child_nodes) {
+ if (!node.$children) {
+ node.$children = $('')
+ .hide()
+ .appendTo(node.$link.parent());
+
+ node.$children.empty();
+
+ if (child_nodes) {
+ $.each(child_nodes, (_i, data) => {
+ this.add_node(node, data);
+ $(`#${data.name}`).addClass('active-child');
+ });
+ }
+ }
+
+ node.$children.show();
+ node.expanded = true;
+ }
+
+ add_node(node, data) {
+ var $li = $(' ');
+
+ return new this.Node({
+ id: data.name,
+ parent: $li.appendTo(node.$children),
+ parent_id: node.id,
+ image: data.image,
+ name: data.employee_name,
+ title: data.designation,
+ expandable: data.expandable,
+ connections: data.connections,
+ children: undefined
+ });
+ }
+
+ set_selected_node(node) {
+ // remove .active class from the current node
+ $('.active').removeClass('active');
+
+ // add active class to the newly selected node
+ this.selected_node = node;
+ node.$link.addClass('active');
+ }
+
+ setup_node_click_action(node) {
+ let me = this;
+ let node_element = $(`#${node.id}`);
+ let node_object = null;
+
+ node_element.click(function() {
+ if (node_element.is(':visible') && node_element.hasClass('active-path')) {
+ me.remove_levels_after_node(node);
+ } else {
+ me.add_node_to_hierarchy(node, true);
+ me.collapse_node();
+ }
+
+ me.expand_node(node);
+ });
+ }
+
+ add_node_to_hierarchy(node) {
+ this.$hierarchy.append(`
+
+
+
+
+ `);
+
+ node.$link.appendTo(this.$hierarchy.find('.level:last'));
+ }
+
+ get_node_group(nodes, sibling) {
+ let limit = 2;
+ const display_nodes = nodes.slice(0, limit);
+ const extra_nodes = nodes.slice(limit);
+
+ let html = display_nodes.map(node =>
+ this.get_avatar(node)
+ ).join('');
+
+ if (extra_nodes.length === 1) {
+ let node = extra_nodes[0];
+ html += this.get_avatar(node);
+ } else if (extra_nodes.length > 1) {
+ html = `
+ ${html}
+
+
+ +${extra_nodes.length}
+
+
+ `;
+ }
+
+ const $node_group =
+ $(``);
+
+ return $node_group;
+ }
+
+ get_avatar(node) {
+ return `
+
+ `
+ }
+
+ remove_levels_after_node(node) {
+ let level = $(`#${node.id}`).parent().parent();
+
+ level = $('.hierarchy-mobile > li:eq('+ (level.index()) + ')');
+ level.nextAll('li').remove();
+
+ let current_node = level.find(`#${node.id}`);
+ let node_object = this.nodes[node.id];
+
+ current_node.removeClass('active-child active-path');
+ node_object.expanded = 0;
+ node_object.$children = undefined;
+
+ level.empty().append(current_node);
+ }
+}
\ No newline at end of file
diff --git a/erpnext/hr/page/organizational_chart/organizational_chart.py b/erpnext/hr/page/organizational_chart/organizational_chart.py
index be2964530b..ae91a919b2 100644
--- a/erpnext/hr/page/organizational_chart/organizational_chart.py
+++ b/erpnext/hr/page/organizational_chart/organizational_chart.py
@@ -2,7 +2,7 @@ from __future__ import unicode_literals
import frappe
@frappe.whitelist()
-def get_children(parent=None, company=None, is_root=False, is_tree=False, fields=None):
+def get_children(parent=None, company=None, exclude_node=None, is_root=False, is_tree=False, fields=None):
filters = [['status', '!=', 'Left']]
if company and company != 'All Companies':
@@ -13,6 +13,10 @@ def get_children(parent=None, company=None, is_root=False, is_tree=False, fields
if is_root:
parent = ''
+
+ if exclude_node:
+ filters.append(['name', '!=', exclude_node])
+
if parent and company and parent!=company:
filters.append(['reports_to', '=', parent])
else:
diff --git a/erpnext/public/scss/organizational_chart.scss b/erpnext/public/scss/organizational_chart.scss
index 62f6ddcb6e..02446be11a 100644
--- a/erpnext/public/scss/organizational_chart.scss
+++ b/erpnext/public/scss/organizational_chart.scss
@@ -6,6 +6,7 @@
padding: 0.75rem;
margin-left: 3rem;
width: 18rem;
+ overflow: hidden;
.btn-edit-node {
display: none;
@@ -207,3 +208,72 @@
.collapsed-connector {
stroke: var(--blue-300);
}
+
+// mobile
+
+.hierarchy-mobile {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ padding-top: 30px;
+ padding-left: 0px;
+}
+
+.hierarchy-mobile li {
+ list-style-type: none;
+ display: flex;
+ flex-direction: column;
+ align-items: flex-end;
+}
+
+.mobile-node {
+ margin-left: 0;
+}
+
+.mobile-node.active-path {
+ width: 12.25rem;
+}
+
+.active-child {
+ width: 15.5rem;
+}
+
+.mobile-node .node-connections {
+ max-width: 80px;
+}
+
+.hierarchy-mobile .node-children {
+ margin-top: 16px;
+}
+
+// node group
+
+.collapsed-level {
+ margin-bottom: 16px;
+}
+
+.node-group {
+ background: white;
+ border: 1px solid var(--gray-300);
+ box-shadow: var(--shadow-sm);
+ border-radius: 0.5rem;
+ padding: 0.75rem;
+ margin-left: 12px;
+ width: 5rem;
+ height: 3rem;
+ overflow: hidden;
+}
+
+.node-group .avatar-group {
+ margin-left: 0px;
+}
+
+.node-group .avatar-extra-count {
+ background-color: var(--blue-100);
+ color: var(--blue-500);
+}
+
+.node-group .avatar-frame {
+ width: 1.5rem;
+ height: 1.5rem;
+}
\ No newline at end of file
From 6e3a7b4a751d6fa53b8659695753cf17518f1579 Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Tue, 29 Jun 2021 11:12:47 +0530
Subject: [PATCH 006/386] feat(mobile): sibling node group expansion and
rendering
---
.../organizational_chart.js | 64 +++++++++++++++----
erpnext/public/scss/organizational_chart.scss | 9 ++-
2 files changed, 60 insertions(+), 13 deletions(-)
diff --git a/erpnext/hr/page/organizational_chart/organizational_chart.js b/erpnext/hr/page/organizational_chart/organizational_chart.js
index 5739a112de..edaf46162e 100644
--- a/erpnext/hr/page/organizational_chart/organizational_chart.js
+++ b/erpnext/hr/page/organizational_chart/organizational_chart.js
@@ -565,11 +565,12 @@ class OrgChartMobile {
frappe.run_serially([
() => this.get_child_nodes(node.parent_id, node.id),
- (child_nodes) => this.get_node_group(child_nodes, node.id),
+ (child_nodes) => this.get_node_group(child_nodes, node.parent_id),
(node_group) => {
node_parent.find('.collapsed-level')
.append(node_group);
- }
+ },
+ () => this.setup_node_group_action()
]);
}
}
@@ -651,7 +652,6 @@ class OrgChartMobile {
setup_node_click_action(node) {
let me = this;
let node_element = $(`#${node.id}`);
- let node_object = null;
node_element.click(function() {
if (node_element.is(':visible') && node_element.hasClass('active-path')) {
@@ -665,6 +665,15 @@ class OrgChartMobile {
});
}
+ setup_node_group_action() {
+ let me = this;
+
+ $('.node-group').on('click', function() {
+ let parent = $(this).attr('data-parent');
+ me.expand_sibling_group_node(parent);
+ });
+ }
+
add_node_to_hierarchy(node) {
this.$hierarchy.append(`
@@ -676,7 +685,7 @@ class OrgChartMobile {
node.$link.appendTo(this.$hierarchy.find('.level:last'));
}
- get_node_group(nodes, sibling) {
+ get_node_group(nodes, parent, collapsed=true) {
let limit = 2;
const display_nodes = nodes.slice(0, limit);
const extra_nodes = nodes.slice(limit);
@@ -700,14 +709,23 @@ class OrgChartMobile {
`;
}
- const $node_group =
- $(``);
+ if (html) {
+ const $node_group =
+ $(``);
- return $node_group;
+ if (collapsed)
+ $node_group.addClass('collapsed');
+ else
+ $node_group.addClass('mb-4');
+
+ return $node_group;
+ }
+
+ return null;
}
get_avatar(node) {
@@ -716,6 +734,30 @@ class OrgChartMobile {
`
}
+ expand_sibling_group_node(parent) {
+ let node_object = this.nodes[parent];
+ let node = node_object.$link;
+ node.removeClass('active-child active-path');
+ node_object.expanded = 0;
+ node_object.$children = undefined;
+
+ // show parent's siblings and expand parent node
+ frappe.run_serially([
+ () => this.get_child_nodes(node_object.parent_id, node_object.id),
+ (child_nodes) => this.get_node_group(child_nodes, node_object.parent_id, false),
+ (node_group) => {
+ this.$hierarchy.empty().append(node_group) },
+ () => this.setup_node_group_action(),
+ () => {
+ this.$hierarchy.append(`
+
+ `);
+ this.$hierarchy.append(node);
+ this.expand_node(node_object);
+ }
+ ]);
+ }
+
remove_levels_after_node(node) {
let level = $(`#${node.id}`).parent().parent();
diff --git a/erpnext/public/scss/organizational_chart.scss b/erpnext/public/scss/organizational_chart.scss
index 02446be11a..b6d50a0470 100644
--- a/erpnext/public/scss/organizational_chart.scss
+++ b/erpnext/public/scss/organizational_chart.scss
@@ -258,10 +258,10 @@
box-shadow: var(--shadow-sm);
border-radius: 0.5rem;
padding: 0.75rem;
- margin-left: 12px;
- width: 5rem;
+ width: 18rem;
height: 3rem;
overflow: hidden;
+ align-items: center;
}
.node-group .avatar-group {
@@ -276,4 +276,9 @@
.node-group .avatar-frame {
width: 1.5rem;
height: 1.5rem;
+}
+
+.node-group.collapsed {
+ width: 5rem;
+ margin-left: 12px;
}
\ No newline at end of file
From 25e8723032aec69e7347ece7e714331cc2a35815 Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Tue, 29 Jun 2021 15:06:09 +0530
Subject: [PATCH 007/386] fix: expanded node group interactions and visibility
---
.../organizational_chart.js | 23 +++++++++++++++----
erpnext/public/scss/organizational_chart.scss | 9 +++++++-
2 files changed, 26 insertions(+), 6 deletions(-)
diff --git a/erpnext/hr/page/organizational_chart/organizational_chart.js b/erpnext/hr/page/organizational_chart/organizational_chart.js
index edaf46162e..f693cf6ba6 100644
--- a/erpnext/hr/page/organizational_chart/organizational_chart.js
+++ b/erpnext/hr/page/organizational_chart/organizational_chart.js
@@ -486,6 +486,13 @@ class OrgChartMobile {
if (company.get_value() && me.company != company.get_value()) {
me.company = company.get_value();
+ if (me.$sibling_group)
+ me.$sibling_group.remove();
+
+ // setup sibling group wrapper
+ me.$sibling_group = $(`
`);
+ me.page.main.append(me.$sibling_group);
+
if (me.$hierarchy)
me.$hierarchy.remove();
@@ -541,6 +548,12 @@ class OrgChartMobile {
this.set_selected_node(node);
this.show_active_path(node);
+ if (this.$sibling_group) {
+ const sibling_parent = this.$sibling_group.find('.node-group').attr('data-parent');
+ if (node.parent_id !== sibling_parent)
+ this.$sibling_group.empty();
+ }
+
if (node.expandable && !node.expanded) {
return this.load_children(node);
}
@@ -719,8 +732,6 @@ class OrgChartMobile {
if (collapsed)
$node_group.addClass('collapsed');
- else
- $node_group.addClass('mb-4');
return $node_group;
}
@@ -746,13 +757,15 @@ class OrgChartMobile {
() => this.get_child_nodes(node_object.parent_id, node_object.id),
(child_nodes) => this.get_node_group(child_nodes, node_object.parent_id, false),
(node_group) => {
- this.$hierarchy.empty().append(node_group) },
+ if (node_group)
+ this.$sibling_group.empty().append(node_group);
+ },
() => this.setup_node_group_action(),
() => {
- this.$hierarchy.append(`
+ this.$hierarchy.empty().append(`
`);
- this.$hierarchy.append(node);
+ this.$hierarchy.find('.level').append(node);
this.expand_node(node_object);
}
]);
diff --git a/erpnext/public/scss/organizational_chart.scss b/erpnext/public/scss/organizational_chart.scss
index b6d50a0470..6012c01573 100644
--- a/erpnext/public/scss/organizational_chart.scss
+++ b/erpnext/public/scss/organizational_chart.scss
@@ -215,7 +215,7 @@
display: flex;
flex-direction: column;
align-items: center;
- padding-top: 30px;
+ padding-top: 10px;
padding-left: 0px;
}
@@ -250,6 +250,7 @@
.collapsed-level {
margin-bottom: 16px;
+ width: 18rem;
}
.node-group {
@@ -281,4 +282,10 @@
.node-group.collapsed {
width: 5rem;
margin-left: 12px;
+}
+
+.sibling-group {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
}
\ No newline at end of file
From f5314293c6215841e87dab7462fc44d3c777804d Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Tue, 29 Jun 2021 17:48:44 +0530
Subject: [PATCH 008/386] feat: connectors for mobile node cards
---
.../organizational_chart.js | 138 ++++++++++++++++++
erpnext/public/scss/organizational_chart.scss | 1 +
2 files changed, 139 insertions(+)
diff --git a/erpnext/hr/page/organizational_chart/organizational_chart.js b/erpnext/hr/page/organizational_chart/organizational_chart.js
index f693cf6ba6..15334bd4ca 100644
--- a/erpnext/hr/page/organizational_chart/organizational_chart.js
+++ b/erpnext/hr/page/organizational_chart/organizational_chart.js
@@ -486,6 +486,9 @@ class OrgChartMobile {
if (company.get_value() && me.company != company.get_value()) {
me.company = company.get_value();
+ // svg for connectors
+ me.make_svg_markers()
+
if (me.$sibling_group)
me.$sibling_group.remove();
@@ -512,6 +515,31 @@ class OrgChartMobile {
$(`[data-fieldname="company"]`).trigger('change');
}
+ make_svg_markers() {
+ $('#arrows').remove();
+
+ this.page.main.prepend(`
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `);
+ }
+
render_root_node() {
this.method = 'erpnext.hr.page.organizational_chart.organizational_chart.get_children';
@@ -554,6 +582,14 @@ class OrgChartMobile {
this.$sibling_group.empty();
}
+ // since the previous/parent node collapses, all connections to that node need to be rebuilt
+ // rebuild outgoing connections of parent
+ this.refresh_connectors(node.parent_id, node.id);
+
+ // rebuild incoming connections of parent
+ let grandparent = $(`#${node.parent_id}`).attr('data-parent');
+ this.refresh_connectors(grandparent, node.parent_id);
+
if (node.expandable && !node.expanded) {
return this.load_children(node);
}
@@ -629,6 +665,10 @@ class OrgChartMobile {
$.each(child_nodes, (_i, data) => {
this.add_node(node, data);
$(`#${data.name}`).addClass('active-child');
+
+ setTimeout(() => {
+ this.add_connector(node.id, data.name);
+ }, 250);
});
}
}
@@ -653,6 +693,83 @@ class OrgChartMobile {
});
}
+ add_connector(parent_id, child_id) {
+ let parent_node = document.querySelector(`#${parent_id}`);
+ let child_node = document.querySelector(`#${child_id}`);
+
+ // variable for the namespace
+ const svgns = 'http://www.w3.org/2000/svg';
+ let path = document.createElementNS(svgns, 'path');
+
+ let connector = undefined;
+
+ if ($(`#${parent_id}`).hasClass('active')) {
+ connector = this.get_connector_for_active_node(parent_node, child_node);
+ } else if ($(`#${parent_id}`).hasClass('active-path')) {
+ connector = this.get_connector_for_collapsed_node(parent_node, child_node);
+ }
+
+ path.setAttribute("d", connector);
+ this.set_path_attributes(path, parent_id, child_id);
+
+ $('#connectors').append(path);
+ }
+
+ get_connector_for_active_node(parent_node, child_node) {
+ // we need to connect the bottom left of the parent to the left side of the child node
+ let pos_parent_bottom = {
+ x: parent_node.offsetLeft + 20,
+ y: parent_node.offsetTop + parent_node.offsetHeight
+ };
+ let pos_child_left = {
+ x: child_node.offsetLeft - 5,
+ y: child_node.offsetTop + child_node.offsetHeight / 2
+ };
+
+ let connector =
+ "M" +
+ (pos_parent_bottom.x) + "," + (pos_parent_bottom.y) + " " +
+ "L" +
+ (pos_parent_bottom.x) + "," + (pos_child_left.y) + " " +
+ "L" +
+ (pos_child_left.x) + "," + (pos_child_left.y);
+
+ return connector;
+ }
+
+ get_connector_for_collapsed_node(parent_node, child_node) {
+ // we need to connect the bottom left of the parent to the top left of the child node
+ let pos_parent_bottom = {
+ x: parent_node.offsetLeft + 20,
+ y: parent_node.offsetTop + parent_node.offsetHeight
+ };
+ let pos_child_top = {
+ x: child_node.offsetLeft + 20,
+ y: child_node.offsetTop
+ };
+
+ let connector =
+ "M" +
+ (pos_parent_bottom.x) + "," + (pos_parent_bottom.y) + " " +
+ "L" +
+ (pos_child_top.x) + "," + (pos_child_top.y);
+
+ return connector;
+ }
+
+ set_path_attributes(path, parent_id, child_id) {
+ path.setAttribute("data-parent", parent_id);
+ path.setAttribute("data-child", child_id);
+
+ if ($(`#${parent_id}`).hasClass('active')) {
+ path.setAttribute("class", "active-connector");
+ path.setAttribute("marker-start", "url(#arrowstart-active)");
+ path.setAttribute("marker-end", "url(#arrowhead-active)");
+ } else if ($(`#${parent_id}`).hasClass('active-path')) {
+ path.setAttribute("class", "collapsed-connector");
+ }
+ }
+
set_selected_node(node) {
// remove .active class from the current node
$('.active').removeClass('active');
@@ -669,6 +786,7 @@ class OrgChartMobile {
node_element.click(function() {
if (node_element.is(':visible') && node_element.hasClass('active-path')) {
me.remove_levels_after_node(node);
+ me.remove_orphaned_connectors();
} else {
me.add_node_to_hierarchy(node, true);
me.collapse_node();
@@ -786,4 +904,24 @@ class OrgChartMobile {
level.empty().append(current_node);
}
+
+ remove_orphaned_connectors() {
+ let paths = $('#connectors > path');
+ $.each(paths, (_i, path) => {
+ let parent = $(path).data('parent');
+ let child = $(path).data('child');
+
+ if ($(parent).length || $(child).length)
+ return;
+
+ $(path).remove();
+ })
+ }
+
+ refresh_connectors(node_parent, node_id) {
+ if (!node_parent) return;
+
+ $(`path[data-parent="${node_parent}"]`).remove();
+ this.add_connector(node_parent, node_id);
+ }
}
\ No newline at end of file
diff --git a/erpnext/public/scss/organizational_chart.scss b/erpnext/public/scss/organizational_chart.scss
index 6012c01573..16b8792432 100644
--- a/erpnext/public/scss/organizational_chart.scss
+++ b/erpnext/public/scss/organizational_chart.scss
@@ -199,6 +199,7 @@
#arrows {
position: absolute;
+ overflow: visible;
}
.active-connector {
From b7c61ff6510b4c6afcda7f315388c61068c13765 Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Tue, 29 Jun 2021 18:21:42 +0530
Subject: [PATCH 009/386] fix: don't refresh connections for same node
- remove all connectors while expanding a group node
---
.../organizational_chart/organizational_chart.js | 16 ++++++++++------
1 file changed, 10 insertions(+), 6 deletions(-)
diff --git a/erpnext/hr/page/organizational_chart/organizational_chart.js b/erpnext/hr/page/organizational_chart/organizational_chart.js
index 15334bd4ca..efb367ad44 100644
--- a/erpnext/hr/page/organizational_chart/organizational_chart.js
+++ b/erpnext/hr/page/organizational_chart/organizational_chart.js
@@ -573,6 +573,7 @@ class OrgChartMobile {
}
expand_node(node) {
+ const is_same_node = (this.selected_node && this.selected_node.id === node.id);
this.set_selected_node(node);
this.show_active_path(node);
@@ -582,13 +583,15 @@ class OrgChartMobile {
this.$sibling_group.empty();
}
- // since the previous/parent node collapses, all connections to that node need to be rebuilt
- // rebuild outgoing connections of parent
- this.refresh_connectors(node.parent_id, node.id);
+ if (!is_same_node) {
+ // since the previous/parent node collapses, all connections to that node need to be rebuilt
+ // rebuild outgoing connections of parent
+ this.refresh_connectors(node.parent_id, node.id);
- // rebuild incoming connections of parent
- let grandparent = $(`#${node.parent_id}`).attr('data-parent');
- this.refresh_connectors(grandparent, node.parent_id);
+ // rebuild incoming connections of parent
+ let grandparent = $(`#${node.parent_id}`).attr('data-parent');
+ this.refresh_connectors(grandparent, node.parent_id);
+ }
if (node.expandable && !node.expanded) {
return this.load_children(node);
@@ -884,6 +887,7 @@ class OrgChartMobile {
`);
this.$hierarchy.find('.level').append(node);
+ $(`#connectors`).empty();
this.expand_node(node_object);
}
]);
From bcc998e8c236766f4a8eadd5f0080050dfc7f160 Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Tue, 29 Jun 2021 19:15:08 +0530
Subject: [PATCH 010/386] chore: create separate files for Desktop and Mobile
view and bundle assets
---
.../organizational_chart.js | 930 +-----------------
erpnext/public/build.json | 9 +-
.../hierarchy_chart_desktop.js | 396 ++++++++
.../hierarchy_chart/hierarchy_chart_mobile.js | 513 ++++++++++
.../js/templates}/node_card.html | 0
...tional_chart.scss => hierarchy_chart.scss} | 0
6 files changed, 925 insertions(+), 923 deletions(-)
create mode 100644 erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
create mode 100644 erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
rename erpnext/{hr/page/organizational_chart => public/js/templates}/node_card.html (100%)
rename erpnext/public/scss/{organizational_chart.scss => hierarchy_chart.scss} (100%)
diff --git a/erpnext/hr/page/organizational_chart/organizational_chart.js b/erpnext/hr/page/organizational_chart/organizational_chart.js
index efb367ad44..0fe724c78e 100644
--- a/erpnext/hr/page/organizational_chart/organizational_chart.js
+++ b/erpnext/hr/page/organizational_chart/organizational_chart.js
@@ -5,927 +5,15 @@ frappe.pages['organizational-chart'].on_page_load = function(wrapper) {
single_column: true
});
- // let organizational_chart = undefined;
- // if (frappe.is_mobile()) {
- // organizational_chart = new OrgChartMobile(wrapper);
- // } else {
- // organizational_chart = new OrgChart(wrapper);
- // }
-
- let organizational_chart = new OrgChartMobile(wrapper);
- $(wrapper).bind('show', ()=> {
- organizational_chart.show();
- });
-};
-
-class OrgChart {
-
- constructor(wrapper) {
- this.wrapper = $(wrapper);
- this.page = wrapper.page;
-
- this.page.main.css({
- 'min-height': '300px',
- 'max-height': '600px',
- 'overflow': 'auto',
- 'position': 'relative'
- });
- this.page.main.addClass('frappe-card');
-
- this.nodes = {};
- this.setup_node_class();
- }
-
- setup_node_class() {
- let me = this;
- this.Node = class {
- constructor({
- id, parent, parent_id, image, name, title, expandable, connections, is_root // eslint-disable-line
- }) {
- // to setup values passed via constructor
- $.extend(this, arguments[0]);
-
- this.expanded = 0;
-
- me.nodes[this.id] = this;
- me.make_node_element(this);
- me.setup_node_click_action(this);
- }
- }
- }
-
- make_node_element(node) {
- let node_card = frappe.render_template('node_card', {
- id: node.id,
- name: node.name,
- title: node.title,
- image: node.image,
- parent: node.parent_id,
- connections: node.connections
- });
-
- node.parent.append(node_card);
- node.$link = $(`#${node.id}`);
- }
-
- show() {
- frappe.breadcrumbs.add('HR');
-
- let me = this;
- let company = this.page.add_field({
- fieldtype: 'Link',
- options: 'Company',
- fieldname: 'company',
- placeholder: __('Select Company'),
- default: frappe.defaults.get_default('company'),
- only_select: true,
- reqd: 1,
- change: () => {
- me.company = undefined;
-
- if (company.get_value() && me.company != company.get_value()) {
- me.company = company.get_value();
-
- // svg for connectors
- me.make_svg_markers()
-
- if (me.$hierarchy)
- me.$hierarchy.remove();
-
- // setup hierarchy
- me.$hierarchy = $(
- ``);
-
- me.page.main.append(me.$hierarchy);
- me.render_root_node();
- }
- }
- });
-
- company.refresh();
- $(`[data-fieldname="company"]`).trigger('change');
- }
-
- make_svg_markers() {
- $('#arrows').remove();
-
- this.page.main.prepend(`
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- `);
- }
-
- render_root_node() {
- this.method = 'erpnext.hr.page.organizational_chart.organizational_chart.get_children';
-
- let me = this;
-
- frappe.call({
- method: me.method,
- args: {
- company: me.company
- },
- callback: function(r) {
- if (r.message.length) {
- let data = r.message[0];
-
- let root_node = new me.Node({
- id: data.name,
- parent: me.$hierarchy.find('.root-level'),
- parent_id: undefined,
- image: data.image,
- name: data.employee_name,
- title: data.designation,
- expandable: true,
- connections: data.connections,
- is_root: true,
- });
-
- me.expand_node(root_node);
- }
- }
- })
- }
-
- expand_node(node) {
- let is_sibling = this.selected_node && this.selected_node.parent_id === node.parent_id;
- this.set_selected_node(node);
- this.show_active_path(node);
- this.collapse_previous_level_nodes(node);
-
- // since the previous node collapses, all connections to that node need to be rebuilt
- // if a sibling node is clicked, connections don't need to be rebuilt
- if (!is_sibling) {
- // rebuild outgoing connections
- this.refresh_connectors(node.parent_id);
-
- // rebuild incoming connections
- let grandparent = $(`#${node.parent_id}`).attr('data-parent');
- this.refresh_connectors(grandparent)
- }
-
- if (node.expandable && !node.expanded) {
- return this.load_children(node);
- }
- }
-
- collapse_node() {
- if (this.selected_node.expandable) {
- this.selected_node.$children.hide();
- $(`path[data-parent="${this.selected_node.id}"]`).hide();
- this.selected_node.expanded = false;
- }
- }
-
- show_active_path(node) {
- // mark node parent on active path
- $(`#${node.parent_id}`).addClass('active-path');
- }
-
- load_children(node) {
- frappe.run_serially([
- () => this.get_child_nodes(node.id),
- (child_nodes) => this.render_child_nodes(node, child_nodes)
- ]);
- }
-
- get_child_nodes(node_id) {
- let me = this;
- return new Promise(resolve => {
- frappe.call({
- method: this.method,
- args: {
- parent: node_id,
- company: me.company
- },
- callback: (r) => {
- resolve(r.message);
- }
- });
- });
- }
-
- render_child_nodes(node, child_nodes) {
- const last_level = this.$hierarchy.find('.level:last').index();
- const current_level = $(`#${node.id}`).parent().parent().parent().index();
-
- if (last_level === current_level) {
- this.$hierarchy.append(`
-
- `);
- }
-
- if (!node.$children) {
- node.$children = $('')
- .hide()
- .appendTo(this.$hierarchy.find('.level:last'));
-
- node.$children.empty();
-
- if (child_nodes) {
- $.each(child_nodes, (_i, data) => {
- this.add_node(node, data);
-
- setTimeout(() => {
- this.add_connector(node.id, data.name);
- }, 250);
- });
- }
- }
-
- node.$children.show();
- $(`path[data-parent="${node.id}"]`).show();
- node.expanded = true;
- }
-
- add_node(node, data) {
- var $li = $(' ');
-
- return new this.Node({
- id: data.name,
- parent: $li.appendTo(node.$children),
- parent_id: node.id,
- image: data.image,
- name: data.employee_name,
- title: data.designation,
- expandable: data.expandable,
- connections: data.connections,
- children: undefined
- });
- }
-
- add_connector(parent_id, child_id) {
- let parent_node = document.querySelector(`#${parent_id}`);
- let child_node = document.querySelector(`#${child_id}`);
-
- // variable for the namespace
- const svgns = 'http://www.w3.org/2000/svg';
- let path = document.createElementNS(svgns, 'path');
-
- // we need to connect right side of the parent to the left side of the child node
- let pos_parent_right = {
- x: parent_node.offsetLeft + parent_node.offsetWidth,
- y: parent_node.offsetTop + parent_node.offsetHeight / 2
- };
- let pos_child_left = {
- x: child_node.offsetLeft - 5,
- y: child_node.offsetTop + child_node.offsetHeight / 2
- };
-
- let connector =
- "M" +
- (pos_parent_right.x) + "," + (pos_parent_right.y) + " " +
- "C" +
- (pos_parent_right.x + 100) + "," + (pos_parent_right.y) + " " +
- (pos_child_left.x - 100) + "," + (pos_child_left.y) + " " +
- (pos_child_left.x) + "," + (pos_child_left.y);
-
- path.setAttribute("d", connector);
- path.setAttribute("data-parent", parent_id);
- path.setAttribute("data-child", child_id);
-
- if ($(`#${parent_id}`).hasClass('active')) {
- path.setAttribute("class", "active-connector");
- path.setAttribute("marker-start", "url(#arrowstart-active)");
- path.setAttribute("marker-end", "url(#arrowhead-active)");
- } else if ($(`#${parent_id}`).hasClass('active-path')) {
- path.setAttribute("class", "collapsed-connector");
- path.setAttribute("marker-start", "url(#arrowstart-collapsed)");
- path.setAttribute("marker-end", "url(#arrowhead-collapsed)");
- }
-
- $('#connectors').append(path);
- }
-
- set_selected_node(node) {
- // remove .active class from the current node
- $('.active').removeClass('active');
-
- // add active class to the newly selected node
- this.selected_node = node;
- node.$link.addClass('active');
- }
-
- collapse_previous_level_nodes(node) {
- let node_parent = $(`#${node.parent_id}`);
-
- let previous_level_nodes = node_parent.parent().parent().children('li');
- if (node_parent.parent().hasClass('root-level')) {
- previous_level_nodes = node_parent.parent().children('li');
- }
-
- let node_card = undefined;
-
- previous_level_nodes.each(function() {
- node_card = $(this).find('.node-card');
-
- if (!node_card.hasClass('active-path')) {
- node_card.addClass('collapsed');
- }
- });
- }
-
- refresh_connectors(node_parent) {
- if (!node_parent) return;
-
- $(`path[data-parent="${node_parent}"]`).remove();
-
- frappe.run_serially([
- () => this.get_child_nodes(node_parent),
- (child_nodes) => {
- if (child_nodes) {
- $.each(child_nodes, (_i, data) => {
- this.add_connector(node_parent, data.name);
- });
- }
- }
- ]);
- }
-
- setup_node_click_action(node) {
- let me = this;
- let node_element = $(`#${node.id}`);
-
- node_element.click(function() {
- let is_sibling = me.selected_node.parent_id === node.parent_id;
-
- if (is_sibling) {
- me.collapse_node();
- } else if (node_element.is(':visible')
- && (node_element.hasClass('collapsed') || node_element.hasClass('active-path'))) {
- me.remove_levels_after_node(node);
- me.remove_orphaned_connectors();
- }
-
- me.expand_node(node);
- });
- }
-
- remove_levels_after_node(node) {
- let level = $(`#${node.id}`).parent().parent().parent();
-
- if ($(`#${node.id}`).parent().hasClass('root-level')) {
- level = $(`#${node.id}`).parent();
- }
-
- level = $('.hierarchy > li:eq('+ level.index() + ')');
- level.nextAll('li').remove();
-
- let nodes = level.find('.node-card');
- let node_object = undefined;
-
- $.each(nodes, (_i, element) => {
- node_object = this.nodes[element.id];
- node_object.expanded = 0;
- node_object.$children = undefined;
- });
-
- nodes.removeClass('collapsed active-path');
- }
-
- remove_orphaned_connectors() {
- let paths = $('#connectors > path');
- $.each(paths, (_i, path) => {
- let parent = $(path).data('parent');
- let child = $(path).data('child');
-
- if ($(parent).length || $(child).length)
- return;
-
- $(path).remove();
- })
- }
-}
-
-
-class OrgChartMobile {
-
- constructor(wrapper) {
- this.wrapper = $(wrapper);
- this.page = wrapper.page;
-
- this.page.main.css({
- 'min-height': '300px',
- 'max-height': '600px',
- 'overflow': 'auto',
- 'position': 'relative'
- });
- this.page.main.addClass('frappe-card');
-
- this.nodes = {};
- this.setup_node_class();
- }
-
- setup_node_class() {
- let me = this;
- this.Node = class {
- constructor({
- id, parent, parent_id, image, name, title, expandable, connections, is_root // eslint-disable-line
- }) {
- // to setup values passed via constructor
- $.extend(this, arguments[0]);
-
- this.expanded = 0;
-
- me.nodes[this.id] = this;
- me.make_node_element(this);
- me.setup_node_click_action(this);
- }
- }
- }
-
- make_node_element(node) {
- let node_card = frappe.render_template('node_card', {
- id: node.id,
- name: node.name,
- title: node.title,
- image: node.image,
- parent: node.parent_id,
- connections: node.connections,
- is_mobile: 1
- });
-
- node.parent.append(node_card);
- node.$link = $(`#${node.id}`);
- node.$link.addClass('mobile-node');
- }
-
- show() {
- frappe.breadcrumbs.add('HR');
-
- let me = this;
- let company = this.page.add_field({
- fieldtype: 'Link',
- options: 'Company',
- fieldname: 'company',
- placeholder: __('Select Company'),
- default: frappe.defaults.get_default('company'),
- only_select: true,
- reqd: 1,
- change: () => {
- me.company = undefined;
-
- if (company.get_value() && me.company != company.get_value()) {
- me.company = company.get_value();
-
- // svg for connectors
- me.make_svg_markers()
-
- if (me.$sibling_group)
- me.$sibling_group.remove();
-
- // setup sibling group wrapper
- me.$sibling_group = $(`
`);
- me.page.main.append(me.$sibling_group);
-
- if (me.$hierarchy)
- me.$hierarchy.remove();
-
- // setup hierarchy
- me.$hierarchy = $(
- ``);
-
- me.page.main.append(me.$hierarchy);
- me.render_root_node();
- }
- }
- });
-
- company.refresh();
- $(`[data-fieldname="company"]`).trigger('change');
- }
-
- make_svg_markers() {
- $('#arrows').remove();
-
- this.page.main.prepend(`
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- `);
- }
-
- render_root_node() {
- this.method = 'erpnext.hr.page.organizational_chart.organizational_chart.get_children';
-
- let me = this;
-
- frappe.call({
- method: me.method,
- args: {
- company: me.company
- },
- callback: function(r) {
- if (r.message.length) {
- let data = r.message[0];
-
- let root_node = new me.Node({
- id: data.name,
- parent: me.$hierarchy.find('.root-level'),
- parent_id: undefined,
- image: data.image,
- name: data.employee_name,
- title: data.designation,
- expandable: true,
- connections: data.connections,
- is_root: true,
- });
-
- me.expand_node(root_node);
- }
- }
- })
- }
-
- expand_node(node) {
- const is_same_node = (this.selected_node && this.selected_node.id === node.id);
- this.set_selected_node(node);
- this.show_active_path(node);
-
- if (this.$sibling_group) {
- const sibling_parent = this.$sibling_group.find('.node-group').attr('data-parent');
- if (node.parent_id !== sibling_parent)
- this.$sibling_group.empty();
- }
-
- if (!is_same_node) {
- // since the previous/parent node collapses, all connections to that node need to be rebuilt
- // rebuild outgoing connections of parent
- this.refresh_connectors(node.parent_id, node.id);
-
- // rebuild incoming connections of parent
- let grandparent = $(`#${node.parent_id}`).attr('data-parent');
- this.refresh_connectors(grandparent, node.parent_id);
- }
-
- if (node.expandable && !node.expanded) {
- return this.load_children(node);
- }
- }
-
- collapse_node() {
- let node = this.selected_node;
- if (node.expandable) {
- node.$children.hide();
- node.expanded = false;
-
- // add a collapsed level to show the collapsed parent
- // and a button beside it to move to that level
- let node_parent = node.$link.parent();
- node_parent.prepend(
- `
`
- );
-
- node_parent
- .find('.collapsed-level')
- .append(node.$link);
-
- frappe.run_serially([
- () => this.get_child_nodes(node.parent_id, node.id),
- (child_nodes) => this.get_node_group(child_nodes, node.parent_id),
- (node_group) => {
- node_parent.find('.collapsed-level')
- .append(node_group);
- },
- () => this.setup_node_group_action()
- ]);
- }
- }
-
- show_active_path(node) {
- // mark node parent on active path
- $(`#${node.parent_id}`).addClass('active-path');
- }
-
- load_children(node) {
- frappe.run_serially([
- () => this.get_child_nodes(node.id),
- (child_nodes) => this.render_child_nodes(node, child_nodes)
- ]);
- }
-
- get_child_nodes(node_id, exclude_node=null) {
- let me = this;
- return new Promise(resolve => {
- frappe.call({
- method: this.method,
- args: {
- parent: node_id,
- company: me.company,
- exclude_node: exclude_node
- },
- callback: (r) => {
- resolve(r.message);
- }
- });
- });
- }
-
- render_child_nodes(node, child_nodes) {
- if (!node.$children) {
- node.$children = $('')
- .hide()
- .appendTo(node.$link.parent());
-
- node.$children.empty();
-
- if (child_nodes) {
- $.each(child_nodes, (_i, data) => {
- this.add_node(node, data);
- $(`#${data.name}`).addClass('active-child');
-
- setTimeout(() => {
- this.add_connector(node.id, data.name);
- }, 250);
- });
- }
- }
-
- node.$children.show();
- node.expanded = true;
- }
-
- add_node(node, data) {
- var $li = $(' ');
-
- return new this.Node({
- id: data.name,
- parent: $li.appendTo(node.$children),
- parent_id: node.id,
- image: data.image,
- name: data.employee_name,
- title: data.designation,
- expandable: data.expandable,
- connections: data.connections,
- children: undefined
- });
- }
-
- add_connector(parent_id, child_id) {
- let parent_node = document.querySelector(`#${parent_id}`);
- let child_node = document.querySelector(`#${child_id}`);
-
- // variable for the namespace
- const svgns = 'http://www.w3.org/2000/svg';
- let path = document.createElementNS(svgns, 'path');
-
- let connector = undefined;
-
- if ($(`#${parent_id}`).hasClass('active')) {
- connector = this.get_connector_for_active_node(parent_node, child_node);
- } else if ($(`#${parent_id}`).hasClass('active-path')) {
- connector = this.get_connector_for_collapsed_node(parent_node, child_node);
- }
-
- path.setAttribute("d", connector);
- this.set_path_attributes(path, parent_id, child_id);
-
- $('#connectors').append(path);
- }
-
- get_connector_for_active_node(parent_node, child_node) {
- // we need to connect the bottom left of the parent to the left side of the child node
- let pos_parent_bottom = {
- x: parent_node.offsetLeft + 20,
- y: parent_node.offsetTop + parent_node.offsetHeight
- };
- let pos_child_left = {
- x: child_node.offsetLeft - 5,
- y: child_node.offsetTop + child_node.offsetHeight / 2
- };
-
- let connector =
- "M" +
- (pos_parent_bottom.x) + "," + (pos_parent_bottom.y) + " " +
- "L" +
- (pos_parent_bottom.x) + "," + (pos_child_left.y) + " " +
- "L" +
- (pos_child_left.x) + "," + (pos_child_left.y);
-
- return connector;
- }
-
- get_connector_for_collapsed_node(parent_node, child_node) {
- // we need to connect the bottom left of the parent to the top left of the child node
- let pos_parent_bottom = {
- x: parent_node.offsetLeft + 20,
- y: parent_node.offsetTop + parent_node.offsetHeight
- };
- let pos_child_top = {
- x: child_node.offsetLeft + 20,
- y: child_node.offsetTop
- };
-
- let connector =
- "M" +
- (pos_parent_bottom.x) + "," + (pos_parent_bottom.y) + " " +
- "L" +
- (pos_child_top.x) + "," + (pos_child_top.y);
-
- return connector;
- }
-
- set_path_attributes(path, parent_id, child_id) {
- path.setAttribute("data-parent", parent_id);
- path.setAttribute("data-child", child_id);
-
- if ($(`#${parent_id}`).hasClass('active')) {
- path.setAttribute("class", "active-connector");
- path.setAttribute("marker-start", "url(#arrowstart-active)");
- path.setAttribute("marker-end", "url(#arrowhead-active)");
- } else if ($(`#${parent_id}`).hasClass('active-path')) {
- path.setAttribute("class", "collapsed-connector");
- }
- }
-
- set_selected_node(node) {
- // remove .active class from the current node
- $('.active').removeClass('active');
-
- // add active class to the newly selected node
- this.selected_node = node;
- node.$link.addClass('active');
- }
-
- setup_node_click_action(node) {
- let me = this;
- let node_element = $(`#${node.id}`);
-
- node_element.click(function() {
- if (node_element.is(':visible') && node_element.hasClass('active-path')) {
- me.remove_levels_after_node(node);
- me.remove_orphaned_connectors();
+ $(wrapper).bind('show', () => {
+ frappe.require('/assets/js/hierarchy-chart.min.js', () => {
+ let organizational_chart = undefined;
+ if (frappe.is_mobile()) {
+ organizational_chart = new erpnext.HierarchyChartMobile(wrapper);
} else {
- me.add_node_to_hierarchy(node, true);
- me.collapse_node();
+ organizational_chart = new erpnext.HierarchyChart(wrapper);
}
-
- me.expand_node(node);
+ organizational_chart.show();
});
- }
-
- setup_node_group_action() {
- let me = this;
-
- $('.node-group').on('click', function() {
- let parent = $(this).attr('data-parent');
- me.expand_sibling_group_node(parent);
- });
- }
-
- add_node_to_hierarchy(node) {
- this.$hierarchy.append(`
-
-
-
-
- `);
-
- node.$link.appendTo(this.$hierarchy.find('.level:last'));
- }
-
- get_node_group(nodes, parent, collapsed=true) {
- let limit = 2;
- const display_nodes = nodes.slice(0, limit);
- const extra_nodes = nodes.slice(limit);
-
- let html = display_nodes.map(node =>
- this.get_avatar(node)
- ).join('');
-
- if (extra_nodes.length === 1) {
- let node = extra_nodes[0];
- html += this.get_avatar(node);
- } else if (extra_nodes.length > 1) {
- html = `
- ${html}
-
-
- +${extra_nodes.length}
-
-
- `;
- }
-
- if (html) {
- const $node_group =
- $(``);
-
- if (collapsed)
- $node_group.addClass('collapsed');
-
- return $node_group;
- }
-
- return null;
- }
-
- get_avatar(node) {
- return `
-
- `
- }
-
- expand_sibling_group_node(parent) {
- let node_object = this.nodes[parent];
- let node = node_object.$link;
- node.removeClass('active-child active-path');
- node_object.expanded = 0;
- node_object.$children = undefined;
-
- // show parent's siblings and expand parent node
- frappe.run_serially([
- () => this.get_child_nodes(node_object.parent_id, node_object.id),
- (child_nodes) => this.get_node_group(child_nodes, node_object.parent_id, false),
- (node_group) => {
- if (node_group)
- this.$sibling_group.empty().append(node_group);
- },
- () => this.setup_node_group_action(),
- () => {
- this.$hierarchy.empty().append(`
-
- `);
- this.$hierarchy.find('.level').append(node);
- $(`#connectors`).empty();
- this.expand_node(node_object);
- }
- ]);
- }
-
- remove_levels_after_node(node) {
- let level = $(`#${node.id}`).parent().parent();
-
- level = $('.hierarchy-mobile > li:eq('+ (level.index()) + ')');
- level.nextAll('li').remove();
-
- let current_node = level.find(`#${node.id}`);
- let node_object = this.nodes[node.id];
-
- current_node.removeClass('active-child active-path');
- node_object.expanded = 0;
- node_object.$children = undefined;
-
- level.empty().append(current_node);
- }
-
- remove_orphaned_connectors() {
- let paths = $('#connectors > path');
- $.each(paths, (_i, path) => {
- let parent = $(path).data('parent');
- let child = $(path).data('child');
-
- if ($(parent).length || $(child).length)
- return;
-
- $(path).remove();
- })
- }
-
- refresh_connectors(node_parent, node_id) {
- if (!node_parent) return;
-
- $(`path[data-parent="${node_parent}"]`).remove();
- this.add_connector(node_parent, node_id);
- }
-}
\ No newline at end of file
+ });
+};
\ No newline at end of file
diff --git a/erpnext/public/build.json b/erpnext/public/build.json
index d3ebcdf7e7..3c60e3ee50 100644
--- a/erpnext/public/build.json
+++ b/erpnext/public/build.json
@@ -4,7 +4,7 @@
"public/less/hub.less",
"public/scss/call_popup.scss",
"public/scss/point-of-sale.scss",
- "public/scss/organizational_chart.scss"
+ "public/scss/hierarchy_chart.scss"
],
"css/marketplace.css": [
"public/less/hub.less"
@@ -44,7 +44,8 @@
"public/js/call_popup/call_popup.js",
"public/js/utils/dimension_tree_filter.js",
"public/js/telephony.js",
- "public/js/templates/call_link.html"
+ "public/js/templates/call_link.html",
+ "public/js/templates/node_card.html"
],
"js/item-dashboard.min.js": [
"stock/dashboard/item_dashboard.html",
@@ -67,5 +68,9 @@
"public/js/bank_reconciliation_tool/data_table_manager.js",
"public/js/bank_reconciliation_tool/number_card.js",
"public/js/bank_reconciliation_tool/dialog_manager.js"
+ ],
+ "js/hierarchy-chart.min.js": [
+ "public/js/hierarchy_chart/hierarchy_chart_desktop.js",
+ "public/js/hierarchy_chart/hierarchy_chart_mobile.js"
]
}
diff --git a/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js b/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
new file mode 100644
index 0000000000..fd84d4ea5c
--- /dev/null
+++ b/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
@@ -0,0 +1,396 @@
+erpnext.HierarchyChart = class {
+
+ constructor(wrapper) {
+ this.wrapper = $(wrapper);
+ this.page = wrapper.page;
+
+ this.page.main.css({
+ 'min-height': '300px',
+ 'max-height': '600px',
+ 'overflow': 'auto',
+ 'position': 'relative'
+ });
+ this.page.main.addClass('frappe-card');
+
+ this.nodes = {};
+ this.setup_node_class();
+ }
+
+ setup_node_class() {
+ let me = this;
+ this.Node = class {
+ constructor({
+ id, parent, parent_id, image, name, title, expandable, connections, is_root // eslint-disable-line
+ }) {
+ // to setup values passed via constructor
+ $.extend(this, arguments[0]);
+
+ this.expanded = 0;
+
+ me.nodes[this.id] = this;
+ me.make_node_element(this);
+ me.setup_node_click_action(this);
+ }
+ }
+ }
+
+ make_node_element(node) {
+ let node_card = frappe.render_template('node_card', {
+ id: node.id,
+ name: node.name,
+ title: node.title,
+ image: node.image,
+ parent: node.parent_id,
+ connections: node.connections
+ });
+
+ node.parent.append(node_card);
+ node.$link = $(`#${node.id}`);
+ }
+
+ show() {
+ frappe.breadcrumbs.add('HR');
+
+ let me = this;
+ let company = this.page.add_field({
+ fieldtype: 'Link',
+ options: 'Company',
+ fieldname: 'company',
+ placeholder: __('Select Company'),
+ default: frappe.defaults.get_default('company'),
+ only_select: true,
+ reqd: 1,
+ change: () => {
+ me.company = undefined;
+
+ if (company.get_value() && me.company != company.get_value()) {
+ me.company = company.get_value();
+
+ // svg for connectors
+ me.make_svg_markers()
+
+ if (me.$hierarchy)
+ me.$hierarchy.remove();
+
+ // setup hierarchy
+ me.$hierarchy = $(
+ ``);
+
+ me.page.main.append(me.$hierarchy);
+ me.render_root_node();
+ }
+ }
+ });
+
+ company.refresh();
+ $(`[data-fieldname="company"]`).trigger('change');
+ }
+
+ make_svg_markers() {
+ $('#arrows').remove();
+
+ this.page.main.prepend(`
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `);
+ }
+
+ render_root_node() {
+ this.method = 'erpnext.hr.page.organizational_chart.organizational_chart.get_children';
+
+ let me = this;
+
+ frappe.call({
+ method: me.method,
+ args: {
+ company: me.company
+ },
+ callback: function(r) {
+ if (r.message.length) {
+ let data = r.message[0];
+
+ let root_node = new me.Node({
+ id: data.name,
+ parent: me.$hierarchy.find('.root-level'),
+ parent_id: undefined,
+ image: data.image,
+ name: data.employee_name,
+ title: data.designation,
+ expandable: true,
+ connections: data.connections,
+ is_root: true,
+ });
+
+ me.expand_node(root_node);
+ }
+ }
+ })
+ }
+
+ expand_node(node) {
+ let is_sibling = this.selected_node && this.selected_node.parent_id === node.parent_id;
+ this.set_selected_node(node);
+ this.show_active_path(node);
+ this.collapse_previous_level_nodes(node);
+
+ // since the previous node collapses, all connections to that node need to be rebuilt
+ // if a sibling node is clicked, connections don't need to be rebuilt
+ if (!is_sibling) {
+ // rebuild outgoing connections
+ this.refresh_connectors(node.parent_id);
+
+ // rebuild incoming connections
+ let grandparent = $(`#${node.parent_id}`).attr('data-parent');
+ this.refresh_connectors(grandparent)
+ }
+
+ if (node.expandable && !node.expanded) {
+ return this.load_children(node);
+ }
+ }
+
+ collapse_node() {
+ if (this.selected_node.expandable) {
+ this.selected_node.$children.hide();
+ $(`path[data-parent="${this.selected_node.id}"]`).hide();
+ this.selected_node.expanded = false;
+ }
+ }
+
+ show_active_path(node) {
+ // mark node parent on active path
+ $(`#${node.parent_id}`).addClass('active-path');
+ }
+
+ load_children(node) {
+ frappe.run_serially([
+ () => this.get_child_nodes(node.id),
+ (child_nodes) => this.render_child_nodes(node, child_nodes)
+ ]);
+ }
+
+ get_child_nodes(node_id) {
+ let me = this;
+ return new Promise(resolve => {
+ frappe.call({
+ method: this.method,
+ args: {
+ parent: node_id,
+ company: me.company
+ },
+ callback: (r) => {
+ resolve(r.message);
+ }
+ });
+ });
+ }
+
+ render_child_nodes(node, child_nodes) {
+ const last_level = this.$hierarchy.find('.level:last').index();
+ const current_level = $(`#${node.id}`).parent().parent().parent().index();
+
+ if (last_level === current_level) {
+ this.$hierarchy.append(`
+
+ `);
+ }
+
+ if (!node.$children) {
+ node.$children = $('')
+ .hide()
+ .appendTo(this.$hierarchy.find('.level:last'));
+
+ node.$children.empty();
+
+ if (child_nodes) {
+ $.each(child_nodes, (_i, data) => {
+ this.add_node(node, data);
+
+ setTimeout(() => {
+ this.add_connector(node.id, data.name);
+ }, 250);
+ });
+ }
+ }
+
+ node.$children.show();
+ $(`path[data-parent="${node.id}"]`).show();
+ node.expanded = true;
+ }
+
+ add_node(node, data) {
+ var $li = $(' ');
+
+ return new this.Node({
+ id: data.name,
+ parent: $li.appendTo(node.$children),
+ parent_id: node.id,
+ image: data.image,
+ name: data.employee_name,
+ title: data.designation,
+ expandable: data.expandable,
+ connections: data.connections,
+ children: undefined
+ });
+ }
+
+ add_connector(parent_id, child_id) {
+ let parent_node = document.querySelector(`#${parent_id}`);
+ let child_node = document.querySelector(`#${child_id}`);
+
+ // variable for the namespace
+ const svgns = 'http://www.w3.org/2000/svg';
+ let path = document.createElementNS(svgns, 'path');
+
+ // we need to connect right side of the parent to the left side of the child node
+ let pos_parent_right = {
+ x: parent_node.offsetLeft + parent_node.offsetWidth,
+ y: parent_node.offsetTop + parent_node.offsetHeight / 2
+ };
+ let pos_child_left = {
+ x: child_node.offsetLeft - 5,
+ y: child_node.offsetTop + child_node.offsetHeight / 2
+ };
+
+ let connector =
+ "M" +
+ (pos_parent_right.x) + "," + (pos_parent_right.y) + " " +
+ "C" +
+ (pos_parent_right.x + 100) + "," + (pos_parent_right.y) + " " +
+ (pos_child_left.x - 100) + "," + (pos_child_left.y) + " " +
+ (pos_child_left.x) + "," + (pos_child_left.y);
+
+ path.setAttribute("d", connector);
+ path.setAttribute("data-parent", parent_id);
+ path.setAttribute("data-child", child_id);
+
+ if ($(`#${parent_id}`).hasClass('active')) {
+ path.setAttribute("class", "active-connector");
+ path.setAttribute("marker-start", "url(#arrowstart-active)");
+ path.setAttribute("marker-end", "url(#arrowhead-active)");
+ } else if ($(`#${parent_id}`).hasClass('active-path')) {
+ path.setAttribute("class", "collapsed-connector");
+ path.setAttribute("marker-start", "url(#arrowstart-collapsed)");
+ path.setAttribute("marker-end", "url(#arrowhead-collapsed)");
+ }
+
+ $('#connectors').append(path);
+ }
+
+ set_selected_node(node) {
+ // remove .active class from the current node
+ $('.active').removeClass('active');
+
+ // add active class to the newly selected node
+ this.selected_node = node;
+ node.$link.addClass('active');
+ }
+
+ collapse_previous_level_nodes(node) {
+ let node_parent = $(`#${node.parent_id}`);
+
+ let previous_level_nodes = node_parent.parent().parent().children('li');
+ if (node_parent.parent().hasClass('root-level')) {
+ previous_level_nodes = node_parent.parent().children('li');
+ }
+
+ let node_card = undefined;
+
+ previous_level_nodes.each(function() {
+ node_card = $(this).find('.node-card');
+
+ if (!node_card.hasClass('active-path')) {
+ node_card.addClass('collapsed');
+ }
+ });
+ }
+
+ refresh_connectors(node_parent) {
+ if (!node_parent) return;
+
+ $(`path[data-parent="${node_parent}"]`).remove();
+
+ frappe.run_serially([
+ () => this.get_child_nodes(node_parent),
+ (child_nodes) => {
+ if (child_nodes) {
+ $.each(child_nodes, (_i, data) => {
+ this.add_connector(node_parent, data.name);
+ });
+ }
+ }
+ ]);
+ }
+
+ setup_node_click_action(node) {
+ let me = this;
+ let node_element = $(`#${node.id}`);
+
+ node_element.click(function() {
+ let is_sibling = me.selected_node.parent_id === node.parent_id;
+
+ if (is_sibling) {
+ me.collapse_node();
+ } else if (node_element.is(':visible')
+ && (node_element.hasClass('collapsed') || node_element.hasClass('active-path'))) {
+ me.remove_levels_after_node(node);
+ me.remove_orphaned_connectors();
+ }
+
+ me.expand_node(node);
+ });
+ }
+
+ remove_levels_after_node(node) {
+ let level = $(`#${node.id}`).parent().parent().parent();
+
+ if ($(`#${node.id}`).parent().hasClass('root-level')) {
+ level = $(`#${node.id}`).parent();
+ }
+
+ level = $('.hierarchy > li:eq('+ level.index() + ')');
+ level.nextAll('li').remove();
+
+ let nodes = level.find('.node-card');
+ let node_object = undefined;
+
+ $.each(nodes, (_i, element) => {
+ node_object = this.nodes[element.id];
+ node_object.expanded = 0;
+ node_object.$children = undefined;
+ });
+
+ nodes.removeClass('collapsed active-path');
+ }
+
+ remove_orphaned_connectors() {
+ let paths = $('#connectors > path');
+ $.each(paths, (_i, path) => {
+ let parent = $(path).data('parent');
+ let child = $(path).data('child');
+
+ if ($(parent).length || $(child).length)
+ return;
+
+ $(path).remove();
+ })
+ }
+}
\ No newline at end of file
diff --git a/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js b/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
new file mode 100644
index 0000000000..c705681438
--- /dev/null
+++ b/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
@@ -0,0 +1,513 @@
+erpnext.HierarchyChartMobile = class {
+
+ constructor(wrapper) {
+ this.wrapper = $(wrapper);
+ this.page = wrapper.page;
+
+ this.page.main.css({
+ 'min-height': '300px',
+ 'max-height': '600px',
+ 'overflow': 'auto',
+ 'position': 'relative'
+ });
+ this.page.main.addClass('frappe-card');
+
+ this.nodes = {};
+ this.setup_node_class();
+ }
+
+ setup_node_class() {
+ let me = this;
+ this.Node = class {
+ constructor({
+ id, parent, parent_id, image, name, title, expandable, connections, is_root // eslint-disable-line
+ }) {
+ // to setup values passed via constructor
+ $.extend(this, arguments[0]);
+
+ this.expanded = 0;
+
+ me.nodes[this.id] = this;
+ me.make_node_element(this);
+ me.setup_node_click_action(this);
+ }
+ }
+ }
+
+ make_node_element(node) {
+ let node_card = frappe.render_template('node_card', {
+ id: node.id,
+ name: node.name,
+ title: node.title,
+ image: node.image,
+ parent: node.parent_id,
+ connections: node.connections,
+ is_mobile: 1
+ });
+
+ node.parent.append(node_card);
+ node.$link = $(`#${node.id}`);
+ node.$link.addClass('mobile-node');
+ }
+
+ show() {
+ frappe.breadcrumbs.add('HR');
+
+ let me = this;
+ let company = this.page.add_field({
+ fieldtype: 'Link',
+ options: 'Company',
+ fieldname: 'company',
+ placeholder: __('Select Company'),
+ default: frappe.defaults.get_default('company'),
+ only_select: true,
+ reqd: 1,
+ change: () => {
+ me.company = undefined;
+
+ if (company.get_value() && me.company != company.get_value()) {
+ me.company = company.get_value();
+
+ // svg for connectors
+ me.make_svg_markers()
+
+ if (me.$sibling_group)
+ me.$sibling_group.remove();
+
+ // setup sibling group wrapper
+ me.$sibling_group = $(`
`);
+ me.page.main.append(me.$sibling_group);
+
+ if (me.$hierarchy)
+ me.$hierarchy.remove();
+
+ // setup hierarchy
+ me.$hierarchy = $(
+ ``);
+
+ me.page.main.append(me.$hierarchy);
+ me.render_root_node();
+ }
+ }
+ });
+
+ company.refresh();
+ $(`[data-fieldname="company"]`).trigger('change');
+ }
+
+ make_svg_markers() {
+ $('#arrows').remove();
+
+ this.page.main.prepend(`
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `);
+ }
+
+ render_root_node() {
+ this.method = 'erpnext.hr.page.organizational_chart.organizational_chart.get_children';
+
+ let me = this;
+
+ frappe.call({
+ method: me.method,
+ args: {
+ company: me.company
+ },
+ callback: function(r) {
+ if (r.message.length) {
+ let data = r.message[0];
+
+ let root_node = new me.Node({
+ id: data.name,
+ parent: me.$hierarchy.find('.root-level'),
+ parent_id: undefined,
+ image: data.image,
+ name: data.employee_name,
+ title: data.designation,
+ expandable: true,
+ connections: data.connections,
+ is_root: true,
+ });
+
+ me.expand_node(root_node);
+ }
+ }
+ })
+ }
+
+ expand_node(node) {
+ const is_same_node = (this.selected_node && this.selected_node.id === node.id);
+ this.set_selected_node(node);
+ this.show_active_path(node);
+
+ if (this.$sibling_group) {
+ const sibling_parent = this.$sibling_group.find('.node-group').attr('data-parent');
+ if (node.parent_id !== sibling_parent)
+ this.$sibling_group.empty();
+ }
+
+ if (!is_same_node) {
+ // since the previous/parent node collapses, all connections to that node need to be rebuilt
+ // rebuild outgoing connections of parent
+ this.refresh_connectors(node.parent_id, node.id);
+
+ // rebuild incoming connections of parent
+ let grandparent = $(`#${node.parent_id}`).attr('data-parent');
+ this.refresh_connectors(grandparent, node.parent_id);
+ }
+
+ if (node.expandable && !node.expanded) {
+ return this.load_children(node);
+ }
+ }
+
+ collapse_node() {
+ let node = this.selected_node;
+ if (node.expandable) {
+ node.$children.hide();
+ node.expanded = false;
+
+ // add a collapsed level to show the collapsed parent
+ // and a button beside it to move to that level
+ let node_parent = node.$link.parent();
+ node_parent.prepend(
+ `
`
+ );
+
+ node_parent
+ .find('.collapsed-level')
+ .append(node.$link);
+
+ frappe.run_serially([
+ () => this.get_child_nodes(node.parent_id, node.id),
+ (child_nodes) => this.get_node_group(child_nodes, node.parent_id),
+ (node_group) => {
+ node_parent.find('.collapsed-level')
+ .append(node_group);
+ },
+ () => this.setup_node_group_action()
+ ]);
+ }
+ }
+
+ show_active_path(node) {
+ // mark node parent on active path
+ $(`#${node.parent_id}`).addClass('active-path');
+ }
+
+ load_children(node) {
+ frappe.run_serially([
+ () => this.get_child_nodes(node.id),
+ (child_nodes) => this.render_child_nodes(node, child_nodes)
+ ]);
+ }
+
+ get_child_nodes(node_id, exclude_node=null) {
+ let me = this;
+ return new Promise(resolve => {
+ frappe.call({
+ method: this.method,
+ args: {
+ parent: node_id,
+ company: me.company,
+ exclude_node: exclude_node
+ },
+ callback: (r) => {
+ resolve(r.message);
+ }
+ });
+ });
+ }
+
+ render_child_nodes(node, child_nodes) {
+ if (!node.$children) {
+ node.$children = $('')
+ .hide()
+ .appendTo(node.$link.parent());
+
+ node.$children.empty();
+
+ if (child_nodes) {
+ $.each(child_nodes, (_i, data) => {
+ this.add_node(node, data);
+ $(`#${data.name}`).addClass('active-child');
+
+ setTimeout(() => {
+ this.add_connector(node.id, data.name);
+ }, 250);
+ });
+ }
+ }
+
+ node.$children.show();
+ node.expanded = true;
+ }
+
+ add_node(node, data) {
+ var $li = $(' ');
+
+ return new this.Node({
+ id: data.name,
+ parent: $li.appendTo(node.$children),
+ parent_id: node.id,
+ image: data.image,
+ name: data.employee_name,
+ title: data.designation,
+ expandable: data.expandable,
+ connections: data.connections,
+ children: undefined
+ });
+ }
+
+ add_connector(parent_id, child_id) {
+ let parent_node = document.querySelector(`#${parent_id}`);
+ let child_node = document.querySelector(`#${child_id}`);
+
+ // variable for the namespace
+ const svgns = 'http://www.w3.org/2000/svg';
+ let path = document.createElementNS(svgns, 'path');
+
+ let connector = undefined;
+
+ if ($(`#${parent_id}`).hasClass('active')) {
+ connector = this.get_connector_for_active_node(parent_node, child_node);
+ } else if ($(`#${parent_id}`).hasClass('active-path')) {
+ connector = this.get_connector_for_collapsed_node(parent_node, child_node);
+ }
+
+ path.setAttribute("d", connector);
+ this.set_path_attributes(path, parent_id, child_id);
+
+ $('#connectors').append(path);
+ }
+
+ get_connector_for_active_node(parent_node, child_node) {
+ // we need to connect the bottom left of the parent to the left side of the child node
+ let pos_parent_bottom = {
+ x: parent_node.offsetLeft + 20,
+ y: parent_node.offsetTop + parent_node.offsetHeight
+ };
+ let pos_child_left = {
+ x: child_node.offsetLeft - 5,
+ y: child_node.offsetTop + child_node.offsetHeight / 2
+ };
+
+ let connector =
+ "M" +
+ (pos_parent_bottom.x) + "," + (pos_parent_bottom.y) + " " +
+ "L" +
+ (pos_parent_bottom.x) + "," + (pos_child_left.y) + " " +
+ "L" +
+ (pos_child_left.x) + "," + (pos_child_left.y);
+
+ return connector;
+ }
+
+ get_connector_for_collapsed_node(parent_node, child_node) {
+ // we need to connect the bottom left of the parent to the top left of the child node
+ let pos_parent_bottom = {
+ x: parent_node.offsetLeft + 20,
+ y: parent_node.offsetTop + parent_node.offsetHeight
+ };
+ let pos_child_top = {
+ x: child_node.offsetLeft + 20,
+ y: child_node.offsetTop
+ };
+
+ let connector =
+ "M" +
+ (pos_parent_bottom.x) + "," + (pos_parent_bottom.y) + " " +
+ "L" +
+ (pos_child_top.x) + "," + (pos_child_top.y);
+
+ return connector;
+ }
+
+ set_path_attributes(path, parent_id, child_id) {
+ path.setAttribute("data-parent", parent_id);
+ path.setAttribute("data-child", child_id);
+
+ if ($(`#${parent_id}`).hasClass('active')) {
+ path.setAttribute("class", "active-connector");
+ path.setAttribute("marker-start", "url(#arrowstart-active)");
+ path.setAttribute("marker-end", "url(#arrowhead-active)");
+ } else if ($(`#${parent_id}`).hasClass('active-path')) {
+ path.setAttribute("class", "collapsed-connector");
+ }
+ }
+
+ set_selected_node(node) {
+ // remove .active class from the current node
+ $('.active').removeClass('active');
+
+ // add active class to the newly selected node
+ this.selected_node = node;
+ node.$link.addClass('active');
+ }
+
+ setup_node_click_action(node) {
+ let me = this;
+ let node_element = $(`#${node.id}`);
+
+ node_element.click(function() {
+ if (node_element.is(':visible') && node_element.hasClass('active-path')) {
+ me.remove_levels_after_node(node);
+ me.remove_orphaned_connectors();
+ } else {
+ me.add_node_to_hierarchy(node, true);
+ me.collapse_node();
+ }
+
+ me.expand_node(node);
+ });
+ }
+
+ setup_node_group_action() {
+ let me = this;
+
+ $('.node-group').on('click', function() {
+ let parent = $(this).attr('data-parent');
+ me.expand_sibling_group_node(parent);
+ });
+ }
+
+ add_node_to_hierarchy(node) {
+ this.$hierarchy.append(`
+
+
+
+
+ `);
+
+ node.$link.appendTo(this.$hierarchy.find('.level:last'));
+ }
+
+ get_node_group(nodes, parent, collapsed=true) {
+ let limit = 2;
+ const display_nodes = nodes.slice(0, limit);
+ const extra_nodes = nodes.slice(limit);
+
+ let html = display_nodes.map(node =>
+ this.get_avatar(node)
+ ).join('');
+
+ if (extra_nodes.length === 1) {
+ let node = extra_nodes[0];
+ html += this.get_avatar(node);
+ } else if (extra_nodes.length > 1) {
+ html = `
+ ${html}
+
+
+ +${extra_nodes.length}
+
+
+ `;
+ }
+
+ if (html) {
+ const $node_group =
+ $(``);
+
+ if (collapsed)
+ $node_group.addClass('collapsed');
+
+ return $node_group;
+ }
+
+ return null;
+ }
+
+ get_avatar(node) {
+ return `
+
+ `
+ }
+
+ expand_sibling_group_node(parent) {
+ let node_object = this.nodes[parent];
+ let node = node_object.$link;
+ node.removeClass('active-child active-path');
+ node_object.expanded = 0;
+ node_object.$children = undefined;
+
+ // show parent's siblings and expand parent node
+ frappe.run_serially([
+ () => this.get_child_nodes(node_object.parent_id, node_object.id),
+ (child_nodes) => this.get_node_group(child_nodes, node_object.parent_id, false),
+ (node_group) => {
+ if (node_group)
+ this.$sibling_group.empty().append(node_group);
+ },
+ () => this.setup_node_group_action(),
+ () => {
+ this.$hierarchy.empty().append(`
+
+ `);
+ this.$hierarchy.find('.level').append(node);
+ $(`#connectors`).empty();
+ this.expand_node(node_object);
+ }
+ ]);
+ }
+
+ remove_levels_after_node(node) {
+ let level = $(`#${node.id}`).parent().parent();
+
+ level = $('.hierarchy-mobile > li:eq('+ (level.index()) + ')');
+ level.nextAll('li').remove();
+
+ let current_node = level.find(`#${node.id}`);
+ let node_object = this.nodes[node.id];
+
+ current_node.removeClass('active-child active-path');
+ node_object.expanded = 0;
+ node_object.$children = undefined;
+
+ level.empty().append(current_node);
+ }
+
+ remove_orphaned_connectors() {
+ let paths = $('#connectors > path');
+ $.each(paths, (_i, path) => {
+ let parent = $(path).data('parent');
+ let child = $(path).data('child');
+
+ if ($(parent).length || $(child).length)
+ return;
+
+ $(path).remove();
+ })
+ }
+
+ refresh_connectors(node_parent, node_id) {
+ if (!node_parent) return;
+
+ $(`path[data-parent="${node_parent}"]`).remove();
+ this.add_connector(node_parent, node_id);
+ }
+}
\ No newline at end of file
diff --git a/erpnext/hr/page/organizational_chart/node_card.html b/erpnext/public/js/templates/node_card.html
similarity index 100%
rename from erpnext/hr/page/organizational_chart/node_card.html
rename to erpnext/public/js/templates/node_card.html
diff --git a/erpnext/public/scss/organizational_chart.scss b/erpnext/public/scss/hierarchy_chart.scss
similarity index 100%
rename from erpnext/public/scss/organizational_chart.scss
rename to erpnext/public/scss/hierarchy_chart.scss
From f15e8b7f5a50cc686e3139b4aee63726a01f6413 Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Tue, 29 Jun 2021 21:26:47 +0530
Subject: [PATCH 011/386] refactor: add options to chart
- method to return the node data
- wrapper for showing the hierarchy
---
.../organizational_chart.js | 6 ++--
.../organizational_chart.py | 6 ++--
.../hierarchy_chart_desktop.js | 28 +++++++++-------
.../hierarchy_chart/hierarchy_chart_mobile.js | 32 +++++++++++--------
4 files changed, 41 insertions(+), 31 deletions(-)
diff --git a/erpnext/hr/page/organizational_chart/organizational_chart.js b/erpnext/hr/page/organizational_chart/organizational_chart.js
index 0fe724c78e..ca9855286c 100644
--- a/erpnext/hr/page/organizational_chart/organizational_chart.js
+++ b/erpnext/hr/page/organizational_chart/organizational_chart.js
@@ -8,10 +8,12 @@ frappe.pages['organizational-chart'].on_page_load = function(wrapper) {
$(wrapper).bind('show', () => {
frappe.require('/assets/js/hierarchy-chart.min.js', () => {
let organizational_chart = undefined;
+ let method = 'erpnext.hr.page.organizational_chart.organizational_chart.get_children';
+
if (frappe.is_mobile()) {
- organizational_chart = new erpnext.HierarchyChartMobile(wrapper);
+ organizational_chart = new erpnext.HierarchyChartMobile(wrapper, method);
} else {
- organizational_chart = new erpnext.HierarchyChart(wrapper);
+ organizational_chart = new erpnext.HierarchyChart(wrapper, method);
}
organizational_chart.show();
});
diff --git a/erpnext/hr/page/organizational_chart/organizational_chart.py b/erpnext/hr/page/organizational_chart/organizational_chart.py
index ae91a919b2..f3aa13897d 100644
--- a/erpnext/hr/page/organizational_chart/organizational_chart.py
+++ b/erpnext/hr/page/organizational_chart/organizational_chart.py
@@ -9,7 +9,7 @@ def get_children(parent=None, company=None, exclude_node=None, is_root=False, is
filters.append(['company', '=', company])
if not fields:
- fields = ['employee_name', 'name', 'reports_to', 'image', 'designation']
+ fields = ['employee_name as name', 'name as id', 'reports_to', 'image', 'designation as title']
if is_root:
parent = ''
@@ -27,9 +27,9 @@ def get_children(parent=None, company=None, exclude_node=None, is_root=False, is
for employee in employees:
is_expandable = frappe.get_all('Employee', filters=[
- ['reports_to', '=', employee.get('name')]
+ ['reports_to', '=', employee.get('id')]
])
- employee.connections = get_connections(employee.name)
+ employee.connections = get_connections(employee.id)
employee.expandable = 1 if is_expandable else 0
return employees
diff --git a/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js b/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
index fd84d4ea5c..052f140c13 100644
--- a/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
+++ b/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
@@ -1,8 +1,14 @@
erpnext.HierarchyChart = class {
-
- constructor(wrapper) {
+ /* Options:
+ - wrapper: wrapper for the hierarchy view
+ - method:
+ - to get the data for each node
+ - this method should return id, name, title, image, and connections for each node
+ */
+ constructor(wrapper, method) {
this.wrapper = $(wrapper);
this.page = wrapper.page;
+ this.method = method;
this.page.main.css({
'min-height': '300px',
@@ -114,8 +120,6 @@ erpnext.HierarchyChart = class {
}
render_root_node() {
- this.method = 'erpnext.hr.page.organizational_chart.organizational_chart.get_children';
-
let me = this;
frappe.call({
@@ -128,12 +132,12 @@ erpnext.HierarchyChart = class {
let data = r.message[0];
let root_node = new me.Node({
- id: data.name,
+ id: data.id,
parent: me.$hierarchy.find('.root-level'),
parent_id: undefined,
image: data.image,
- name: data.employee_name,
- title: data.designation,
+ name: data.name,
+ title: data.title,
expandable: true,
connections: data.connections,
is_root: true,
@@ -225,7 +229,7 @@ erpnext.HierarchyChart = class {
this.add_node(node, data);
setTimeout(() => {
- this.add_connector(node.id, data.name);
+ this.add_connector(node.id, data.id);
}, 250);
});
}
@@ -240,12 +244,12 @@ erpnext.HierarchyChart = class {
var $li = $(' ');
return new this.Node({
- id: data.name,
+ id: data.id,
parent: $li.appendTo(node.$children),
parent_id: node.id,
image: data.image,
- name: data.employee_name,
- title: data.designation,
+ name: data.name,
+ title: data.title,
expandable: data.expandable,
connections: data.connections,
children: undefined
@@ -333,7 +337,7 @@ erpnext.HierarchyChart = class {
(child_nodes) => {
if (child_nodes) {
$.each(child_nodes, (_i, data) => {
- this.add_connector(node_parent, data.name);
+ this.add_connector(node_parent, data.id);
});
}
}
diff --git a/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js b/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
index c705681438..1b8bc2e8e0 100644
--- a/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
+++ b/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
@@ -1,8 +1,14 @@
erpnext.HierarchyChartMobile = class {
-
- constructor(wrapper) {
+ /* Options:
+ - wrapper: wrapper for the hierarchy view
+ - method:
+ - to get the data for each node
+ - this method should return id, name, title, image, and connections for each node
+ */
+ constructor(wrapper, method) {
this.wrapper = $(wrapper);
this.page = wrapper.page;
+ this.method = method;
this.page.main.css({
'min-height': '300px',
@@ -123,8 +129,6 @@ erpnext.HierarchyChartMobile = class {
}
render_root_node() {
- this.method = 'erpnext.hr.page.organizational_chart.organizational_chart.get_children';
-
let me = this;
frappe.call({
@@ -137,12 +141,12 @@ erpnext.HierarchyChartMobile = class {
let data = r.message[0];
let root_node = new me.Node({
- id: data.name,
+ id: data.id,
parent: me.$hierarchy.find('.root-level'),
parent_id: undefined,
image: data.image,
- name: data.employee_name,
- title: data.designation,
+ name: data.name,
+ title: data.title,
expandable: true,
connections: data.connections,
is_root: true,
@@ -249,10 +253,10 @@ erpnext.HierarchyChartMobile = class {
if (child_nodes) {
$.each(child_nodes, (_i, data) => {
this.add_node(node, data);
- $(`#${data.name}`).addClass('active-child');
+ $(`#${data.id}`).addClass('active-child');
setTimeout(() => {
- this.add_connector(node.id, data.name);
+ this.add_connector(node.id, data.id);
}, 250);
});
}
@@ -266,12 +270,12 @@ erpnext.HierarchyChartMobile = class {
var $li = $(' ');
return new this.Node({
- id: data.name,
+ id: data.id,
parent: $li.appendTo(node.$children),
parent_id: node.id,
image: data.image,
- name: data.employee_name,
- title: data.designation,
+ name: data.name,
+ title: data.title,
expandable: data.expandable,
connections: data.connections,
children: undefined
@@ -418,7 +422,7 @@ erpnext.HierarchyChartMobile = class {
${html}
+ title="${extra_nodes.map(node => node.name).join(', ')}">
+${extra_nodes.length}
@@ -443,7 +447,7 @@ erpnext.HierarchyChartMobile = class {
}
get_avatar(node) {
- return `
+ return `
`
}
From c40b9d276e04cb521dd33601a84acb53100f40c0 Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Tue, 29 Jun 2021 21:51:21 +0530
Subject: [PATCH 012/386] feat: setup node edit action
---
.../organizational_chart/organizational_chart.js | 4 ++--
.../js/hierarchy_chart/hierarchy_chart_desktop.js | 14 +++++++++++++-
.../js/hierarchy_chart/hierarchy_chart_mobile.js | 14 +++++++++++++-
erpnext/public/js/templates/node_card.html | 4 ++--
4 files changed, 30 insertions(+), 6 deletions(-)
diff --git a/erpnext/hr/page/organizational_chart/organizational_chart.js b/erpnext/hr/page/organizational_chart/organizational_chart.js
index ca9855286c..a138886768 100644
--- a/erpnext/hr/page/organizational_chart/organizational_chart.js
+++ b/erpnext/hr/page/organizational_chart/organizational_chart.js
@@ -11,9 +11,9 @@ frappe.pages['organizational-chart'].on_page_load = function(wrapper) {
let method = 'erpnext.hr.page.organizational_chart.organizational_chart.get_children';
if (frappe.is_mobile()) {
- organizational_chart = new erpnext.HierarchyChartMobile(wrapper, method);
+ organizational_chart = new erpnext.HierarchyChartMobile('Employee', wrapper, method);
} else {
- organizational_chart = new erpnext.HierarchyChart(wrapper, method);
+ organizational_chart = new erpnext.HierarchyChart('Employee', wrapper, method);
}
organizational_chart.show();
});
diff --git a/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js b/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
index 052f140c13..0823ec77a8 100644
--- a/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
+++ b/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
@@ -1,14 +1,16 @@
erpnext.HierarchyChart = class {
/* Options:
+ - doctype
- wrapper: wrapper for the hierarchy view
- method:
- to get the data for each node
- this method should return id, name, title, image, and connections for each node
*/
- constructor(wrapper, method) {
+ constructor(doctype, wrapper, method) {
this.wrapper = $(wrapper);
this.page = wrapper.page;
this.method = method;
+ this.doctype = doctype;
this.page.main.css({
'min-height': '300px',
@@ -36,6 +38,7 @@ erpnext.HierarchyChart = class {
me.nodes[this.id] = this;
me.make_node_element(this);
me.setup_node_click_action(this);
+ me.setup_edit_node_action(this);
}
}
}
@@ -363,6 +366,15 @@ erpnext.HierarchyChart = class {
});
}
+ setup_edit_node_action(node) {
+ let node_element = $(`#${node.id}`);
+ let me = this;
+
+ node_element.find('.btn-edit-node').click(function() {
+ frappe.set_route('Form', me.doctype, node.id);
+ });
+ }
+
remove_levels_after_node(node) {
let level = $(`#${node.id}`).parent().parent().parent();
diff --git a/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js b/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
index 1b8bc2e8e0..4b09714d0a 100644
--- a/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
+++ b/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
@@ -1,14 +1,16 @@
erpnext.HierarchyChartMobile = class {
/* Options:
+ - doctype
- wrapper: wrapper for the hierarchy view
- method:
- to get the data for each node
- this method should return id, name, title, image, and connections for each node
*/
- constructor(wrapper, method) {
+ constructor(doctype, wrapper, method) {
this.wrapper = $(wrapper);
this.page = wrapper.page;
this.method = method;
+ this.doctype = doctype
this.page.main.css({
'min-height': '300px',
@@ -36,6 +38,7 @@ erpnext.HierarchyChartMobile = class {
me.nodes[this.id] = this;
me.make_node_element(this);
me.setup_node_click_action(this);
+ me.setup_edit_node_action(this);
}
}
}
@@ -385,6 +388,15 @@ erpnext.HierarchyChartMobile = class {
});
}
+ setup_edit_node_action(node) {
+ let node_element = $(`#${node.id}`);
+ let me = this;
+
+ node_element.find('.btn-edit-node').click(function() {
+ frappe.set_route('Form', me.doctype, node.id);
+ });
+ }
+
setup_node_group_action() {
let me = this;
diff --git a/erpnext/public/js/templates/node_card.html b/erpnext/public/js/templates/node_card.html
index e42e54f690..30aedab4bb 100644
--- a/erpnext/public/js/templates/node_card.html
+++ b/erpnext/public/js/templates/node_card.html
@@ -17,9 +17,9 @@
{{ title }}
{% if connections == 1 %}
- · {{ connections }}
+ · {{ connections }} Connection
{% else %}
- · {{ connections }}
+ · {{ connections }} Connections
{% endif %}
From 7558b28b794f09826bcf8f42385605dcdc819086 Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Tue, 29 Jun 2021 21:57:27 +0530
Subject: [PATCH 013/386] fix: revert changes in employee descendants query
---
erpnext/hr/doctype/employee/employee.py | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/erpnext/hr/doctype/employee/employee.py b/erpnext/hr/doctype/employee/employee.py
index 7917e3abf5..ed7d588434 100755
--- a/erpnext/hr/doctype/employee/employee.py
+++ b/erpnext/hr/doctype/employee/employee.py
@@ -476,14 +476,13 @@ def get_employee_emails(employee_list):
return employee_emails
@frappe.whitelist()
-def get_children(doctype, parent=None, company=None, is_root=False, is_tree=False, fields=None):
+def get_children(doctype, parent=None, company=None, is_root=False, is_tree=False):
filters = [['status', '!=', 'Left']]
if company and company != 'All Companies':
filters.append(['company', '=', company])
- if not fields:
- fields = ['name as value', 'employee_name as title']
+ fields = ['name as value', 'employee_name as title']
if is_root:
parent = ''
From a7507f7af63c259fd61164c39a5dbd5d6e3c2df1 Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Wed, 30 Jun 2021 01:46:10 +0530
Subject: [PATCH 014/386] refactor: use arcs instead of bezier curves for
cleaner connectors
---
.../hierarchy_chart_desktop.js | 54 +++++++++++++++----
erpnext/public/scss/hierarchy_chart.scss | 2 +-
2 files changed, 46 insertions(+), 10 deletions(-)
diff --git a/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js b/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
index 0823ec77a8..ba811be586 100644
--- a/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
+++ b/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
@@ -277,15 +277,53 @@ erpnext.HierarchyChart = class {
y: child_node.offsetTop + child_node.offsetHeight / 2
};
- let connector =
- "M" +
- (pos_parent_right.x) + "," + (pos_parent_right.y) + " " +
- "C" +
- (pos_parent_right.x + 100) + "," + (pos_parent_right.y) + " " +
- (pos_child_left.x - 100) + "," + (pos_child_left.y) + " " +
- (pos_child_left.x) + "," + (pos_child_left.y);
+ let connector = this.get_connector(pos_parent_right, pos_child_left);
path.setAttribute("d", connector);
+ this.set_path_attributes(path, parent_id, child_id);
+
+ $('#connectors').append(path);
+ }
+
+ get_connector(pos_parent_right, pos_child_left) {
+ if (pos_parent_right.y === pos_child_left.y) {
+ // don't add arcs if it's a straight line
+ return "M" +
+ (pos_parent_right.x) + "," + (pos_parent_right.y) + " " +
+ "L"+
+ (pos_child_left.x) + "," + (pos_child_left.y);
+ } else {
+ let arc_1 = "";
+ let arc_2 = "";
+ let offset = 0;
+
+ if (pos_parent_right.y > pos_child_left.y) {
+ // if child is above parent on Y axis 1st arc is anticlocwise
+ // second arc is clockwise
+ arc_1 = "a10,10 1 0 0 10,-10 ";
+ arc_2 = "a10,10 0 0 1 10,-10 ";
+ offset = 10;
+ } else {
+ // if child is below parent on Y axis 1st arc is clockwise
+ // second arc is anticlockwise
+ arc_1 = "a10,10 0 0 1 10,10 ";
+ arc_2 = "a10,10 1 0 0 10,10 ";
+ offset = -10;
+ }
+
+ return "M" + (pos_parent_right.x) + "," + (pos_parent_right.y) + " " +
+ "L" +
+ (pos_parent_right.x + 40) + "," + (pos_parent_right.y) + " " +
+ arc_1 +
+ "L" +
+ (pos_parent_right.x + 50) + "," + (pos_child_left.y + offset) + " " +
+ arc_2 +
+ "L"+
+ (pos_child_left.x) + "," + (pos_child_left.y);
+ }
+ }
+
+ set_path_attributes(path, parent_id, child_id) {
path.setAttribute("data-parent", parent_id);
path.setAttribute("data-child", child_id);
@@ -298,8 +336,6 @@ erpnext.HierarchyChart = class {
path.setAttribute("marker-start", "url(#arrowstart-collapsed)");
path.setAttribute("marker-end", "url(#arrowhead-collapsed)");
}
-
- $('#connectors').append(path);
}
set_selected_node(node) {
diff --git a/erpnext/public/scss/hierarchy_chart.scss b/erpnext/public/scss/hierarchy_chart.scss
index 16b8792432..16137fdb5f 100644
--- a/erpnext/public/scss/hierarchy_chart.scss
+++ b/erpnext/public/scss/hierarchy_chart.scss
@@ -48,7 +48,6 @@
border-radius: 0.5rem;
padding: 0.75rem;
width: 18rem;
- height: 5rem;
.btn-edit-node {
display: flex;
@@ -195,6 +194,7 @@
.level {
margin-right: 8px;
+ align-items: flex-start;
}
#arrows {
From b8a18bfef1f3c86758d63bc3cde172ecc1758f43 Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Wed, 30 Jun 2021 01:57:43 +0530
Subject: [PATCH 015/386] feat: add arc to connectors in mobile view
---
erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js b/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
index 4b09714d0a..b09b428b30 100644
--- a/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
+++ b/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
@@ -322,7 +322,8 @@ erpnext.HierarchyChartMobile = class {
"M" +
(pos_parent_bottom.x) + "," + (pos_parent_bottom.y) + " " +
"L" +
- (pos_parent_bottom.x) + "," + (pos_child_left.y) + " " +
+ (pos_parent_bottom.x) + "," + (pos_child_left.y - 10) + " " +
+ "a10,10 1 0 0 10,10 " +
"L" +
(pos_child_left.x) + "," + (pos_child_left.y);
From 77b0b8a877108062818b5e0f72995966a85f9af2 Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Wed, 30 Jun 2021 02:29:16 +0530
Subject: [PATCH 016/386] fix: edit node button overflowing
---
erpnext/public/js/templates/node_card.html | 2 +-
erpnext/public/scss/hierarchy_chart.scss | 2 ++
2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/erpnext/public/js/templates/node_card.html b/erpnext/public/js/templates/node_card.html
index 30aedab4bb..c3d8e010b5 100644
--- a/erpnext/public/js/templates/node_card.html
+++ b/erpnext/public/js/templates/node_card.html
@@ -8,7 +8,7 @@
{{ name }}
-
+
diff --git a/erpnext/public/scss/hierarchy_chart.scss b/erpnext/public/scss/hierarchy_chart.scss
index 16137fdb5f..eefc14d679 100644
--- a/erpnext/public/scss/hierarchy_chart.scss
+++ b/erpnext/public/scss/hierarchy_chart.scss
@@ -57,6 +57,7 @@
font-size: .75rem;
justify-content: center;
box-shadow: var(--shadow-sm);
+ margin-left: auto;
}
.edit-chart-node {
@@ -79,6 +80,7 @@
align-items: center;
justify-content: space-between;
margin-bottom: 2px;
+ width: 12.2rem;
}
}
From 2fcd05aa82042456b50c9dad42d1e97d57afb80f Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Fri, 2 Jul 2021 18:15:18 +0530
Subject: [PATCH 017/386] fix: sider
---
.../hierarchy_chart_desktop.js | 25 +++++++++----------
.../hierarchy_chart/hierarchy_chart_mobile.js | 18 ++++++-------
erpnext/public/scss/hierarchy_chart.scss | 5 +---
3 files changed, 22 insertions(+), 26 deletions(-)
diff --git a/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js b/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
index ba811be586..9e82fb2002 100644
--- a/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
+++ b/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
@@ -40,7 +40,7 @@ erpnext.HierarchyChart = class {
me.setup_node_click_action(this);
me.setup_edit_node_action(this);
}
- }
+ };
}
make_node_element(node) {
@@ -76,7 +76,7 @@ erpnext.HierarchyChart = class {
me.company = company.get_value();
// svg for connectors
- me.make_svg_markers()
+ me.make_svg_markers();
if (me.$hierarchy)
me.$hierarchy.remove();
@@ -149,7 +149,7 @@ erpnext.HierarchyChart = class {
me.expand_node(root_node);
}
}
- })
+ });
}
expand_node(node) {
@@ -166,7 +166,7 @@ erpnext.HierarchyChart = class {
// rebuild incoming connections
let grandparent = $(`#${node.parent_id}`).attr('data-parent');
- this.refresh_connectors(grandparent)
+ this.refresh_connectors(grandparent);
}
if (node.expandable && !node.expanded) {
@@ -176,8 +176,8 @@ erpnext.HierarchyChart = class {
collapse_node() {
if (this.selected_node.expandable) {
- this.selected_node.$children.hide();
- $(`path[data-parent="${this.selected_node.id}"]`).hide();
+ this.selected_node.$children.hide('fast');
+ $(`path[data-parent="${this.selected_node.id}"]`).hide('fast');
this.selected_node.expanded = false;
}
}
@@ -222,15 +222,14 @@ erpnext.HierarchyChart = class {
if (!node.$children) {
node.$children = $('')
- .hide()
- .appendTo(this.$hierarchy.find('.level:last'));
+ .hide()
+ .appendTo(this.$hierarchy.find('.level:last'));
node.$children.empty();
if (child_nodes) {
$.each(child_nodes, (_i, data) => {
this.add_node(node, data);
-
setTimeout(() => {
this.add_connector(node.id, data.id);
}, 250);
@@ -238,8 +237,8 @@ erpnext.HierarchyChart = class {
}
}
- node.$children.show();
- $(`path[data-parent="${node.id}"]`).show();
+ node.$children.show('fast');
+ $(`path[data-parent="${node.id}"]`).show('fast');
node.expanded = true;
}
@@ -443,6 +442,6 @@ erpnext.HierarchyChart = class {
return;
$(path).remove();
- })
+ });
}
-}
\ No newline at end of file
+};
\ No newline at end of file
diff --git a/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js b/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
index b09b428b30..2ff00baa7c 100644
--- a/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
+++ b/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
@@ -10,7 +10,7 @@ erpnext.HierarchyChartMobile = class {
this.wrapper = $(wrapper);
this.page = wrapper.page;
this.method = method;
- this.doctype = doctype
+ this.doctype = doctype;
this.page.main.css({
'min-height': '300px',
@@ -40,7 +40,7 @@ erpnext.HierarchyChartMobile = class {
me.setup_node_click_action(this);
me.setup_edit_node_action(this);
}
- }
+ };
}
make_node_element(node) {
@@ -78,7 +78,7 @@ erpnext.HierarchyChartMobile = class {
me.company = company.get_value();
// svg for connectors
- me.make_svg_markers()
+ me.make_svg_markers();
if (me.$sibling_group)
me.$sibling_group.remove();
@@ -158,7 +158,7 @@ erpnext.HierarchyChartMobile = class {
me.expand_node(root_node);
}
}
- })
+ });
}
expand_node(node) {
@@ -248,8 +248,8 @@ erpnext.HierarchyChartMobile = class {
render_child_nodes(node, child_nodes) {
if (!node.$children) {
node.$children = $('')
- .hide()
- .appendTo(node.$link.parent());
+ .hide()
+ .appendTo(node.$link.parent());
node.$children.empty();
@@ -462,7 +462,7 @@ erpnext.HierarchyChartMobile = class {
get_avatar(node) {
return `
- `
+ `;
}
expand_sibling_group_node(parent) {
@@ -518,7 +518,7 @@ erpnext.HierarchyChartMobile = class {
return;
$(path).remove();
- })
+ });
}
refresh_connectors(node_parent, node_id) {
@@ -527,4 +527,4 @@ erpnext.HierarchyChartMobile = class {
$(`path[data-parent="${node_parent}"]`).remove();
this.add_connector(node_parent, node_id);
}
-}
\ No newline at end of file
+};
\ No newline at end of file
diff --git a/erpnext/public/scss/hierarchy_chart.scss b/erpnext/public/scss/hierarchy_chart.scss
index eefc14d679..a54bf6f332 100644
--- a/erpnext/public/scss/hierarchy_chart.scss
+++ b/erpnext/public/scss/hierarchy_chart.scss
@@ -62,16 +62,13 @@
.edit-chart-node {
display: block;
+ margin-right: 0.25rem;
}
.node-edit-icon {
display: block;
}
- .edit-chart-node {
- margin-right: 0.25rem;
- }
-
.node-edit-icon > .icon{
stroke: var(--blue-500);
}
From ad066033925ed8f8e5bd6c2e8b7f9c3cc54e5e27 Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Tue, 6 Jul 2021 18:16:49 +0530
Subject: [PATCH 018/386] fix: removing orphaned connectors
---
.../js/hierarchy_chart/hierarchy_chart_desktop.js | 14 ++++++--------
.../js/hierarchy_chart/hierarchy_chart_mobile.js | 6 ++----
2 files changed, 8 insertions(+), 12 deletions(-)
diff --git a/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js b/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
index 9e82fb2002..1896ac7c39 100644
--- a/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
+++ b/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
@@ -176,8 +176,8 @@ erpnext.HierarchyChart = class {
collapse_node() {
if (this.selected_node.expandable) {
- this.selected_node.$children.hide('fast');
- $(`path[data-parent="${this.selected_node.id}"]`).hide('fast');
+ this.selected_node.$children.hide();
+ $(`path[data-parent="${this.selected_node.id}"]`).hide();
this.selected_node.expanded = false;
}
}
@@ -237,8 +237,8 @@ erpnext.HierarchyChart = class {
}
}
- node.$children.show('fast');
- $(`path[data-parent="${node.id}"]`).show('fast');
+ node.$children.show();
+ $(`path[data-parent="${node.id}"]`).show();
node.expanded = true;
}
@@ -262,9 +262,7 @@ erpnext.HierarchyChart = class {
let parent_node = document.querySelector(`#${parent_id}`);
let child_node = document.querySelector(`#${child_id}`);
- // variable for the namespace
- const svgns = 'http://www.w3.org/2000/svg';
- let path = document.createElementNS(svgns, 'path');
+ let path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
// we need to connect right side of the parent to the left side of the child node
let pos_parent_right = {
@@ -438,7 +436,7 @@ erpnext.HierarchyChart = class {
let parent = $(path).data('parent');
let child = $(path).data('child');
- if ($(parent).length || $(child).length)
+ if ($(`#${parent}`).length && $(`#${child}`).length)
return;
$(path).remove();
diff --git a/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js b/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
index 2ff00baa7c..102cbb03b0 100644
--- a/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
+++ b/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
@@ -289,9 +289,7 @@ erpnext.HierarchyChartMobile = class {
let parent_node = document.querySelector(`#${parent_id}`);
let child_node = document.querySelector(`#${child_id}`);
- // variable for the namespace
- const svgns = 'http://www.w3.org/2000/svg';
- let path = document.createElementNS(svgns, 'path');
+ let path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
let connector = undefined;
@@ -514,7 +512,7 @@ erpnext.HierarchyChartMobile = class {
let parent = $(path).data('parent');
let child = $(path).data('child');
- if ($(parent).length || $(child).length)
+ if ($(`#${parent}`).length && $(`#${child}`).length)
return;
$(path).remove();
From 6d5ee25bba0222b122d873340784cc82ee8309fc Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Wed, 7 Jul 2021 09:43:28 +0530
Subject: [PATCH 019/386] fix: unnecessary variables
---
.../js/hierarchy_chart/hierarchy_chart_desktop.js | 14 ++++++--------
1 file changed, 6 insertions(+), 8 deletions(-)
diff --git a/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js b/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
index 1896ac7c39..8d0685f80d 100644
--- a/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
+++ b/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
@@ -153,7 +153,7 @@ erpnext.HierarchyChart = class {
}
expand_node(node) {
- let is_sibling = this.selected_node && this.selected_node.parent_id === node.parent_id;
+ const is_sibling = this.selected_node && this.selected_node.parent_id === node.parent_id;
this.set_selected_node(node);
this.show_active_path(node);
this.collapse_previous_level_nodes(node);
@@ -243,11 +243,9 @@ erpnext.HierarchyChart = class {
}
add_node(node, data) {
- var $li = $(' ');
-
return new this.Node({
id: data.id,
- parent: $li.appendTo(node.$children),
+ parent: $(' ').appendTo(node.$children),
parent_id: node.id,
image: data.image,
name: data.name,
@@ -259,8 +257,8 @@ erpnext.HierarchyChart = class {
}
add_connector(parent_id, child_id) {
- let parent_node = document.querySelector(`#${parent_id}`);
- let child_node = document.querySelector(`#${child_id}`);
+ const parent_node = document.querySelector(`#${parent_id}`);
+ const child_node = document.querySelector(`#${child_id}`);
let path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
@@ -276,7 +274,7 @@ erpnext.HierarchyChart = class {
let connector = this.get_connector(pos_parent_right, pos_child_left);
- path.setAttribute("d", connector);
+ path.setAttribute('d', connector);
this.set_path_attributes(path, parent_id, child_id);
$('#connectors').append(path);
@@ -385,7 +383,7 @@ erpnext.HierarchyChart = class {
let node_element = $(`#${node.id}`);
node_element.click(function() {
- let is_sibling = me.selected_node.parent_id === node.parent_id;
+ const is_sibling = me.selected_node.parent_id === node.parent_id;
if (is_sibling) {
me.collapse_node();
From 6eec25127369e2b3af3658d11a80132facfee29e Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Wed, 7 Jul 2021 12:05:50 +0530
Subject: [PATCH 020/386] feat: handle multiple root / orphan nodes
---
.../organizational_chart.py | 3 +-
.../hierarchy_chart_desktop.js | 48 +++++++++----------
.../hierarchy_chart/hierarchy_chart_mobile.js | 35 +++++++-------
erpnext/public/scss/hierarchy_chart.scss | 4 ++
4 files changed, 49 insertions(+), 41 deletions(-)
diff --git a/erpnext/hr/page/organizational_chart/organizational_chart.py b/erpnext/hr/page/organizational_chart/organizational_chart.py
index f3aa13897d..77b8df7520 100644
--- a/erpnext/hr/page/organizational_chart/organizational_chart.py
+++ b/erpnext/hr/page/organizational_chart/organizational_chart.py
@@ -17,7 +17,7 @@ def get_children(parent=None, company=None, exclude_node=None, is_root=False, is
if exclude_node:
filters.append(['name', '!=', exclude_node])
- if parent and company and parent!=company:
+ if parent and company and parent != company:
filters.append(['reports_to', '=', parent])
else:
filters.append(['reports_to', '=', ''])
@@ -32,6 +32,7 @@ def get_children(parent=None, company=None, exclude_node=None, is_root=False, is
employee.connections = get_connections(employee.id)
employee.expandable = 1 if is_expandable else 0
+ employees.sort(key=lambda x: x['connections'], reverse=True)
return employees
diff --git a/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js b/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
index 8d0685f80d..e89a98ac4f 100644
--- a/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
+++ b/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
@@ -84,11 +84,13 @@ erpnext.HierarchyChart = class {
// setup hierarchy
me.$hierarchy = $(
``);
me.page.main.append(me.$hierarchy);
- me.render_root_node();
+ me.render_root_nodes();
}
}
});
@@ -122,7 +124,7 @@ erpnext.HierarchyChart = class {
`);
}
- render_root_node() {
+ render_root_nodes() {
let me = this;
frappe.call({
@@ -132,21 +134,28 @@ erpnext.HierarchyChart = class {
},
callback: function(r) {
if (r.message.length) {
- let data = r.message[0];
+ let nodes = r.message;
+ let node = undefined;
+ let first_root = undefined;
- let root_node = new me.Node({
- id: data.id,
- parent: me.$hierarchy.find('.root-level'),
- parent_id: undefined,
- image: data.image,
- name: data.name,
- title: data.title,
- expandable: true,
- connections: data.connections,
- is_root: true,
+ $.each(nodes, (i, data) => {
+ node = new me.Node({
+ id: data.id,
+ parent: $(' ').appendTo(me.$hierarchy.find('.node-children')),
+ parent_id: undefined,
+ image: data.image,
+ name: data.name,
+ title: data.title,
+ expandable: true,
+ connections: data.connections,
+ is_root: true
+ });
+
+ if (i == 0)
+ first_root = node;
});
- me.expand_node(root_node);
+ me.expand_node(first_root);
}
}
});
@@ -344,12 +353,7 @@ erpnext.HierarchyChart = class {
collapse_previous_level_nodes(node) {
let node_parent = $(`#${node.parent_id}`);
-
let previous_level_nodes = node_parent.parent().parent().children('li');
- if (node_parent.parent().hasClass('root-level')) {
- previous_level_nodes = node_parent.parent().children('li');
- }
-
let node_card = undefined;
previous_level_nodes.each(function() {
@@ -409,10 +413,6 @@ erpnext.HierarchyChart = class {
remove_levels_after_node(node) {
let level = $(`#${node.id}`).parent().parent().parent();
- if ($(`#${node.id}`).parent().hasClass('root-level')) {
- level = $(`#${node.id}`).parent();
- }
-
level = $('.hierarchy > li:eq('+ level.index() + ')');
level.nextAll('li').remove();
diff --git a/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js b/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
index 102cbb03b0..5eee27b5fc 100644
--- a/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
+++ b/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
@@ -97,7 +97,7 @@ erpnext.HierarchyChartMobile = class {
`);
me.page.main.append(me.$hierarchy);
- me.render_root_node();
+ me.render_root_nodes();
}
}
});
@@ -131,7 +131,7 @@ erpnext.HierarchyChartMobile = class {
`);
}
- render_root_node() {
+ render_root_nodes() {
let me = this;
frappe.call({
@@ -141,21 +141,21 @@ erpnext.HierarchyChartMobile = class {
},
callback: function(r) {
if (r.message.length) {
- let data = r.message[0];
+ let nodes = r.message;
- let root_node = new me.Node({
- id: data.id,
- parent: me.$hierarchy.find('.root-level'),
- parent_id: undefined,
- image: data.image,
- name: data.name,
- title: data.title,
- expandable: true,
- connections: data.connections,
- is_root: true,
+ $.each(nodes, (_i, data) => {
+ return new me.Node({
+ id: data.id,
+ parent: me.$hierarchy.find('.root-level'),
+ parent_id: undefined,
+ image: data.image,
+ name: data.name,
+ title: data.title,
+ expandable: true,
+ connections: data.connections,
+ is_root: true
+ });
});
-
- me.expand_node(root_node);
}
}
});
@@ -375,7 +375,10 @@ erpnext.HierarchyChartMobile = class {
let node_element = $(`#${node.id}`);
node_element.click(function() {
- if (node_element.is(':visible') && node_element.hasClass('active-path')) {
+ if (node.is_root) {
+ me.$hierarchy.empty();
+ me.add_node_to_hierarchy(node, true);
+ } else if (node_element.is(':visible') && node_element.hasClass('active-path')) {
me.remove_levels_after_node(node);
me.remove_orphaned_connectors();
} else {
diff --git a/erpnext/public/scss/hierarchy_chart.scss b/erpnext/public/scss/hierarchy_chart.scss
index a54bf6f332..dd523c3443 100644
--- a/erpnext/public/scss/hierarchy_chart.scss
+++ b/erpnext/public/scss/hierarchy_chart.scss
@@ -246,6 +246,10 @@
margin-top: 16px;
}
+.root-level .node-card {
+ margin: 0 0 16px;
+}
+
// node group
.collapsed-level {
From df3bb9ea8caffe47e3696c10f711a393d78e6630 Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Thu, 8 Jul 2021 09:53:31 +0530
Subject: [PATCH 021/386] perf: Optimise Rendering
- optimise get_children function
- use promises instead of callbacks
- optimise selectors
- use const wherever possible
- use pure js instead of jquery for connectors for faster rendering
---
.../organizational_chart.py | 22 ++---
.../hierarchy_chart_desktop.js | 82 +++++++++----------
.../hierarchy_chart/hierarchy_chart_mobile.js | 65 +++++++--------
3 files changed, 78 insertions(+), 91 deletions(-)
diff --git a/erpnext/hr/page/organizational_chart/organizational_chart.py b/erpnext/hr/page/organizational_chart/organizational_chart.py
index 77b8df7520..46578f3aaf 100644
--- a/erpnext/hr/page/organizational_chart/organizational_chart.py
+++ b/erpnext/hr/page/organizational_chart/organizational_chart.py
@@ -2,33 +2,25 @@ from __future__ import unicode_literals
import frappe
@frappe.whitelist()
-def get_children(parent=None, company=None, exclude_node=None, is_root=False, is_tree=False, fields=None):
+def get_children(parent=None, company=None):
filters = [['status', '!=', 'Left']]
if company and company != 'All Companies':
filters.append(['company', '=', company])
- if not fields:
- fields = ['employee_name as name', 'name as id', 'reports_to', 'image', 'designation as title']
-
- if is_root:
- parent = ''
-
- if exclude_node:
- filters.append(['name', '!=', exclude_node])
-
if parent and company and parent != company:
filters.append(['reports_to', '=', parent])
else:
filters.append(['reports_to', '=', ''])
- employees = frappe.get_list('Employee', fields=fields,
- filters=filters, order_by='name')
+ employees = frappe.get_list('Employee',
+ fields=['employee_name as name', 'name as id', 'reports_to', 'image', 'designation as title'],
+ filters=filters,
+ order_by='name'
+ )
for employee in employees:
- is_expandable = frappe.get_all('Employee', filters=[
- ['reports_to', '=', employee.get('id')]
- ])
+ is_expandable = frappe.db.count('Employee', filters={'reports_to': employee.get('id')})
employee.connections = get_connections(employee.id)
employee.expandable = 1 if is_expandable else 0
diff --git a/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js b/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
index e89a98ac4f..bf366792a9 100644
--- a/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
+++ b/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
@@ -7,7 +7,6 @@ erpnext.HierarchyChart = class {
- this method should return id, name, title, image, and connections for each node
*/
constructor(doctype, wrapper, method) {
- this.wrapper = $(wrapper);
this.page = wrapper.page;
this.method = method;
this.doctype = doctype;
@@ -61,6 +60,8 @@ erpnext.HierarchyChart = class {
frappe.breadcrumbs.add('HR');
let me = this;
+ if ($(`[data-fieldname="company"]`).length) return;
+
let company = this.page.add_field({
fieldtype: 'Link',
options: 'Company',
@@ -131,32 +132,30 @@ erpnext.HierarchyChart = class {
method: me.method,
args: {
company: me.company
- },
- callback: function(r) {
- if (r.message.length) {
- let nodes = r.message;
- let node = undefined;
- let first_root = undefined;
+ }
+ }).then(r => {
+ if (r.message.length) {
+ let node = undefined;
+ let first_root = undefined;
- $.each(nodes, (i, data) => {
- node = new me.Node({
- id: data.id,
- parent: $(' ').appendTo(me.$hierarchy.find('.node-children')),
- parent_id: undefined,
- image: data.image,
- name: data.name,
- title: data.title,
- expandable: true,
- connections: data.connections,
- is_root: true
- });
-
- if (i == 0)
- first_root = node;
+ $.each(r.message, (i, data) => {
+ node = new me.Node({
+ id: data.id,
+ parent: $(' ').appendTo(me.$hierarchy.find('.node-children')),
+ parent_id: undefined,
+ image: data.image,
+ name: data.name,
+ title: data.title,
+ expandable: true,
+ connections: data.connections,
+ is_root: true
});
- me.expand_node(first_root);
- }
+ if (i == 0)
+ first_root = node;
+ });
+
+ me.expand_node(first_root);
}
});
}
@@ -204,18 +203,14 @@ erpnext.HierarchyChart = class {
}
get_child_nodes(node_id) {
- let me = this;
return new Promise(resolve => {
frappe.call({
method: this.method,
args: {
parent: node_id,
- company: me.company
- },
- callback: (r) => {
- resolve(r.message);
+ company: this.company
}
- });
+ }).then(r => resolve(r.message));
});
}
@@ -266,27 +261,28 @@ erpnext.HierarchyChart = class {
}
add_connector(parent_id, child_id) {
+ // using pure javascript for better performance
const parent_node = document.querySelector(`#${parent_id}`);
const child_node = document.querySelector(`#${child_id}`);
let path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
// we need to connect right side of the parent to the left side of the child node
- let pos_parent_right = {
+ const pos_parent_right = {
x: parent_node.offsetLeft + parent_node.offsetWidth,
y: parent_node.offsetTop + parent_node.offsetHeight / 2
};
- let pos_child_left = {
+ const pos_child_left = {
x: child_node.offsetLeft - 5,
y: child_node.offsetTop + child_node.offsetHeight / 2
};
- let connector = this.get_connector(pos_parent_right, pos_child_left);
+ const connector = this.get_connector(pos_parent_right, pos_child_left);
path.setAttribute('d', connector);
this.set_path_attributes(path, parent_id, child_id);
- $('#connectors').append(path);
+ document.getElementById('connectors').appendChild(path);
}
get_connector(pos_parent_right, pos_child_left) {
@@ -330,12 +326,13 @@ erpnext.HierarchyChart = class {
set_path_attributes(path, parent_id, child_id) {
path.setAttribute("data-parent", parent_id);
path.setAttribute("data-child", child_id);
+ const parent = $(`#${parent_id}`);
- if ($(`#${parent_id}`).hasClass('active')) {
+ if (parent.hasClass('active')) {
path.setAttribute("class", "active-connector");
path.setAttribute("marker-start", "url(#arrowstart-active)");
path.setAttribute("marker-end", "url(#arrowhead-active)");
- } else if ($(`#${parent_id}`).hasClass('active-path')) {
+ } else if (parent.hasClass('active-path')) {
path.setAttribute("class", "collapsed-connector");
path.setAttribute("marker-start", "url(#arrowstart-collapsed)");
path.setAttribute("marker-end", "url(#arrowhead-collapsed)");
@@ -343,8 +340,9 @@ erpnext.HierarchyChart = class {
}
set_selected_node(node) {
- // remove .active class from the current node
- $('.active').removeClass('active');
+ // remove active class from the current node
+ if (this.selected_node)
+ this.selected_node.$link.removeClass('active');
// add active class to the newly selected node
this.selected_node = node;
@@ -411,9 +409,9 @@ erpnext.HierarchyChart = class {
}
remove_levels_after_node(node) {
- let level = $(`#${node.id}`).parent().parent().parent();
+ let level = $(`#${node.id}`).parent().parent().parent().index();
- level = $('.hierarchy > li:eq('+ level.index() + ')');
+ level = $('.hierarchy > li:eq('+ level + ')');
level.nextAll('li').remove();
let nodes = level.find('.node-card');
@@ -431,8 +429,8 @@ erpnext.HierarchyChart = class {
remove_orphaned_connectors() {
let paths = $('#connectors > path');
$.each(paths, (_i, path) => {
- let parent = $(path).data('parent');
- let child = $(path).data('child');
+ const parent = $(path).data('parent');
+ const child = $(path).data('child');
if ($(`#${parent}`).length && $(`#${child}`).length)
return;
diff --git a/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js b/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
index 5eee27b5fc..17062e2585 100644
--- a/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
+++ b/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
@@ -7,7 +7,6 @@ erpnext.HierarchyChartMobile = class {
- this method should return id, name, title, image, and connections for each node
*/
constructor(doctype, wrapper, method) {
- this.wrapper = $(wrapper);
this.page = wrapper.page;
this.method = method;
this.doctype = doctype;
@@ -63,6 +62,8 @@ erpnext.HierarchyChartMobile = class {
frappe.breadcrumbs.add('HR');
let me = this;
+ if ($(`[data-fieldname="company"]`).length) return;
+
let company = this.page.add_field({
fieldtype: 'Link',
options: 'Company',
@@ -139,24 +140,21 @@ erpnext.HierarchyChartMobile = class {
args: {
company: me.company
},
- callback: function(r) {
- if (r.message.length) {
- let nodes = r.message;
-
- $.each(nodes, (_i, data) => {
- return new me.Node({
- id: data.id,
- parent: me.$hierarchy.find('.root-level'),
- parent_id: undefined,
- image: data.image,
- name: data.name,
- title: data.title,
- expandable: true,
- connections: data.connections,
- is_root: true
- });
+ }).then(r => {
+ if (r.message.length) {
+ $.each(r.message, (_i, data) => {
+ return new me.Node({
+ id: data.id,
+ parent: me.$hierarchy.find('.root-level'),
+ parent_id: undefined,
+ image: data.image,
+ name: data.name,
+ title: data.title,
+ expandable: true,
+ connections: data.connections,
+ is_root: true
});
- }
+ });
}
});
}
@@ -237,11 +235,8 @@ erpnext.HierarchyChartMobile = class {
parent: node_id,
company: me.company,
exclude_node: exclude_node
- },
- callback: (r) => {
- resolve(r.message);
}
- });
+ }).then(r => resolve(r.message));
});
}
@@ -286,10 +281,10 @@ erpnext.HierarchyChartMobile = class {
}
add_connector(parent_id, child_id) {
- let parent_node = document.querySelector(`#${parent_id}`);
- let child_node = document.querySelector(`#${child_id}`);
+ const parent_node = document.querySelector(`#${parent_id}`);
+ const child_node = document.querySelector(`#${child_id}`);
- let path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
+ const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
let connector = undefined;
@@ -299,10 +294,10 @@ erpnext.HierarchyChartMobile = class {
connector = this.get_connector_for_collapsed_node(parent_node, child_node);
}
- path.setAttribute("d", connector);
+ path.setAttribute('d', connector);
this.set_path_attributes(path, parent_id, child_id);
- $('#connectors').append(path);
+ document.getElementById('connectors').appendChild(path);
}
get_connector_for_active_node(parent_node, child_node) {
@@ -351,19 +346,21 @@ erpnext.HierarchyChartMobile = class {
set_path_attributes(path, parent_id, child_id) {
path.setAttribute("data-parent", parent_id);
path.setAttribute("data-child", child_id);
+ const parent = $(`#${parent_id}`);
- if ($(`#${parent_id}`).hasClass('active')) {
+ if (parent.hasClass('active')) {
path.setAttribute("class", "active-connector");
path.setAttribute("marker-start", "url(#arrowstart-active)");
path.setAttribute("marker-end", "url(#arrowhead-active)");
- } else if ($(`#${parent_id}`).hasClass('active-path')) {
+ } else if (parent.hasClass('active-path')) {
path.setAttribute("class", "collapsed-connector");
}
}
set_selected_node(node) {
// remove .active class from the current node
- $('.active').removeClass('active');
+ if (this.selected_node)
+ this.selected_node.$link.removeClass('active');
// add active class to the newly selected node
this.selected_node = node;
@@ -494,9 +491,9 @@ erpnext.HierarchyChartMobile = class {
}
remove_levels_after_node(node) {
- let level = $(`#${node.id}`).parent().parent();
+ let level = $(`#${node.id}`).parent().parent().index();
- level = $('.hierarchy-mobile > li:eq('+ (level.index()) + ')');
+ level = $('.hierarchy-mobile > li:eq('+ level + ')');
level.nextAll('li').remove();
let current_node = level.find(`#${node.id}`);
@@ -512,8 +509,8 @@ erpnext.HierarchyChartMobile = class {
remove_orphaned_connectors() {
let paths = $('#connectors > path');
$.each(paths, (_i, path) => {
- let parent = $(path).data('parent');
- let child = $(path).data('child');
+ const parent = $(path).data('parent');
+ const child = $(path).data('child');
if ($(`#${parent}`).length && $(`#${child}`).length)
return;
From 48018b8d8c50caee0e8b6ff6bd5a81a35806dcdb Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Thu, 8 Jul 2021 11:23:50 +0530
Subject: [PATCH 022/386] fix: do not sort by number of connections
---
.../hr/page/organizational_chart/organizational_chart.py | 1 -
.../public/js/hierarchy_chart/hierarchy_chart_desktop.js | 8 ++++----
2 files changed, 4 insertions(+), 5 deletions(-)
diff --git a/erpnext/hr/page/organizational_chart/organizational_chart.py b/erpnext/hr/page/organizational_chart/organizational_chart.py
index 46578f3aaf..ce84b3c744 100644
--- a/erpnext/hr/page/organizational_chart/organizational_chart.py
+++ b/erpnext/hr/page/organizational_chart/organizational_chart.py
@@ -24,7 +24,6 @@ def get_children(parent=None, company=None):
employee.connections = get_connections(employee.id)
employee.expandable = 1 if is_expandable else 0
- employees.sort(key=lambda x: x['connections'], reverse=True)
return employees
diff --git a/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js b/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
index bf366792a9..374787c6ef 100644
--- a/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
+++ b/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
@@ -135,8 +135,8 @@ erpnext.HierarchyChart = class {
}
}).then(r => {
if (r.message.length) {
+ let expand_node = undefined;
let node = undefined;
- let first_root = undefined;
$.each(r.message, (i, data) => {
node = new me.Node({
@@ -151,11 +151,11 @@ erpnext.HierarchyChart = class {
is_root: true
});
- if (i == 0)
- first_root = node;
+ if (!expand_node && data.connections)
+ expand_node = node;
});
- me.expand_node(first_root);
+ me.expand_node(expand_node);
}
});
}
From 05ffc0d3e0fc061639494df2978557c63f7d2d25 Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Thu, 8 Jul 2021 16:55:42 +0530
Subject: [PATCH 023/386] feat: use icon for connections on mobile view
---
.../js/hierarchy_chart/hierarchy_chart_mobile.js | 2 +-
erpnext/public/js/templates/node_card.html | 12 +++++++++---
2 files changed, 10 insertions(+), 4 deletions(-)
diff --git a/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js b/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
index 17062e2585..1985299378 100644
--- a/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
+++ b/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
@@ -50,7 +50,7 @@ erpnext.HierarchyChartMobile = class {
image: node.image,
parent: node.parent_id,
connections: node.connections,
- is_mobile: 1
+ is_mobile: true
});
node.parent.append(node_card);
diff --git a/erpnext/public/js/templates/node_card.html b/erpnext/public/js/templates/node_card.html
index c3d8e010b5..fb94df85ed 100644
--- a/erpnext/public/js/templates/node_card.html
+++ b/erpnext/public/js/templates/node_card.html
@@ -16,10 +16,16 @@
{{ title }}
- {% if connections == 1 %}
-
· {{ connections }} Connection
+ {% if is_mobile %}
+
+ · {{ connections }}
+
{% else %}
-
· {{ connections }} Connections
+ {% if connections == 1 %}
+
· {{ connections }} Connection
+ {% else %}
+
· {{ connections }} Connections
+ {% endif %}
{% endif %}
From 09c24c79496e942d749ff8e5a4ef502453064557 Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Thu, 8 Jul 2021 17:05:40 +0530
Subject: [PATCH 024/386] fix: exclude active node while fetching sibling group
---
.../hr/page/organizational_chart/organizational_chart.py | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/erpnext/hr/page/organizational_chart/organizational_chart.py b/erpnext/hr/page/organizational_chart/organizational_chart.py
index ce84b3c744..1e03e3d06a 100644
--- a/erpnext/hr/page/organizational_chart/organizational_chart.py
+++ b/erpnext/hr/page/organizational_chart/organizational_chart.py
@@ -2,8 +2,7 @@ from __future__ import unicode_literals
import frappe
@frappe.whitelist()
-def get_children(parent=None, company=None):
-
+def get_children(parent=None, company=None, exclude_node=None):
filters = [['status', '!=', 'Left']]
if company and company != 'All Companies':
filters.append(['company', '=', company])
@@ -13,6 +12,9 @@ def get_children(parent=None, company=None):
else:
filters.append(['reports_to', '=', ''])
+ if exclude_node:
+ filters.append(['name', '!=', exclude_node])
+
employees = frappe.get_list('Employee',
fields=['employee_name as name', 'name as id', 'reports_to', 'image', 'designation as title'],
filters=filters,
From 06fc9e7847622cf0443c166d3514d6a2288e4902 Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Thu, 8 Jul 2021 18:44:53 +0530
Subject: [PATCH 025/386] fix: sibling group expansion not working for root
nodes
---
.../hierarchy_chart/hierarchy_chart_mobile.js | 36 ++++++++++++-------
1 file changed, 24 insertions(+), 12 deletions(-)
diff --git a/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js b/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
index 1985299378..d48b4c8f36 100644
--- a/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
+++ b/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
@@ -88,16 +88,7 @@ erpnext.HierarchyChartMobile = class {
me.$sibling_group = $(`
`);
me.page.main.append(me.$sibling_group);
- if (me.$hierarchy)
- me.$hierarchy.remove();
-
- // setup hierarchy
- me.$hierarchy = $(
- ``);
-
- me.page.main.append(me.$hierarchy);
+ me.setup_hierarchy()
me.render_root_nodes();
}
}
@@ -132,6 +123,19 @@ erpnext.HierarchyChartMobile = class {
`);
}
+ setup_hierarchy() {
+ $(`#connectors`).empty();
+ if (this.$hierarchy)
+ this.$hierarchy.remove();
+
+ this.$hierarchy = $(
+ ``);
+
+ this.page.main.append(this.$hierarchy);
+ }
+
render_root_nodes() {
let me = this;
@@ -142,10 +146,13 @@ erpnext.HierarchyChartMobile = class {
},
}).then(r => {
if (r.message.length) {
+ let root_level = me.$hierarchy.find('.root-level');
+ root_level.empty();
+
$.each(r.message, (_i, data) => {
return new me.Node({
id: data.id,
- parent: me.$hierarchy.find('.root-level'),
+ parent: root_level,
parent_id: undefined,
image: data.image,
name: data.name,
@@ -401,7 +408,12 @@ erpnext.HierarchyChartMobile = class {
$('.node-group').on('click', function() {
let parent = $(this).attr('data-parent');
- me.expand_sibling_group_node(parent);
+ if (parent === 'undefined') {
+ me.setup_hierarchy();
+ me.render_root_nodes();
+ } else {
+ me.expand_sibling_group_node(parent);
+ }
});
}
From 24b31c0bf93a53c4f98fe5020b9575288b2a9aab Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Fri, 9 Jul 2021 01:03:02 +0530
Subject: [PATCH 026/386] fix(mobile): collapsed nodes not expanding
---
.../hierarchy_chart/hierarchy_chart_mobile.js | 58 ++++++++++---------
1 file changed, 32 insertions(+), 26 deletions(-)
diff --git a/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js b/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
index d48b4c8f36..58530eaaf9 100644
--- a/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
+++ b/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
@@ -88,7 +88,7 @@ erpnext.HierarchyChartMobile = class {
me.$sibling_group = $(`
`);
me.page.main.append(me.$sibling_group);
- me.setup_hierarchy()
+ me.setup_hierarchy();
me.render_root_nodes();
}
}
@@ -194,9 +194,9 @@ erpnext.HierarchyChartMobile = class {
collapse_node() {
let node = this.selected_node;
- if (node.expandable) {
+ if (node.expandable && node.$children) {
node.$children.hide();
- node.expanded = false;
+ node.expanded = 0;
// add a collapsed level to show the collapsed parent
// and a button beside it to move to that level
@@ -212,10 +212,7 @@ erpnext.HierarchyChartMobile = class {
frappe.run_serially([
() => this.get_child_nodes(node.parent_id, node.id),
(child_nodes) => this.get_node_group(child_nodes, node.parent_id),
- (node_group) => {
- node_parent.find('.collapsed-level')
- .append(node_group);
- },
+ (node_group) => node_parent.find('.collapsed-level').append(node_group),
() => this.setup_node_group_action()
]);
}
@@ -268,7 +265,7 @@ erpnext.HierarchyChartMobile = class {
}
node.$children.show();
- node.expanded = true;
+ node.expanded = 1;
}
add_node(node, data) {
@@ -380,13 +377,16 @@ erpnext.HierarchyChartMobile = class {
node_element.click(function() {
if (node.is_root) {
+ var el = $(this).detach();
me.$hierarchy.empty();
- me.add_node_to_hierarchy(node, true);
+ $(`#connectors`).empty();
+ me.add_node_to_hierarchy(el, node);
} else if (node_element.is(':visible') && node_element.hasClass('active-path')) {
me.remove_levels_after_node(node);
me.remove_orphaned_connectors();
} else {
- me.add_node_to_hierarchy(node, true);
+ var el = $(this).detach();
+ me.add_node_to_hierarchy(el, node);
me.collapse_node();
}
@@ -417,15 +417,15 @@ erpnext.HierarchyChartMobile = class {
});
}
- add_node_to_hierarchy(node) {
- this.$hierarchy.append(`
-
-
-
-
- `);
+ add_node_to_hierarchy(node_element, node) {
+ this.$hierarchy.append(` `);
+ node_element.removeClass('active-child active-path');
+ this.$hierarchy.find('.level:last').append(node_element);
- node.$link.appendTo(this.$hierarchy.find('.level:last'));
+ let node_object = this.nodes[node.id];
+ node_object.expanded = 0;
+ node_object.$children = undefined;
+ this.nodes[node.id] = node_object;
}
get_node_group(nodes, parent, collapsed=true) {
@@ -478,9 +478,11 @@ erpnext.HierarchyChartMobile = class {
expand_sibling_group_node(parent) {
let node_object = this.nodes[parent];
let node = node_object.$link;
+
node.removeClass('active-child active-path');
node_object.expanded = 0;
node_object.$children = undefined;
+ this.nodes[node.id] = node_object;
// show parent's siblings and expand parent node
frappe.run_serially([
@@ -491,17 +493,21 @@ erpnext.HierarchyChartMobile = class {
this.$sibling_group.empty().append(node_group);
},
() => this.setup_node_group_action(),
- () => {
- this.$hierarchy.empty().append(`
-
- `);
- this.$hierarchy.find('.level').append(node);
- $(`#connectors`).empty();
- this.expand_node(node_object);
- }
+ () => this.reattach_and_expand_node(node, node_object)
]);
}
+ reattach_and_expand_node(node, node_object) {
+ var el = node.detach();
+
+ this.$hierarchy.empty().append(`
+
+ `);
+ this.$hierarchy.find('.level').append(el);
+ $(`#connectors`).empty();
+ this.expand_node(node_object);
+ }
+
remove_levels_after_node(node) {
let level = $(`#${node.id}`).parent().parent().index();
From 4582f28d0d072feddc7cbfcab4aac063fdfaad36 Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Fri, 9 Jul 2021 01:25:26 +0530
Subject: [PATCH 027/386] fix: sider
---
erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js b/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
index 58530eaaf9..5a6f168876 100644
--- a/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
+++ b/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
@@ -376,8 +376,9 @@ erpnext.HierarchyChartMobile = class {
let node_element = $(`#${node.id}`);
node_element.click(function() {
+ let el = $(this).detach();
+
if (node.is_root) {
- var el = $(this).detach();
me.$hierarchy.empty();
$(`#connectors`).empty();
me.add_node_to_hierarchy(el, node);
@@ -385,7 +386,6 @@ erpnext.HierarchyChartMobile = class {
me.remove_levels_after_node(node);
me.remove_orphaned_connectors();
} else {
- var el = $(this).detach();
me.add_node_to_hierarchy(el, node);
me.collapse_node();
}
From 9e26f2d797ee17b332463e9aace65b516c0c2deb Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Fri, 9 Jul 2021 22:08:56 +0530
Subject: [PATCH 028/386] fix: Organize buttons
---
erpnext/assets/doctype/asset/asset.js | 67 ++++++++++++-------
erpnext/assets/doctype/asset/asset.py | 11 ++-
.../doctype/asset_repair/asset_repair.json | 42 +++++-------
3 files changed, 70 insertions(+), 50 deletions(-)
diff --git a/erpnext/assets/doctype/asset/asset.js b/erpnext/assets/doctype/asset/asset.js
index 6f1bb28f37..2a57183a80 100644
--- a/erpnext/assets/doctype/asset/asset.js
+++ b/erpnext/assets/doctype/asset/asset.js
@@ -82,24 +82,46 @@ frappe.ui.form.on('Asset', {
if (in_list(["Submitted", "Partially Depreciated", "Fully Depreciated"], frm.doc.status)) {
frm.add_custom_button("Transfer Asset", function() {
erpnext.asset.transfer_asset(frm);
- });
+ }, __("Manage"));
frm.add_custom_button("Scrap Asset", function() {
erpnext.asset.scrap_asset(frm);
- });
+ }, __("Manage"));
frm.add_custom_button("Sell Asset", function() {
frm.trigger("make_sales_invoice");
- });
+ }, __("Manage"));
} else if (frm.doc.status=='Scrapped') {
frm.add_custom_button("Restore Asset", function() {
erpnext.asset.restore_asset(frm);
- });
+ }, __("Manage"));
+ }
+
+ if (frm.doc.maintenance_required && !frm.doc.maintenance_schedule) {
+ frm.add_custom_button(__("Maintain Asset"), function() {
+ frm.trigger("create_asset_maintenance");
+ }, __("Manage"));
+ }
+
+ frm.add_custom_button(__("Repair Asset"), function() {
+ frm.trigger("create_asset_repair");
+ }, __("Manage"));
+
+ if (frm.doc.status != 'Fully Depreciated') {
+ frm.add_custom_button(__("Adjust Asset Value"), function() {
+ frm.trigger("create_asset_adjustment");
+ }, __("Manage"));
+ }
+
+ if (!frm.doc.calculate_depreciation) {
+ frm.add_custom_button(__("Create Depreciation Entry"), function() {
+ frm.trigger("make_journal_entry");
+ }, __("Manage"));
}
if (frm.doc.purchase_receipt || !frm.doc.is_existing_asset) {
- frm.add_custom_button("General Ledger", function() {
+ frm.add_custom_button("View General Ledger", function() {
frappe.route_options = {
"voucher_no": frm.doc.name,
"from_date": frm.doc.available_for_use_date,
@@ -107,27 +129,10 @@ frappe.ui.form.on('Asset', {
"company": frm.doc.company
};
frappe.set_route("query-report", "General Ledger");
- });
+ }, __("Manage"));
}
- if (frm.doc.maintenance_required && !frm.doc.maintenance_schedule) {
- frm.add_custom_button(__("Asset Maintenance"), function() {
- frm.trigger("create_asset_maintenance");
- }, __('Create'));
- }
- if (frm.doc.status != 'Fully Depreciated') {
- frm.add_custom_button(__("Asset Value Adjustment"), function() {
- frm.trigger("create_asset_adjustment");
- }, __('Create'));
- }
-
- if (!frm.doc.calculate_depreciation) {
- frm.add_custom_button(__("Depreciation Entry"), function() {
- frm.trigger("make_journal_entry");
- }, __('Create'));
- }
-
- frm.page.set_inner_btn_group_as_primary(__('Create'));
+ frm.page.set_inner_btn_group_as_primary(__("Manage"));
frm.trigger("setup_chart");
}
@@ -304,6 +309,20 @@ frappe.ui.form.on('Asset', {
})
},
+ create_asset_repair: function(frm) {
+ frappe.call({
+ args: {
+ "asset": frm.doc.name,
+ "asset_name": frm.doc.asset_name
+ },
+ method: "erpnext.assets.doctype.asset.asset.create_asset_repair",
+ callback: function(r) {
+ var doclist = frappe.model.sync(r.message);
+ frappe.set_route("Form", doclist[0].doctype, doclist[0].name);
+ }
+ })
+ },
+
create_asset_adjustment: function(frm) {
frappe.call({
args: {
diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py
index 8799275fc4..456649fa07 100644
--- a/erpnext/assets/doctype/asset/asset.py
+++ b/erpnext/assets/doctype/asset/asset.py
@@ -625,9 +625,18 @@ def create_asset_maintenance(asset, item_code, item_name, asset_category, compan
})
return asset_maintenance
+@frappe.whitelist()
+def create_asset_repair(asset, asset_name):
+ asset_repair = frappe.new_doc("Asset Repair")
+ asset_repair.update({
+ "asset": asset,
+ "asset_name": asset_name
+ })
+ return asset_repair
+
@frappe.whitelist()
def create_asset_adjustment(asset, asset_category, company):
- asset_maintenance = frappe.new_doc("Asset Value Adjustment")
+ asset_maintenance = frappe.get_doc("Asset Value Adjustment")
asset_maintenance.update({
"asset": asset,
"company": company,
diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.json b/erpnext/assets/doctype/asset_repair/asset_repair.json
index d338fc0fb7..853534eb31 100644
--- a/erpnext/assets/doctype/asset_repair/asset_repair.json
+++ b/erpnext/assets/doctype/asset_repair/asset_repair.json
@@ -8,10 +8,9 @@
"engine": "InnoDB",
"field_order": [
"naming_series",
- "asset_name",
"column_break_2",
- "item_code",
- "item_name",
+ "asset",
+ "asset_name",
"section_break_5",
"failure_date",
"assign_to",
@@ -30,15 +29,6 @@
"amended_from"
],
"fields": [
- {
- "columns": 1,
- "fieldname": "asset_name",
- "fieldtype": "Link",
- "in_list_view": 1,
- "label": "Asset",
- "options": "Asset",
- "reqd": 1
- },
{
"fieldname": "naming_series",
"fieldtype": "Select",
@@ -50,18 +40,6 @@
"fieldname": "column_break_2",
"fieldtype": "Column Break"
},
- {
- "fetch_from": "asset_name.item_code",
- "fieldname": "item_code",
- "fieldtype": "Read Only",
- "label": "Item Code"
- },
- {
- "fetch_from": "asset_name.item_name",
- "fieldname": "item_name",
- "fieldtype": "Read Only",
- "label": "Item Name"
- },
{
"fieldname": "section_break_5",
"fieldtype": "Section Break",
@@ -159,12 +137,26 @@
"options": "Asset Repair",
"print_hide": 1,
"read_only": 1
+ },
+ {
+ "columns": 1,
+ "fieldname": "asset",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Asset",
+ "options": "Asset",
+ "reqd": 1
+ },
+ {
+ "fieldname": "asset_name",
+ "fieldtype": "Read Only",
+ "label": "Asset Name"
}
],
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
- "modified": "2021-01-22 15:08:12.495850",
+ "modified": "2021-05-10 22:48:42.165513",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Repair",
From 58bc967073255a6e28eac76d4776810553ea0aa1 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Fri, 9 Jul 2021 22:10:35 +0530
Subject: [PATCH 029/386] fix: Rename 'Fixed Asset Depreciation Settings' to
'Fixed Asset Deafults'
---
.../doctype/asset_repair/asset_repair.js | 4 ++++
.../doctype/asset_repair/asset_repair.json | 22 +++++++++++++++++--
.../doctype/asset_repair/asset_repair.py | 4 ++++
erpnext/setup/doctype/company/company.json | 16 +++++++-------
4 files changed, 36 insertions(+), 10 deletions(-)
diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.js b/erpnext/assets/doctype/asset_repair/asset_repair.js
index 4ba2b4474a..f5eeeda5fb 100644
--- a/erpnext/assets/doctype/asset_repair/asset_repair.js
+++ b/erpnext/assets/doctype/asset_repair/asset_repair.js
@@ -2,6 +2,10 @@
// For license information, please see license.txt
frappe.ui.form.on('Asset Repair', {
+ refresh: function(frm) {
+ frm.toggle_display(['completion_date', 'repair_status'], !(frm.doc.__islocal));
+ },
+
repair_status: (frm) => {
if (frm.doc.completion_date && frm.doc.repair_status == "Completed") {
frappe.call ({
diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.json b/erpnext/assets/doctype/asset_repair/asset_repair.json
index 853534eb31..4ed9916392 100644
--- a/erpnext/assets/doctype/asset_repair/asset_repair.json
+++ b/erpnext/assets/doctype/asset_repair/asset_repair.json
@@ -7,9 +7,9 @@
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
+ "asset",
"naming_series",
"column_break_2",
- "asset",
"asset_name",
"section_break_5",
"failure_date",
@@ -18,7 +18,10 @@
"column_break_6",
"completion_date",
"repair_status",
+ "section_break_7",
"repair_cost",
+ "column_break_8",
+ "payable_account",
"section_break_9",
"description",
"column_break_9",
@@ -151,12 +154,27 @@
"fieldname": "asset_name",
"fieldtype": "Read Only",
"label": "Asset Name"
+ },
+ {
+ "fieldname": "payable_account",
+ "fieldtype": "Link",
+ "label": "Payable Account",
+ "options": "Account"
+ },
+ {
+ "fieldname": "section_break_7",
+ "fieldtype": "Section Break",
+ "label": "Accounting Details"
+ },
+ {
+ "fieldname": "column_break_8",
+ "fieldtype": "Column Break"
}
],
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
- "modified": "2021-05-10 22:48:42.165513",
+ "modified": "2021-05-11 05:11:58.330860",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Repair",
diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.py b/erpnext/assets/doctype/asset_repair/asset_repair.py
index 049b931b5e..884dc19588 100644
--- a/erpnext/assets/doctype/asset_repair/asset_repair.py
+++ b/erpnext/assets/doctype/asset_repair/asset_repair.py
@@ -13,6 +13,10 @@ class AssetRepair(Document):
if self.repair_status == "Completed" and not self.completion_date:
frappe.throw(_("Please select Completion Date for Completed Repair"))
+ if self.repair_status == 'Pending':
+ frappe.db.set_value('Asset', self.asset, 'status', 'Out of Order')
+ else:
+ frappe.db.set_value('Asset', self.asset, 'status', 'Submitted')
@frappe.whitelist()
def get_downtime(failure_date, completion_date):
diff --git a/erpnext/setup/doctype/company/company.json b/erpnext/setup/doctype/company/company.json
index 061986d92d..2d2f336e93 100644
--- a/erpnext/setup/doctype/company/company.json
+++ b/erpnext/setup/doctype/company/company.json
@@ -74,7 +74,7 @@
"stock_received_but_not_billed",
"service_received_but_not_billed",
"expenses_included_in_valuation",
- "fixed_asset_depreciation_settings",
+ "fixed_asset_defaults",
"accumulated_depreciation_account",
"depreciation_expense_account",
"series_for_depreciation_entry",
@@ -519,12 +519,6 @@
"no_copy": 1,
"options": "Account"
},
- {
- "collapsible": 1,
- "fieldname": "fixed_asset_depreciation_settings",
- "fieldtype": "Section Break",
- "label": "Fixed Asset Depreciation Settings"
- },
{
"fieldname": "accumulated_depreciation_account",
"fieldtype": "Link",
@@ -734,6 +728,12 @@
"fieldtype": "Link",
"label": "Default Payment Discount Account",
"options": "Account"
+ },
+ {
+ "collapsible": 1,
+ "fieldname": "fixed_asset_defaults",
+ "fieldtype": "Section Break",
+ "label": "Fixed Asset Defaults"
}
],
"icon": "fa fa-building",
@@ -741,7 +741,7 @@
"image_field": "company_logo",
"is_tree": 1,
"links": [],
- "modified": "2021-05-07 03:11:28.189740",
+ "modified": "2021-05-11 21:45:22.803065",
"modified_by": "Administrator",
"module": "Setup",
"name": "Company",
From 42c70fba3c7c645b308d1f6f84123037a8466712 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Fri, 9 Jul 2021 22:11:50 +0530
Subject: [PATCH 030/386] fix: Modify depreciation schedule when
increase_in_asset_life is not a multiple of frequency_of_depreciation)
---
erpnext/assets/doctype/asset/asset.js | 1 -
erpnext/assets/doctype/asset/asset.json | 23 ++-
erpnext/assets/doctype/asset/asset.py | 31 +++-
.../asset_maintenance/asset_maintenance.js | 3 +
.../asset_maintenance/asset_maintenance.json | 31 +++-
.../asset_maintenance/asset_maintenance.py | 37 ++++-
.../doctype/asset_repair/asset_repair.js | 11 +-
.../doctype/asset_repair/asset_repair.json | 127 ++++++++++----
.../doctype/asset_repair/asset_repair.py | 157 +++++++++++++++++-
erpnext/assets/doctype/stock_item/__init__.py | 0
.../assets/doctype/stock_item/stock_item.json | 55 ++++++
.../assets/doctype/stock_item/stock_item.py | 8 +
erpnext/setup/doctype/company/company.json | 9 +-
13 files changed, 444 insertions(+), 49 deletions(-)
create mode 100644 erpnext/assets/doctype/stock_item/__init__.py
create mode 100644 erpnext/assets/doctype/stock_item/stock_item.json
create mode 100644 erpnext/assets/doctype/stock_item/stock_item.py
diff --git a/erpnext/assets/doctype/asset/asset.js b/erpnext/assets/doctype/asset/asset.js
index 2a57183a80..1e67ec816b 100644
--- a/erpnext/assets/doctype/asset/asset.js
+++ b/erpnext/assets/doctype/asset/asset.js
@@ -132,7 +132,6 @@ frappe.ui.form.on('Asset', {
}, __("Manage"));
}
- frm.page.set_inner_btn_group_as_primary(__("Manage"));
frm.trigger("setup_chart");
}
diff --git a/erpnext/assets/doctype/asset/asset.json b/erpnext/assets/doctype/asset/asset.json
index 421b9a6c37..8a0e3ad2a6 100644
--- a/erpnext/assets/doctype/asset/asset.json
+++ b/erpnext/assets/doctype/asset/asset.json
@@ -23,6 +23,7 @@
"asset_name",
"asset_category",
"location",
+ "asset_value",
"custodian",
"department",
"disposal_date",
@@ -53,6 +54,8 @@
"next_depreciation_date",
"section_break_14",
"schedules",
+ "to_date",
+ "edit_dates",
"insurance_details",
"policy_number",
"insurer",
@@ -480,6 +483,24 @@
"fieldname": "section_break_36",
"fieldtype": "Section Break",
"label": "Finance Books"
+ },
+ {
+ "fieldname": "asset_value",
+ "fieldtype": "Currency",
+ "label": "Asset Value",
+ "read_only": 1
+ },
+ {
+ "fieldname": "to_date",
+ "fieldtype": "Date",
+ "hidden": 1,
+ "label": "To Date"
+ },
+ {
+ "fieldname": "edit_dates",
+ "fieldtype": "Data",
+ "hidden": 1,
+ "label": "Edit Dates"
}
],
"idx": 72,
@@ -502,7 +523,7 @@
"link_fieldname": "asset"
}
],
- "modified": "2021-01-22 12:38:59.091510",
+ "modified": "2021-05-21 12:05:29.424083",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset",
diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py
index 456649fa07..e8cfe0ae17 100644
--- a/erpnext/assets/doctype/asset/asset.py
+++ b/erpnext/assets/doctype/asset/asset.py
@@ -96,6 +96,9 @@ class Asset(AccountsController):
finance_books = get_item_details(self.item_code, self.asset_category)
self.set('finance_books', finance_books)
+ if not(self.asset_value):
+ self.asset_value = self.gross_purchase_amount
+
def validate_asset_values(self):
if not self.asset_category:
self.asset_category = frappe.get_cached_value("Item", self.item_code, "asset_category")
@@ -168,15 +171,23 @@ class Asset(AccountsController):
d.precision("rate_of_depreciation"))
def make_depreciation_schedule(self):
- if 'Manual' not in [d.depreciation_method for d in self.finance_books]:
+ if 'Manual' not in [d.depreciation_method for d in self.finance_books] and not self.schedules:
self.schedules = []
- if self.get("schedules") or not self.available_for_use_date:
+ if not self.available_for_use_date:
return
for d in self.get('finance_books'):
self.validate_asset_finance_books(d)
+ start = 0
+ for n in range (len(self.schedules)):
+ if not self.schedules[n].journal_entry:
+ print("*"*100)
+ del self.schedules[n:]
+ start = n
+ break
+
value_after_depreciation = (flt(self.gross_purchase_amount) -
flt(self.opening_accumulated_depreciation))
@@ -189,9 +200,9 @@ class Asset(AccountsController):
if has_pro_rata:
number_of_pending_depreciations += 1
-
+
skip_row = False
- for n in range(number_of_pending_depreciations):
+ for n in range(start, number_of_pending_depreciations):
# If depreciation is already completed (for double declining balance)
if skip_row: continue
@@ -216,11 +227,12 @@ class Asset(AccountsController):
# For last row
elif has_pro_rata and n == cint(number_of_pending_depreciations) - 1:
- to_date = add_months(self.available_for_use_date,
- n * cint(d.frequency_of_depreciation))
+ if not self.edit_dates:
+ self.to_date = add_months(self.available_for_use_date,
+ n * cint(d.frequency_of_depreciation))
- depreciation_amount, days, months = self.get_pro_rata_amt(d,
- depreciation_amount, schedule_date, to_date)
+ depreciation_amount, days, months = get_pro_rata_amt(d,
+ depreciation_amount, schedule_date, self.to_date)
monthly_schedule_date = add_months(schedule_date, 1)
@@ -346,11 +358,12 @@ class Asset(AccountsController):
if d.finance_book_id not in finance_books:
accumulated_depreciation = flt(self.opening_accumulated_depreciation)
value_after_depreciation = flt(self.get_value_after_depreciation(d.finance_book_id))
- finance_books.append(d.finance_book_id)
+ finance_books.append(int(d.finance_book_id))
depreciation_amount = flt(d.depreciation_amount, d.precision("depreciation_amount"))
value_after_depreciation -= flt(depreciation_amount)
+ # for the last row, if depreciation method = Straight Line
if straight_line_idx and i == max(straight_line_idx) - 1:
book = self.get('finance_books')[cint(d.finance_book_id) - 1]
depreciation_amount += flt(value_after_depreciation -
diff --git a/erpnext/assets/doctype/asset_maintenance/asset_maintenance.js b/erpnext/assets/doctype/asset_maintenance/asset_maintenance.js
index 70b8654509..3830d1168c 100644
--- a/erpnext/assets/doctype/asset_maintenance/asset_maintenance.js
+++ b/erpnext/assets/doctype/asset_maintenance/asset_maintenance.js
@@ -30,7 +30,10 @@ frappe.ui.form.on('Asset Maintenance', {
if(!frm.is_new()) {
frm.trigger('make_dashboard');
}
+
+ frm.toggle_display(['stock_consumption_details_section'], frm.doc.stock_consumption)
},
+
make_dashboard: (frm) => {
if(!frm.is_new()) {
frappe.call({
diff --git a/erpnext/assets/doctype/asset_maintenance/asset_maintenance.json b/erpnext/assets/doctype/asset_maintenance/asset_maintenance.json
index c0c2566fe2..da2fd75451 100644
--- a/erpnext/assets/doctype/asset_maintenance/asset_maintenance.json
+++ b/erpnext/assets/doctype/asset_maintenance/asset_maintenance.json
@@ -12,13 +12,17 @@
"column_break_3",
"item_code",
"item_name",
+ "stock_consumption",
"section_break_6",
"maintenance_team",
"column_break_9",
"maintenance_manager",
"maintenance_manager_name",
"section_break_8",
- "asset_maintenance_tasks"
+ "asset_maintenance_tasks",
+ "stock_consumption_details_section",
+ "warehouse",
+ "stock_items"
],
"fields": [
{
@@ -100,10 +104,33 @@
"label": "Maintenance Tasks",
"options": "Asset Maintenance Task",
"reqd": 1
+ },
+ {
+ "default": "0",
+ "fieldname": "stock_consumption",
+ "fieldtype": "Check",
+ "label": "Stock Consumed During Maintenance"
+ },
+ {
+ "fieldname": "stock_consumption_details_section",
+ "fieldtype": "Section Break",
+ "label": "Stock Consumption Details"
+ },
+ {
+ "fieldname": "warehouse",
+ "fieldtype": "Link",
+ "label": "Warehouse",
+ "options": "Warehouse"
+ },
+ {
+ "fieldname": "stock_items",
+ "fieldtype": "Table",
+ "label": "Stock Items",
+ "options": "Stock Item"
}
],
"links": [],
- "modified": "2020-05-28 20:28:32.993823",
+ "modified": "2021-05-13 05:24:58.480132",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Maintenance",
diff --git a/erpnext/assets/doctype/asset_maintenance/asset_maintenance.py b/erpnext/assets/doctype/asset_maintenance/asset_maintenance.py
index a506deec93..e3e654c398 100644
--- a/erpnext/assets/doctype/asset_maintenance/asset_maintenance.py
+++ b/erpnext/assets/doctype/asset_maintenance/asset_maintenance.py
@@ -19,10 +19,45 @@ class AssetMaintenance(Document):
if not task.assign_to and self.docstatus == 0:
throw(_("Row #{}: Please asign task to a member.").format(task.idx))
+ if self.stock_consumption:
+ self.check_for_stock_items_and_warehouse()
+ self.increase_asset_value()
+ self.decrease_stock_quantity()
+
def on_update(self):
for task in self.get('asset_maintenance_tasks'):
assign_tasks(self.name, task.assign_to, task.maintenance_task, task.next_due_date)
- self.sync_maintenance_tasks()
+ self.sync_maintenance_tasks()
+
+ def check_for_stock_items_and_warehouse(self):
+ if self.stock_consumption:
+ if not self.stock_items:
+ frappe.throw(_("Please enter Stock Items consumed during Asset Maintenance."))
+ if not self.warehouse:
+ frappe.throw(_("Please enter Warehouse from which Stock Items consumed during Asset Maintenance were taken."))
+
+ def increase_asset_value(self):
+ asset_value = frappe.db.get_value('Asset', self.asset_name, 'asset_value')
+ for item in self.stock_items:
+ asset_value += item.total_value
+
+ frappe.db.set_value('Asset', self.asset_name, 'asset_value', asset_value)
+
+ def decrease_stock_quantity(self):
+ stock_entry = frappe.get_doc({
+ "doctype": "Stock Entry",
+ "stock_entry_type": "Material Issue"
+ })
+
+ for stock_item in self.stock_items:
+ stock_entry.append('items', {
+ "s_warehouse": self.warehouse,
+ "item_code": stock_item.item,
+ "qty": stock_item.consumed_quantity
+ })
+
+ stock_entry.insert()
+ stock_entry.submit()
def sync_maintenance_tasks(self):
tasks_names = []
diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.js b/erpnext/assets/doctype/asset_repair/asset_repair.js
index f5eeeda5fb..7633a595a2 100644
--- a/erpnext/assets/doctype/asset_repair/asset_repair.js
+++ b/erpnext/assets/doctype/asset_repair/asset_repair.js
@@ -3,7 +3,16 @@
frappe.ui.form.on('Asset Repair', {
refresh: function(frm) {
- frm.toggle_display(['completion_date', 'repair_status'], !(frm.doc.__islocal));
+ frm.toggle_display(['completion_date', 'repair_status', 'accounting_details', 'accounting_dimensions_section'], !(frm.doc.__islocal));
+
+ if (frm.doc.docstatus) {
+ frm.add_custom_button("View General Ledger", function() {
+ frappe.route_options = {
+ "voucher_no": frm.doc.name
+ };
+ frappe.set_route("query-report", "General Ledger");
+ });
+ }
},
repair_status: (frm) => {
diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.json b/erpnext/assets/doctype/asset_repair/asset_repair.json
index 4ed9916392..522f2874d9 100644
--- a/erpnext/assets/doctype/asset_repair/asset_repair.json
+++ b/erpnext/assets/doctype/asset_repair/asset_repair.json
@@ -13,20 +13,30 @@
"asset_name",
"section_break_5",
"failure_date",
- "assign_to",
- "assign_to_name",
+ "repair_status",
"column_break_6",
"completion_date",
- "repair_status",
- "section_break_7",
+ "accounting_dimensions_section",
+ "cost_center",
+ "column_break_14",
+ "project",
+ "accounting_details",
"repair_cost",
+ "capitalize_repair_cost",
+ "stock_consumption",
"column_break_8",
- "payable_account",
+ "total_repair_cost",
+ "purchase_invoice",
+ "stock_consumption_details_section",
+ "warehouse",
+ "stock_items",
+ "asset_depreciation_details_section",
+ "increase_in_asset_life",
"section_break_9",
"description",
"column_break_9",
"actions_performed",
- "section_break_17",
+ "section_break_23",
"downtime",
"column_break_19",
"amended_from"
@@ -55,20 +65,6 @@
"label": "Failure Date",
"reqd": 1
},
- {
- "allow_on_submit": 1,
- "fieldname": "assign_to",
- "fieldtype": "Link",
- "label": "Assign To",
- "options": "User"
- },
- {
- "allow_on_submit": 1,
- "fetch_from": "assign_to.full_name",
- "fieldname": "assign_to_name",
- "fieldtype": "Read Only",
- "label": "Assign To Name"
- },
{
"fieldname": "column_break_6",
"fieldtype": "Column Break"
@@ -110,10 +106,6 @@
"fieldtype": "Long Text",
"label": "Actions performed"
},
- {
- "fieldname": "section_break_17",
- "fieldtype": "Section Break"
- },
{
"allow_on_submit": 1,
"fieldname": "downtime",
@@ -151,30 +143,103 @@
"reqd": 1
},
{
+ "fetch_from": "asset.asset_name",
"fieldname": "asset_name",
"fieldtype": "Read Only",
"label": "Asset Name"
},
{
- "fieldname": "payable_account",
- "fieldtype": "Link",
- "label": "Payable Account",
- "options": "Account"
+ "fieldname": "column_break_8",
+ "fieldtype": "Column Break"
},
{
- "fieldname": "section_break_7",
+ "default": "0",
+ "fieldname": "capitalize_repair_cost",
+ "fieldtype": "Check",
+ "label": "Capitalize Repair Cost"
+ },
+ {
+ "fieldname": "accounting_details",
"fieldtype": "Section Break",
"label": "Accounting Details"
},
{
- "fieldname": "column_break_8",
+ "fieldname": "stock_items",
+ "fieldtype": "Table",
+ "label": "Stock Items",
+ "options": "Stock Item"
+ },
+ {
+ "fieldname": "section_break_23",
+ "fieldtype": "Section Break"
+ },
+ {
+ "fieldname": "accounting_dimensions_section",
+ "fieldtype": "Section Break",
+ "label": "Accounting Dimensions"
+ },
+ {
+ "fieldname": "cost_center",
+ "fieldtype": "Link",
+ "label": "Cost Center",
+ "options": "Cost Center"
+ },
+ {
+ "fieldname": "project",
+ "fieldtype": "Link",
+ "label": "Project",
+ "options": "Project"
+ },
+ {
+ "fieldname": "column_break_14",
"fieldtype": "Column Break"
+ },
+ {
+ "default": "0",
+ "fieldname": "stock_consumption",
+ "fieldtype": "Check",
+ "label": "Stock Consumed During Repair"
+ },
+ {
+ "depends_on": "stock_consumption",
+ "fieldname": "stock_consumption_details_section",
+ "fieldtype": "Section Break",
+ "label": "Stock Consumption Details"
+ },
+ {
+ "depends_on": "stock_consumption",
+ "fieldname": "total_repair_cost",
+ "fieldtype": "Currency",
+ "label": "Total Repair Cost"
+ },
+ {
+ "fieldname": "warehouse",
+ "fieldtype": "Link",
+ "label": "Warehouse",
+ "options": "Warehouse"
+ },
+ {
+ "depends_on": "capitalize_repair_cost",
+ "fieldname": "asset_depreciation_details_section",
+ "fieldtype": "Section Break",
+ "label": "Asset Depreciation Details"
+ },
+ {
+ "fieldname": "increase_in_asset_life",
+ "fieldtype": "Int",
+ "label": "Increase In Asset Life(Months)"
+ },
+ {
+ "fieldname": "purchase_invoice",
+ "fieldtype": "Link",
+ "label": "Purchase Invoice",
+ "options": "Purchase Invoice"
}
],
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
- "modified": "2021-05-11 05:11:58.330860",
+ "modified": "2021-05-21 10:37:35.002238",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Repair",
diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.py b/erpnext/assets/doctype/asset_repair/asset_repair.py
index 884dc19588..8fd019febd 100644
--- a/erpnext/assets/doctype/asset_repair/asset_repair.py
+++ b/erpnext/assets/doctype/asset_repair/asset_repair.py
@@ -5,19 +5,172 @@
from __future__ import unicode_literals
import frappe
from frappe import _
-from frappe.utils import time_diff_in_hours
+from frappe.utils import time_diff_in_hours, getdate, add_days, date_diff, add_months, flt, cint
from frappe.model.document import Document
+from erpnext.accounts.general_ledger import make_gl_entries
class AssetRepair(Document):
def validate(self):
if self.repair_status == "Completed" and not self.completion_date:
frappe.throw(_("Please select Completion Date for Completed Repair"))
+ self.update_status()
+ self.set_total_value() # change later
+ self.calculate_total_repair_cost()
+
+ def update_status(self):
if self.repair_status == 'Pending':
frappe.db.set_value('Asset', self.asset, 'status', 'Out of Order')
else:
- frappe.db.set_value('Asset', self.asset, 'status', 'Submitted')
+ asset = frappe.get_doc('Asset', self.asset)
+ asset.set_status()
+ def set_total_value(self):
+ for item in self.stock_items:
+ item.total_value = flt(item.valuation_rate) * flt(item.consumed_quantity)
+
+ def calculate_total_repair_cost(self):
+ self.total_repair_cost = self.repair_cost
+ if self.stock_consumption:
+ for item in self.stock_items:
+ self.total_repair_cost += item.total_value
+
+ def on_submit(self):
+ self.check_repair_status()
+ self.check_for_cost_center()
+
+ if self.stock_consumption or self.capitalize_repair_cost:
+ self.increase_asset_value()
+ if self.stock_consumption:
+ self.check_for_stock_items_and_warehouse()
+ self.decrease_stock_quantity()
+ if self.capitalize_repair_cost:
+ self.check_for_purchase_invoice()
+ self.make_gl_entries()
+ self.modify_depreciation_schedule()
+
+ def check_repair_status(self):
+ if self.repair_status == "Pending":
+ frappe.throw(_("Please update Repair Status."))
+
+ def check_for_stock_items_and_warehouse(self):
+ if not self.stock_items:
+ frappe.throw(_("Please enter Stock Items consumed during Asset Repair."))
+ if not self.warehouse:
+ frappe.throw(_("Please enter Warehouse from which Stock Items consumed during Asset Repair were taken."))
+
+ def check_for_cost_center(self):
+ if not self.cost_center:
+ frappe.throw(_("Please enter Cost Center."))
+
+ def increase_asset_value(self):
+ asset_value = frappe.db.get_value('Asset', self.asset, 'asset_value')
+ for item in self.stock_items:
+ asset_value += item.total_value
+
+ if self.capitalize_repair_cost:
+ asset_value += self.repair_cost
+ frappe.db.set_value('Asset', self.asset, 'asset_value', asset_value)
+
+ def decrease_stock_quantity(self):
+ stock_entry = frappe.get_doc({
+ "doctype": "Stock Entry",
+ "stock_entry_type": "Material Issue"
+ })
+
+ for stock_item in self.stock_items:
+ stock_entry.append('items', {
+ "s_warehouse": self.warehouse,
+ "item_code": stock_item.item,
+ "qty": stock_item.consumed_quantity
+ })
+
+ stock_entry.insert()
+ stock_entry.submit()
+
+ def check_for_purchase_invoice(self):
+ if not self.purchase_invoice:
+ frappe.throw(_("Please link Purchase Invoice."))
+
+ def on_cancel(self):
+ self.make_gl_entries(cancel=True)
+
+ def make_gl_entries(self, cancel=False):
+ if flt(self.repair_cost) > 0:
+ gl_entries = self.get_gl_entries()
+ make_gl_entries(gl_entries, cancel)
+
+ def get_gl_entries(self):
+ gl_entry = []
+ company = frappe.db.get_value('Asset', self.asset, 'company')
+ repair_and_maintenance_account = frappe.db.get_value('Company', company, 'repair_and_maintenance_account')
+ fixed_asset_account = self.get_fixed_asset_account()
+ expense_account = frappe.get_doc('Purchase Invoice', self.purchase_invoice).items[0].expense_account
+
+ gl_entry = frappe.get_doc({
+ "doctype": "GL Entry",
+ "account": expense_account,
+ "credit": self.total_repair_cost,
+ "credit_in_account_currency": self.total_repair_cost,
+ "against": repair_and_maintenance_account,
+ "voucher_type": self.doctype,
+ "voucher_no": self.name,
+ "cost_center": self.cost_center,
+ "posting_date": getdate()
+ })
+ gl_entry.insert()
+ gl_entry = frappe.get_doc({
+ "doctype": "GL Entry",
+ "account": fixed_asset_account,
+ "debit": self.total_repair_cost,
+ "debit_in_account_currency": self.total_repair_cost,
+ "against": expense_account,
+ "voucher_type": self.doctype,
+ "voucher_no": self.name,
+ "cost_center": self.cost_center,
+ "posting_date": getdate(),
+ "against_voucher_type": "Purchase Invoice",
+ "against_voucher": self.purchase_invoice
+ })
+ gl_entry.insert()
+
+ def get_fixed_asset_account(self):
+ asset_category = frappe.get_doc('Asset Category', frappe.db.get_value('Asset', self.asset, 'asset_category'))
+ company = frappe.db.get_value('Asset', self.asset, 'company')
+ for account in asset_category.accounts:
+ if account.company_name == company:
+ return account.fixed_asset_account
+
+ def modify_depreciation_schedule(self):
+ if self.increase_in_asset_life:
+ asset = frappe.get_doc('Asset', self.asset)
+ asset.flags.ignore_validate_update_after_submit = True
+ for row in asset.finance_books:
+ row.total_number_of_depreciations += self.increase_in_asset_life/row.frequency_of_depreciation
+
+ asset.edit_dates = ""
+ extra_months = self.increase_in_asset_life % row.frequency_of_depreciation
+ if extra_months != 0:
+ self.calculate_last_schedule_date(asset, row, extra_months)
+ # fix depreciation amount
+
+ asset.prepare_depreciation_data()
+ asset.save()
+
+ # to help modify depreciation schedule when increase_in_asset_life is not a multiple of frequency_of_depreciation
+ def calculate_last_schedule_date(self, asset, row, extra_months):
+ asset.edit_dates = "Don't Edit"
+ number_of_pending_depreciations = cint(row.total_number_of_depreciations) - \
+ cint(asset.number_of_depreciations_booked)
+ last_schedule_date = asset.schedules[len(asset.schedules)-1].schedule_date
+ asset.to_date = add_months(last_schedule_date, extra_months)
+ schedule_date = add_months(row.depreciation_start_date,
+ number_of_pending_depreciations * cint(row.frequency_of_depreciation))
+
+ if asset.to_date > schedule_date:
+ row.total_number_of_depreciations += 1
+
+
@frappe.whitelist()
def get_downtime(failure_date, completion_date):
downtime = time_diff_in_hours(completion_date, failure_date)
diff --git a/erpnext/assets/doctype/stock_item/__init__.py b/erpnext/assets/doctype/stock_item/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/assets/doctype/stock_item/stock_item.json b/erpnext/assets/doctype/stock_item/stock_item.json
new file mode 100644
index 0000000000..b1f05db395
--- /dev/null
+++ b/erpnext/assets/doctype/stock_item/stock_item.json
@@ -0,0 +1,55 @@
+{
+ "actions": [],
+ "creation": "2021-05-12 02:41:54.161024",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "item",
+ "valuation_rate",
+ "consumed_quantity",
+ "total_value"
+ ],
+ "fields": [
+ {
+ "fieldname": "item",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Item",
+ "options": "Item"
+ },
+ {
+ "fetch_from": "item.valuation_rate",
+ "fieldname": "valuation_rate",
+ "fieldtype": "Currency",
+ "in_list_view": 1,
+ "label": "Valuation Rate",
+ "read_only": 1
+ },
+ {
+ "fieldname": "consumed_quantity",
+ "fieldtype": "Data",
+ "in_list_view": 1,
+ "label": "Consumed Quantity"
+ },
+ {
+ "fieldname": "total_value",
+ "fieldtype": "Currency",
+ "in_list_view": 1,
+ "label": "Total Value",
+ "read_only": 1
+ }
+ ],
+ "index_web_pages_for_search": 1,
+ "istable": 1,
+ "links": [],
+ "modified": "2021-05-12 03:19:55.006300",
+ "modified_by": "Administrator",
+ "module": "Assets",
+ "name": "Stock Item",
+ "owner": "Administrator",
+ "permissions": [],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/assets/doctype/stock_item/stock_item.py b/erpnext/assets/doctype/stock_item/stock_item.py
new file mode 100644
index 0000000000..0e3cc3f8ba
--- /dev/null
+++ b/erpnext/assets/doctype/stock_item/stock_item.py
@@ -0,0 +1,8 @@
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+# import frappe
+from frappe.model.document import Document
+
+class StockItem(Document):
+ pass
diff --git a/erpnext/setup/doctype/company/company.json b/erpnext/setup/doctype/company/company.json
index 2d2f336e93..e6ec496a65 100644
--- a/erpnext/setup/doctype/company/company.json
+++ b/erpnext/setup/doctype/company/company.json
@@ -83,6 +83,7 @@
"disposal_account",
"depreciation_cost_center",
"capital_work_in_progress_account",
+ "repair_and_maintenance_account",
"asset_received_but_not_billed",
"budget_detail",
"exception_budget_approver_role",
@@ -734,6 +735,12 @@
"fieldname": "fixed_asset_defaults",
"fieldtype": "Section Break",
"label": "Fixed Asset Defaults"
+ },
+ {
+ "fieldname": "repair_and_maintenance_account",
+ "fieldtype": "Link",
+ "label": "Repair and Maintenance Account",
+ "options": "Account"
}
],
"icon": "fa fa-building",
@@ -741,7 +748,7 @@
"image_field": "company_logo",
"is_tree": 1,
"links": [],
- "modified": "2021-05-11 21:45:22.803065",
+ "modified": "2021-05-12 16:51:08.187233",
"modified_by": "Administrator",
"module": "Setup",
"name": "Company",
From 4e284433d17e7830c8c4a33885c2d82db689b926 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Fri, 9 Jul 2021 22:12:46 +0530
Subject: [PATCH 031/386] fix: Fix depreciation_amount calculation
---
erpnext/assets/doctype/asset/asset.py | 15 +++++++++------
.../assets/doctype/asset_repair/asset_repair.py | 1 -
2 files changed, 9 insertions(+), 7 deletions(-)
diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py
index e8cfe0ae17..3bd20023ab 100644
--- a/erpnext/assets/doctype/asset/asset.py
+++ b/erpnext/assets/doctype/asset/asset.py
@@ -183,13 +183,12 @@ class Asset(AccountsController):
start = 0
for n in range (len(self.schedules)):
if not self.schedules[n].journal_entry:
- print("*"*100)
del self.schedules[n:]
start = n
break
- value_after_depreciation = (flt(self.gross_purchase_amount) -
- flt(self.opening_accumulated_depreciation))
+ value_after_depreciation = (flt(self.asset_value) -
+ flt(self.opening_accumulated_depreciation)) - flt(d.expected_value_after_useful_life)
d.value_after_depreciation = value_after_depreciation
@@ -779,9 +778,13 @@ def get_depreciation_amount(asset, depreciable_value, row):
depreciation_left = flt(row.total_number_of_depreciations) - flt(asset.number_of_depreciations_booked)
if row.depreciation_method in ("Straight Line", "Manual"):
- depreciation_amount = (flt(row.value_after_depreciation) -
- flt(row.expected_value_after_useful_life)) / depreciation_left
+ if not asset.to_date:
+ depreciation_amount = (flt(row.value_after_depreciation) -
+ flt(row.expected_value_after_useful_life)) / depreciation_left
+ else:
+ depreciation_amount = (flt(row.value_after_depreciation) -
+ flt(row.expected_value_after_useful_life)) / (date_diff(asset.to_date, asset.available_for_use_date) / 365)
else:
depreciation_amount = flt(depreciable_value * (flt(row.rate_of_depreciation) / 100))
- return depreciation_amount
\ No newline at end of file
+ return depreciation_amount
diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.py b/erpnext/assets/doctype/asset_repair/asset_repair.py
index 8fd019febd..9973afd80a 100644
--- a/erpnext/assets/doctype/asset_repair/asset_repair.py
+++ b/erpnext/assets/doctype/asset_repair/asset_repair.py
@@ -152,7 +152,6 @@ class AssetRepair(Document):
extra_months = self.increase_in_asset_life % row.frequency_of_depreciation
if extra_months != 0:
self.calculate_last_schedule_date(asset, row, extra_months)
- # fix depreciation amount
asset.prepare_depreciation_data()
asset.save()
From 97193a46324dd0c10650e4f51111eea323555602 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Fri, 9 Jul 2021 22:15:10 +0530
Subject: [PATCH 032/386] fix: Sider issues
---
erpnext/assets/doctype/asset/asset.js | 2 +-
erpnext/assets/doctype/asset/asset.py | 2 +-
erpnext/assets/doctype/asset_maintenance/asset_maintenance.js | 2 +-
erpnext/assets/doctype/asset_repair/asset_repair.py | 2 +-
4 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/erpnext/assets/doctype/asset/asset.js b/erpnext/assets/doctype/asset/asset.js
index 1e67ec816b..922cc4a7b2 100644
--- a/erpnext/assets/doctype/asset/asset.js
+++ b/erpnext/assets/doctype/asset/asset.js
@@ -319,7 +319,7 @@ frappe.ui.form.on('Asset', {
var doclist = frappe.model.sync(r.message);
frappe.set_route("Form", doclist[0].doctype, doclist[0].name);
}
- })
+ });
},
create_asset_adjustment: function(frm) {
diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py
index 3bd20023ab..b3d3a198c3 100644
--- a/erpnext/assets/doctype/asset/asset.py
+++ b/erpnext/assets/doctype/asset/asset.py
@@ -181,7 +181,7 @@ class Asset(AccountsController):
self.validate_asset_finance_books(d)
start = 0
- for n in range (len(self.schedules)):
+ for n in range(len(self.schedules)):
if not self.schedules[n].journal_entry:
del self.schedules[n:]
start = n
diff --git a/erpnext/assets/doctype/asset_maintenance/asset_maintenance.js b/erpnext/assets/doctype/asset_maintenance/asset_maintenance.js
index 3830d1168c..19393b7e9d 100644
--- a/erpnext/assets/doctype/asset_maintenance/asset_maintenance.js
+++ b/erpnext/assets/doctype/asset_maintenance/asset_maintenance.js
@@ -31,7 +31,7 @@ frappe.ui.form.on('Asset Maintenance', {
frm.trigger('make_dashboard');
}
- frm.toggle_display(['stock_consumption_details_section'], frm.doc.stock_consumption)
+ frm.toggle_display(['stock_consumption_details_section'], frm.doc.stock_consumption);
},
make_dashboard: (frm) => {
diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.py b/erpnext/assets/doctype/asset_repair/asset_repair.py
index 9973afd80a..3e81ba55b0 100644
--- a/erpnext/assets/doctype/asset_repair/asset_repair.py
+++ b/erpnext/assets/doctype/asset_repair/asset_repair.py
@@ -5,7 +5,7 @@
from __future__ import unicode_literals
import frappe
from frappe import _
-from frappe.utils import time_diff_in_hours, getdate, add_days, date_diff, add_months, flt, cint
+from frappe.utils import time_diff_in_hours, getdate, add_months, flt, cint
from frappe.model.document import Document
from erpnext.accounts.general_ledger import make_gl_entries
From 794807ecc3bb709a0cfdb0bb5ee7aa50c0399698 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Thu, 3 Jun 2021 04:55:49 +0530
Subject: [PATCH 033/386] fix(Asset Repair): Only modify depreciation schedule
if calculate_depreciation is checked
---
erpnext/assets/doctype/asset_repair/asset_repair.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.py b/erpnext/assets/doctype/asset_repair/asset_repair.py
index 3e81ba55b0..e3093df7fb 100644
--- a/erpnext/assets/doctype/asset_repair/asset_repair.py
+++ b/erpnext/assets/doctype/asset_repair/asset_repair.py
@@ -47,7 +47,8 @@ class AssetRepair(Document):
if self.capitalize_repair_cost:
self.check_for_purchase_invoice()
self.make_gl_entries()
- self.modify_depreciation_schedule()
+ if frappe.db.get_value('Asset', self.asset, 'calculate_depreciation'):
+ self.modify_depreciation_schedule()
def check_repair_status(self):
if self.repair_status == "Pending":
From c6ed66ec5b54b96a455452f33c927989fb9ab586 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Thu, 3 Jun 2021 21:07:07 +0530
Subject: [PATCH 034/386] fix(Asset Repair): Remove unnecessary condition
---
erpnext/assets/doctype/asset_repair/asset_repair.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.py b/erpnext/assets/doctype/asset_repair/asset_repair.py
index e3093df7fb..070e7b0a9b 100644
--- a/erpnext/assets/doctype/asset_repair/asset_repair.py
+++ b/erpnext/assets/doctype/asset_repair/asset_repair.py
@@ -72,7 +72,7 @@ class AssetRepair(Document):
if self.capitalize_repair_cost:
asset_value += self.repair_cost
frappe.db.set_value('Asset', self.asset, 'asset_value', asset_value)
-
+
def decrease_stock_quantity(self):
stock_entry = frappe.get_doc({
"doctype": "Stock Entry",
From 3f9f0ffdfe504646b09e76fe7554bf31816ca0d4 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Thu, 3 Jun 2021 21:28:58 +0530
Subject: [PATCH 035/386] fix(Asset Repair): Add Company in GL Entries
---
erpnext/assets/doctype/asset_repair/asset_repair.py | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.py b/erpnext/assets/doctype/asset_repair/asset_repair.py
index 070e7b0a9b..9f09643864 100644
--- a/erpnext/assets/doctype/asset_repair/asset_repair.py
+++ b/erpnext/assets/doctype/asset_repair/asset_repair.py
@@ -117,7 +117,8 @@ class AssetRepair(Document):
"voucher_type": self.doctype,
"voucher_no": self.name,
"cost_center": self.cost_center,
- "posting_date": getdate()
+ "posting_date": getdate(),
+ "company": company
})
gl_entry.insert()
gl_entry = frappe.get_doc({
@@ -131,7 +132,8 @@ class AssetRepair(Document):
"cost_center": self.cost_center,
"posting_date": getdate(),
"against_voucher_type": "Purchase Invoice",
- "against_voucher": self.purchase_invoice
+ "against_voucher": self.purchase_invoice,
+ "company": company
})
gl_entry.insert()
From 70de9744965045c6302ac63f0ec1eb3004c4efe5 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Thu, 3 Jun 2021 22:28:30 +0530
Subject: [PATCH 036/386] fix(Asset): Add depreciation schedule details in
create_asset()
---
erpnext/assets/doctype/asset/test_asset.py | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/erpnext/assets/doctype/asset/test_asset.py b/erpnext/assets/doctype/asset/test_asset.py
index 8845f24d10..29fbc9f15d 100644
--- a/erpnext/assets/doctype/asset/test_asset.py
+++ b/erpnext/assets/doctype/asset/test_asset.py
@@ -699,7 +699,7 @@ def create_asset(**args):
"item_code": args.item_code or "Macbook Pro",
"company": args.company or"_Test Company",
"purchase_date": "2015-01-01",
- "calculate_depreciation": 0,
+ "calculate_depreciation": args.calculate_depreciation or 0,
"gross_purchase_amount": 100000,
"purchase_receipt_amount": 100000,
"expected_value_after_useful_life": 10000,
@@ -710,6 +710,13 @@ def create_asset(**args):
"is_existing_asset": args.is_existing_asset or 0
})
+ if asset.calculate_depreciation:
+ asset.append("finance_books", {
+ "depreciation_method": "Straight Line",
+ "frequency_of_depreciation": 12,
+ "total_number_of_depreciations": 5
+ })
+
try:
asset.save()
except frappe.DuplicateEntryError:
From 2833903ce570abd3a2d5a68adf6dd5c4afac42b6 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Thu, 3 Jun 2021 22:28:57 +0530
Subject: [PATCH 037/386] fix(Asset Repair): Add tests
---
.../doctype/asset_repair/asset_repair.py | 1 -
.../doctype/asset_repair/test_asset_repair.py | 166 +++++++++++++++++-
2 files changed, 164 insertions(+), 3 deletions(-)
diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.py b/erpnext/assets/doctype/asset_repair/asset_repair.py
index 9f09643864..4ca6fbc5d0 100644
--- a/erpnext/assets/doctype/asset_repair/asset_repair.py
+++ b/erpnext/assets/doctype/asset_repair/asset_repair.py
@@ -172,7 +172,6 @@ class AssetRepair(Document):
if asset.to_date > schedule_date:
row.total_number_of_depreciations += 1
-
@frappe.whitelist()
def get_downtime(failure_date, completion_date):
downtime = time_diff_in_hours(completion_date, failure_date)
diff --git a/erpnext/assets/doctype/asset_repair/test_asset_repair.py b/erpnext/assets/doctype/asset_repair/test_asset_repair.py
index 3d325a9683..9c9dd44971 100644
--- a/erpnext/assets/doctype/asset_repair/test_asset_repair.py
+++ b/erpnext/assets/doctype/asset_repair/test_asset_repair.py
@@ -2,8 +2,170 @@
# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
from __future__ import unicode_literals
-
+import frappe
+from frappe.utils import nowdate, flt
import unittest
+from erpnext.assets.doctype.asset.test_asset import create_asset_data, create_asset, set_depreciation_settings_in_company
class TestAssetRepair(unittest.TestCase):
- pass
+ def setUp(self):
+ set_depreciation_settings_in_company()
+ create_asset_data()
+ frappe.db.sql("delete from `tabTax Rule`")
+
+ def test_completion_date(self):
+ asset_repair = create_asset_repair()
+ asset_repair.repair_status = "Completed"
+ asset_repair.save()
+ self.assertTrue(asset_repair.completion_date)
+
+ def test_update_status(self):
+ asset = create_asset()
+ initial_status = asset.status
+ asset_repair = create_asset_repair(asset = asset)
+
+ if asset_repair.repair_status == "Pending":
+ asset.reload()
+ self.assertEqual(asset.status, "Out of Order")
+
+ asset_repair.repair_status = "Completed"
+ asset_repair.save()
+ asset_status = frappe.db.get_value("Asset", asset_repair.asset, "status")
+ self.assertEqual(asset_status, initial_status)
+
+ def test_stock_item_total_value(self):
+ asset_repair = create_asset_repair(stock_consumption = 1)
+
+ for item in asset_repair.stock_items:
+ total_value = flt(item.valuation_rate) * flt(item.consumed_quantity)
+ self.assertEqual(item.total_value, total_value)
+
+ def test_total_repair_cost(self):
+ asset_repair = create_asset_repair(stock_consumption = 1)
+
+ total_repair_cost = asset_repair.repair_cost
+ self.assertEqual(total_repair_cost, asset_repair.repair_cost)
+ for item in asset_repair.stock_items:
+ total_repair_cost += item.total_value
+
+ self.assertEqual(total_repair_cost, asset_repair.total_repair_cost)
+
+ def test_repair_status_after_submit(self):
+ asset_repair = create_asset_repair(submit = 1)
+ self.assertNotEqual(asset_repair.repair_status, "Pending")
+
+ def test_stock_items(self):
+ asset_repair = create_asset_repair(stock_consumption = 1)
+ self.assertTrue(asset_repair.stock_consumption)
+ self.assertTrue(asset_repair.stock_items)
+
+ def test_warehouse(self):
+ asset_repair = create_asset_repair(stock_consumption = 1)
+ self.assertTrue(asset_repair.stock_consumption)
+ self.assertTrue(asset_repair.warehouse)
+
+ def test_decrease_stock_quantity(self):
+ asset_repair = create_asset_repair(stock_consumption = 1, submit = 1)
+ stock_entry = frappe.get_last_doc('Stock Entry')
+
+ self.assertEqual(stock_entry.stock_entry_type, "Material Issue")
+ self.assertEqual(stock_entry.items[0].s_warehouse, asset_repair.warehouse)
+ self.assertEqual(stock_entry.items[0].item_code, asset_repair.stock_items[0].item)
+ self.assertEqual(stock_entry.items[0].qty, asset_repair.stock_items[0].consumed_quantity)
+
+ def test_increase_in_asset_value_due_to_stock_consumption(self):
+ asset = create_asset()
+ initial_asset_value = asset.asset_value
+ asset_repair = create_asset_repair(asset= asset, stock_consumption = 1, submit = 1)
+ asset.reload()
+
+ increase_in_asset_value = asset.asset_value - initial_asset_value
+ self.assertEqual(asset_repair.stock_items[0].total_value, increase_in_asset_value)
+
+ def test_increase_in_asset_value_due_to_repair_cost_capitalisation(self):
+ asset = create_asset()
+ initial_asset_value = asset.asset_value
+ asset_repair = create_asset_repair(asset= asset, capitalize_repair_cost = 1, submit = 1)
+ asset.reload()
+
+ increase_in_asset_value = asset.asset_value - initial_asset_value
+ self.assertEqual(asset_repair.repair_cost, increase_in_asset_value)
+
+ def test_purchase_invoice(self):
+ asset_repair = create_asset_repair(capitalize_repair_cost = 1, submit = 1)
+ self.assertTrue(asset_repair.purchase_invoice)
+
+ def test_gl_entries(self):
+ asset_repair = create_asset_repair(capitalize_repair_cost = 1, submit = 1)
+ gl_entry = frappe.get_last_doc('GL Entry')
+ self.assertEqual(asset_repair.name, gl_entry.voucher_no)
+
+ def test_increase_in_asset_life(self):
+ asset = create_asset(calculate_depreciation = 1)
+ initial_num_of_depreciations = num_of_depreciations(asset)
+ create_asset_repair(asset= asset, capitalize_repair_cost = 1, submit = 1)
+ asset.reload()
+ self.assertEqual((initial_num_of_depreciations + 1), num_of_depreciations(asset))
+
+def num_of_depreciations(asset):
+ return asset.finance_books[0].total_number_of_depreciations
+
+def create_asset_repair(**args):
+ from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse
+ from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
+
+ args = frappe._dict(args)
+
+ if args.asset:
+ asset = args.asset
+ else:
+ asset = create_asset(is_existing_asset = 1)
+ asset_repair = frappe.new_doc("Asset Repair")
+ asset_repair.update({
+ "asset": asset.name,
+ "asset_name": asset.asset_name,
+ "failure_date": nowdate(),
+ "description": "Test Description",
+ "repair_cost": 0
+ })
+
+ if args.stock_consumption:
+ asset_repair.stock_consumption = 1
+ asset_repair.warehouse = create_warehouse("Test Warehouse", company = asset.company)
+ asset_repair.append("stock_items", {
+ "item": args.item or args.item_code or "_Test Item",
+ "valuation_rate": args.rate if args.get("rate") is not None else 100,
+ "consumed_quantity": args.qty or 1
+ })
+
+ try:
+ asset_repair.save()
+ except frappe.DuplicateEntryError:
+ pass
+
+ if args.submit:
+ asset_repair.repair_status = "Completed"
+ asset_repair.cost_center = "_Test Cost Center - _TC"
+
+ if args.stock_consumption:
+ stock_entry = frappe.get_doc({
+ "doctype": "Stock Entry",
+ "stock_entry_type": "Material Receipt",
+ "company": asset.company
+ })
+ stock_entry.append('items', {
+ "t_warehouse": asset_repair.warehouse,
+ "item_code": asset_repair.stock_items[0].item,
+ "qty": asset_repair.stock_items[0].consumed_quantity
+ })
+ stock_entry.submit()
+
+ if args.capitalize_repair_cost:
+ asset_repair.capitalize_repair_cost = 1
+ asset_repair.repair_cost = 1000
+ if asset.calculate_depreciation:
+ asset_repair.increase_in_asset_life = 12
+ asset_repair.purchase_invoice = make_purchase_invoice().name
+
+ asset_repair.submit()
+ return asset_repair
\ No newline at end of file
From 65b2f9234b46f8e6442292bb0e54d56dd6841a46 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Thu, 3 Jun 2021 01:54:44 +0530
Subject: [PATCH 038/386] fix(Asset Repair): Set company when creating Stock
Entry
---
erpnext/assets/doctype/asset_repair/asset_repair.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.py b/erpnext/assets/doctype/asset_repair/asset_repair.py
index 4ca6fbc5d0..6a5776a835 100644
--- a/erpnext/assets/doctype/asset_repair/asset_repair.py
+++ b/erpnext/assets/doctype/asset_repair/asset_repair.py
@@ -76,7 +76,8 @@ class AssetRepair(Document):
def decrease_stock_quantity(self):
stock_entry = frappe.get_doc({
"doctype": "Stock Entry",
- "stock_entry_type": "Material Issue"
+ "stock_entry_type": "Material Issue",
+ "company": frappe.get_value('Asset', self.asset, "company")
})
for stock_item in self.stock_items:
From 4e620c3b32381b97fb44c50f0608bd6522d10668 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Tue, 15 Jun 2021 12:02:07 +0530
Subject: [PATCH 039/386] fix: Set asset_name as title
---
erpnext/assets/doctype/asset_repair/asset_repair.json | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.json b/erpnext/assets/doctype/asset_repair/asset_repair.json
index 522f2874d9..640762d82c 100644
--- a/erpnext/assets/doctype/asset_repair/asset_repair.json
+++ b/erpnext/assets/doctype/asset_repair/asset_repair.json
@@ -239,7 +239,8 @@
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
- "modified": "2021-05-21 10:37:35.002238",
+ "modified": "2021-06-15 10:34:00.839353",
+ "title_field": "asset_name",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Repair",
From fd272569aa1bb8e35c65d982691c32402cf6cdd2 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Wed, 16 Jun 2021 07:03:32 +0530
Subject: [PATCH 040/386] fix(Asset Repair): Display fields according to the
state of the doc
---
erpnext/assets/doctype/asset_repair/asset_repair.js | 2 --
erpnext/assets/doctype/asset_repair/asset_repair.json | 9 +++++++--
2 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.js b/erpnext/assets/doctype/asset_repair/asset_repair.js
index 7633a595a2..fdb8d0af67 100644
--- a/erpnext/assets/doctype/asset_repair/asset_repair.js
+++ b/erpnext/assets/doctype/asset_repair/asset_repair.js
@@ -3,8 +3,6 @@
frappe.ui.form.on('Asset Repair', {
refresh: function(frm) {
- frm.toggle_display(['completion_date', 'repair_status', 'accounting_details', 'accounting_dimensions_section'], !(frm.doc.__islocal));
-
if (frm.doc.docstatus) {
frm.add_custom_button("View General Ledger", function() {
frappe.route_options = {
diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.json b/erpnext/assets/doctype/asset_repair/asset_repair.json
index 640762d82c..baae93d468 100644
--- a/erpnext/assets/doctype/asset_repair/asset_repair.json
+++ b/erpnext/assets/doctype/asset_repair/asset_repair.json
@@ -71,6 +71,7 @@
},
{
"allow_on_submit": 1,
+ "depends_on": "eval:!doc.__islocal",
"fieldname": "completion_date",
"fieldtype": "Datetime",
"label": "Completion Date"
@@ -78,6 +79,7 @@
{
"allow_on_submit": 1,
"default": "Pending",
+ "depends_on": "eval:!doc.__islocal",
"fieldname": "repair_status",
"fieldtype": "Select",
"label": "Repair Status",
@@ -154,6 +156,7 @@
},
{
"default": "0",
+ "depends_on": "eval:!doc.__islocal",
"fieldname": "capitalize_repair_cost",
"fieldtype": "Check",
"label": "Capitalize Repair Cost"
@@ -196,6 +199,7 @@
},
{
"default": "0",
+ "depends_on": "eval:!doc.__islocal",
"fieldname": "stock_consumption",
"fieldtype": "Check",
"label": "Stock Consumed During Repair"
@@ -230,6 +234,7 @@
"label": "Increase In Asset Life(Months)"
},
{
+ "depends_on": "eval:!doc.__islocal",
"fieldname": "purchase_invoice",
"fieldtype": "Link",
"label": "Purchase Invoice",
@@ -239,8 +244,7 @@
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
- "modified": "2021-06-15 10:34:00.839353",
- "title_field": "asset_name",
+ "modified": "2021-06-16 07:01:28.217619",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Repair",
@@ -279,6 +283,7 @@
],
"sort_field": "modified",
"sort_order": "DESC",
+ "title_field": "asset_name",
"track_changes": 1,
"track_seen": 1
}
\ No newline at end of file
From 654074ad7a3e55a4bf073e7c6f9e11195a12bfcd Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Wed, 16 Jun 2021 07:50:03 +0530
Subject: [PATCH 041/386] fix(Asset Repair): Add title to error messages
---
erpnext/assets/doctype/asset_repair/asset_repair.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.py b/erpnext/assets/doctype/asset_repair/asset_repair.py
index 6a5776a835..6565f356ae 100644
--- a/erpnext/assets/doctype/asset_repair/asset_repair.py
+++ b/erpnext/assets/doctype/asset_repair/asset_repair.py
@@ -56,9 +56,9 @@ class AssetRepair(Document):
def check_for_stock_items_and_warehouse(self):
if not self.stock_items:
- frappe.throw(_("Please enter Stock Items consumed during Asset Repair."))
+ frappe.throw(_("Please enter Stock Items consumed during the Repair."), title=_("Missing Items"))
if not self.warehouse:
- frappe.throw(_("Please enter Warehouse from which Stock Items consumed during Asset Repair were taken."))
+ frappe.throw(_("Please enter Warehouse from which Stock Items consumed during the Repair were taken."), title=_("Missing Warehouse"))
def check_for_cost_center(self):
if not self.cost_center:
From 5ab0cabf911581fe27cff997b326c76c6c90d777 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Wed, 16 Jun 2021 07:56:40 +0530
Subject: [PATCH 042/386] fix(Asset Repair): Make Stock Items and Warehouse
mandatory if stock_consumption is checked
---
erpnext/assets/doctype/asset_repair/asset_repair.json | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.json b/erpnext/assets/doctype/asset_repair/asset_repair.json
index baae93d468..17d33c41ec 100644
--- a/erpnext/assets/doctype/asset_repair/asset_repair.json
+++ b/erpnext/assets/doctype/asset_repair/asset_repair.json
@@ -170,6 +170,7 @@
"fieldname": "stock_items",
"fieldtype": "Table",
"label": "Stock Items",
+ "mandatory_depends_on": "stock_consumption",
"options": "Stock Item"
},
{
@@ -217,6 +218,7 @@
"label": "Total Repair Cost"
},
{
+ "depends_on": "stock_consumption",
"fieldname": "warehouse",
"fieldtype": "Link",
"label": "Warehouse",
@@ -244,7 +246,7 @@
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
- "modified": "2021-06-16 07:01:28.217619",
+ "modified": "2021-06-16 07:52:49.438800",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Repair",
From 867fd02b2dfb1d54a823cabc1f0ebaef295ccc6f Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Wed, 16 Jun 2021 08:07:06 +0530
Subject: [PATCH 043/386] fix(Asset Repair): Add Company field
---
.../assets/doctype/asset_repair/asset_repair.json | 10 +++++++++-
erpnext/assets/doctype/asset_repair/asset_repair.py | 12 +++++-------
2 files changed, 14 insertions(+), 8 deletions(-)
diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.json b/erpnext/assets/doctype/asset_repair/asset_repair.json
index 17d33c41ec..840589ca2e 100644
--- a/erpnext/assets/doctype/asset_repair/asset_repair.json
+++ b/erpnext/assets/doctype/asset_repair/asset_repair.json
@@ -11,6 +11,7 @@
"naming_series",
"column_break_2",
"asset_name",
+ "company",
"section_break_5",
"failure_date",
"repair_status",
@@ -241,12 +242,19 @@
"fieldtype": "Link",
"label": "Purchase Invoice",
"options": "Purchase Invoice"
+ },
+ {
+ "fetch_from": "asset.company",
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "label": "Company",
+ "options": "Company"
}
],
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
- "modified": "2021-06-16 07:52:49.438800",
+ "modified": "2021-06-16 08:02:34.782990",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Repair",
diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.py b/erpnext/assets/doctype/asset_repair/asset_repair.py
index 6565f356ae..bd5e462f13 100644
--- a/erpnext/assets/doctype/asset_repair/asset_repair.py
+++ b/erpnext/assets/doctype/asset_repair/asset_repair.py
@@ -77,7 +77,7 @@ class AssetRepair(Document):
stock_entry = frappe.get_doc({
"doctype": "Stock Entry",
"stock_entry_type": "Material Issue",
- "company": frappe.get_value('Asset', self.asset, "company")
+ "company": self.company
})
for stock_item in self.stock_items:
@@ -104,8 +104,7 @@ class AssetRepair(Document):
def get_gl_entries(self):
gl_entry = []
- company = frappe.db.get_value('Asset', self.asset, 'company')
- repair_and_maintenance_account = frappe.db.get_value('Company', company, 'repair_and_maintenance_account')
+ repair_and_maintenance_account = frappe.db.get_value('Company', self.company, 'repair_and_maintenance_account')
fixed_asset_account = self.get_fixed_asset_account()
expense_account = frappe.get_doc('Purchase Invoice', self.purchase_invoice).items[0].expense_account
@@ -119,7 +118,7 @@ class AssetRepair(Document):
"voucher_no": self.name,
"cost_center": self.cost_center,
"posting_date": getdate(),
- "company": company
+ "company": self.company
})
gl_entry.insert()
gl_entry = frappe.get_doc({
@@ -134,15 +133,14 @@ class AssetRepair(Document):
"posting_date": getdate(),
"against_voucher_type": "Purchase Invoice",
"against_voucher": self.purchase_invoice,
- "company": company
+ "company": self.company
})
gl_entry.insert()
def get_fixed_asset_account(self):
asset_category = frappe.get_doc('Asset Category', frappe.db.get_value('Asset', self.asset, 'asset_category'))
- company = frappe.db.get_value('Asset', self.asset, 'company')
for account in asset_category.accounts:
- if account.company_name == company:
+ if account.company_name == self.company:
return account.fixed_asset_account
def modify_depreciation_schedule(self):
From 17fa1217792bb06554d4c2f60e45768091da2bac Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Wed, 16 Jun 2021 08:13:36 +0530
Subject: [PATCH 044/386] fix(Asset Repair): Filter Cost Center and Project by
Company
---
.../doctype/asset_repair/asset_repair.js | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.js b/erpnext/assets/doctype/asset_repair/asset_repair.js
index fdb8d0af67..1e87722179 100644
--- a/erpnext/assets/doctype/asset_repair/asset_repair.js
+++ b/erpnext/assets/doctype/asset_repair/asset_repair.js
@@ -30,3 +30,21 @@ frappe.ui.form.on('Asset Repair', {
}
}
});
+
+cur_frm.fields_dict.cost_center.get_query = function(doc) {
+ return{
+ filters:{
+ 'is_group': 0,
+ 'company': doc.company
+ }
+ }
+}
+
+cur_frm.fields_dict.project.get_query = function(doc) {
+ return{
+ filters:{
+ 'is_group': 0,
+ 'company': doc.company
+ }
+ }
+}
\ No newline at end of file
From aff97095252aa2807f4ea4c0bf1a35c6e7d8e912 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Wed, 16 Jun 2021 08:18:45 +0530
Subject: [PATCH 045/386] fix(Asset Repair): Add mandatory_depends_on condition
for Purchase Invoice
---
erpnext/assets/doctype/asset_repair/asset_repair.json | 3 ++-
erpnext/assets/doctype/asset_repair/asset_repair.py | 5 -----
2 files changed, 2 insertions(+), 6 deletions(-)
diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.json b/erpnext/assets/doctype/asset_repair/asset_repair.json
index 840589ca2e..d3335c5afb 100644
--- a/erpnext/assets/doctype/asset_repair/asset_repair.json
+++ b/erpnext/assets/doctype/asset_repair/asset_repair.json
@@ -241,6 +241,7 @@
"fieldname": "purchase_invoice",
"fieldtype": "Link",
"label": "Purchase Invoice",
+ "mandatory_depends_on": "eval: doc.repair_status == 'Completed' && doc.repair_cost > 0",
"options": "Purchase Invoice"
},
{
@@ -254,7 +255,7 @@
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
- "modified": "2021-06-16 08:02:34.782990",
+ "modified": "2021-06-16 08:16:07.581813",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Repair",
diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.py b/erpnext/assets/doctype/asset_repair/asset_repair.py
index bd5e462f13..01eeb36e3a 100644
--- a/erpnext/assets/doctype/asset_repair/asset_repair.py
+++ b/erpnext/assets/doctype/asset_repair/asset_repair.py
@@ -45,7 +45,6 @@ class AssetRepair(Document):
self.check_for_stock_items_and_warehouse()
self.decrease_stock_quantity()
if self.capitalize_repair_cost:
- self.check_for_purchase_invoice()
self.make_gl_entries()
if frappe.db.get_value('Asset', self.asset, 'calculate_depreciation'):
self.modify_depreciation_schedule()
@@ -90,10 +89,6 @@ class AssetRepair(Document):
stock_entry.insert()
stock_entry.submit()
- def check_for_purchase_invoice(self):
- if not self.purchase_invoice:
- frappe.throw(_("Please link Purchase Invoice."))
-
def on_cancel(self):
self.make_gl_entries(cancel=True)
From 9779aa11fbd7390bc08a9f025f6893eb4890a5b9 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Wed, 16 Jun 2021 08:26:02 +0530
Subject: [PATCH 046/386] fix(Asset Repair): Use existing function from
asset.py for fetching fixed_asset_account
---
erpnext/assets/doctype/asset_repair/asset_repair.py | 9 ++-------
1 file changed, 2 insertions(+), 7 deletions(-)
diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.py b/erpnext/assets/doctype/asset_repair/asset_repair.py
index 01eeb36e3a..63cdaf5cde 100644
--- a/erpnext/assets/doctype/asset_repair/asset_repair.py
+++ b/erpnext/assets/doctype/asset_repair/asset_repair.py
@@ -8,6 +8,7 @@ from frappe import _
from frappe.utils import time_diff_in_hours, getdate, add_months, flt, cint
from frappe.model.document import Document
from erpnext.accounts.general_ledger import make_gl_entries
+from erpnext.assets.doctype.asset.asset import get_asset_account
class AssetRepair(Document):
def validate(self):
@@ -100,7 +101,7 @@ class AssetRepair(Document):
def get_gl_entries(self):
gl_entry = []
repair_and_maintenance_account = frappe.db.get_value('Company', self.company, 'repair_and_maintenance_account')
- fixed_asset_account = self.get_fixed_asset_account()
+ fixed_asset_account = get_asset_account("fixed_asset_account", asset=self.asset, company=self.company)
expense_account = frappe.get_doc('Purchase Invoice', self.purchase_invoice).items[0].expense_account
gl_entry = frappe.get_doc({
@@ -132,12 +133,6 @@ class AssetRepair(Document):
})
gl_entry.insert()
- def get_fixed_asset_account(self):
- asset_category = frappe.get_doc('Asset Category', frappe.db.get_value('Asset', self.asset, 'asset_category'))
- for account in asset_category.accounts:
- if account.company_name == self.company:
- return account.fixed_asset_account
-
def modify_depreciation_schedule(self):
if self.increase_in_asset_life:
asset = frappe.get_doc('Asset', self.asset)
From 0aaf88cc0aadd37f1e19a79829c767fb3a69265c Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Wed, 16 Jun 2021 08:33:05 +0530
Subject: [PATCH 047/386] fix(Asset Repair): Uncheck allow_on_submit for all
fields
---
erpnext/assets/doctype/asset_repair/asset_repair.json | 7 +------
1 file changed, 1 insertion(+), 6 deletions(-)
diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.json b/erpnext/assets/doctype/asset_repair/asset_repair.json
index d3335c5afb..88e75a168f 100644
--- a/erpnext/assets/doctype/asset_repair/asset_repair.json
+++ b/erpnext/assets/doctype/asset_repair/asset_repair.json
@@ -71,14 +71,12 @@
"fieldtype": "Column Break"
},
{
- "allow_on_submit": 1,
"depends_on": "eval:!doc.__islocal",
"fieldname": "completion_date",
"fieldtype": "Datetime",
"label": "Completion Date"
},
{
- "allow_on_submit": 1,
"default": "Pending",
"depends_on": "eval:!doc.__islocal",
"fieldname": "repair_status",
@@ -104,13 +102,11 @@
"fieldtype": "Column Break"
},
{
- "allow_on_submit": 1,
"fieldname": "actions_performed",
"fieldtype": "Long Text",
"label": "Actions performed"
},
{
- "allow_on_submit": 1,
"fieldname": "downtime",
"fieldtype": "Data",
"in_list_view": 1,
@@ -122,7 +118,6 @@
"fieldtype": "Column Break"
},
{
- "allow_on_submit": 1,
"fieldname": "repair_cost",
"fieldtype": "Currency",
"label": "Repair Cost"
@@ -255,7 +250,7 @@
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
- "modified": "2021-06-16 08:16:07.581813",
+ "modified": "2021-06-16 08:32:06.160615",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Repair",
From 75fbda10ad1c51c00a02123e63b62c4d6a066d36 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Wed, 16 Jun 2021 08:35:50 +0530
Subject: [PATCH 048/386] fix(Asset Repair): Make Cost Center non-mandatory
---
erpnext/assets/doctype/asset_repair/asset_repair.py | 5 -----
1 file changed, 5 deletions(-)
diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.py b/erpnext/assets/doctype/asset_repair/asset_repair.py
index 63cdaf5cde..5f4c382079 100644
--- a/erpnext/assets/doctype/asset_repair/asset_repair.py
+++ b/erpnext/assets/doctype/asset_repair/asset_repair.py
@@ -38,7 +38,6 @@ class AssetRepair(Document):
def on_submit(self):
self.check_repair_status()
- self.check_for_cost_center()
if self.stock_consumption or self.capitalize_repair_cost:
self.increase_asset_value()
@@ -60,10 +59,6 @@ class AssetRepair(Document):
if not self.warehouse:
frappe.throw(_("Please enter Warehouse from which Stock Items consumed during the Repair were taken."), title=_("Missing Warehouse"))
- def check_for_cost_center(self):
- if not self.cost_center:
- frappe.throw(_("Please enter Cost Center."))
-
def increase_asset_value(self):
asset_value = frappe.db.get_value('Asset', self.asset, 'asset_value')
for item in self.stock_items:
From 71eaf3dbd8bffed9f1e499170729d84884944d02 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Wed, 16 Jun 2021 08:45:54 +0530
Subject: [PATCH 049/386] fix(Asset Repair): Fix Sider issues
---
.../assets/doctype/asset_repair/asset_repair.js | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.js b/erpnext/assets/doctype/asset_repair/asset_repair.js
index 1e87722179..2319b069b0 100644
--- a/erpnext/assets/doctype/asset_repair/asset_repair.js
+++ b/erpnext/assets/doctype/asset_repair/asset_repair.js
@@ -32,19 +32,19 @@ frappe.ui.form.on('Asset Repair', {
});
cur_frm.fields_dict.cost_center.get_query = function(doc) {
- return{
- filters:{
+ return {
+ filters: {
'is_group': 0,
'company': doc.company
}
- }
-}
+ };
+};
cur_frm.fields_dict.project.get_query = function(doc) {
- return{
- filters:{
+ return {
+ filters: {
'is_group': 0,
'company': doc.company
}
- }
-}
\ No newline at end of file
+ };
+};
\ No newline at end of file
From 96de4fdf1fd8b3047ede42ff10b20ecc443e3026 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Wed, 16 Jun 2021 10:42:37 +0530
Subject: [PATCH 050/386] fix(Asset Repair): Fix GL Entry creation
---
.../doctype/asset_repair/asset_repair.py | 78 ++++++++++++-------
1 file changed, 48 insertions(+), 30 deletions(-)
diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.py b/erpnext/assets/doctype/asset_repair/asset_repair.py
index 5f4c382079..92f7408ba7 100644
--- a/erpnext/assets/doctype/asset_repair/asset_repair.py
+++ b/erpnext/assets/doctype/asset_repair/asset_repair.py
@@ -9,8 +9,9 @@ from frappe.utils import time_diff_in_hours, getdate, add_months, flt, cint
from frappe.model.document import Document
from erpnext.accounts.general_ledger import make_gl_entries
from erpnext.assets.doctype.asset.asset import get_asset_account
+from erpnext.controllers.accounts_controller import AccountsController
-class AssetRepair(Document):
+class AssetRepair(AccountsController):
def validate(self):
if self.repair_status == "Completed" and not self.completion_date:
frappe.throw(_("Please select Completion Date for Completed Repair"))
@@ -94,39 +95,56 @@ class AssetRepair(Document):
make_gl_entries(gl_entries, cancel)
def get_gl_entries(self):
- gl_entry = []
+ gl_entries = []
repair_and_maintenance_account = frappe.db.get_value('Company', self.company, 'repair_and_maintenance_account')
fixed_asset_account = get_asset_account("fixed_asset_account", asset=self.asset, company=self.company)
expense_account = frappe.get_doc('Purchase Invoice', self.purchase_invoice).items[0].expense_account
- gl_entry = frappe.get_doc({
- "doctype": "GL Entry",
- "account": expense_account,
- "credit": self.total_repair_cost,
- "credit_in_account_currency": self.total_repair_cost,
- "against": repair_and_maintenance_account,
- "voucher_type": self.doctype,
- "voucher_no": self.name,
- "cost_center": self.cost_center,
- "posting_date": getdate(),
- "company": self.company
- })
- gl_entry.insert()
- gl_entry = frappe.get_doc({
- "doctype": "GL Entry",
- "account": fixed_asset_account,
- "debit": self.total_repair_cost,
- "debit_in_account_currency": self.total_repair_cost,
- "against": expense_account,
- "voucher_type": self.doctype,
- "voucher_no": self.name,
- "cost_center": self.cost_center,
- "posting_date": getdate(),
- "against_voucher_type": "Purchase Invoice",
- "against_voucher": self.purchase_invoice,
- "company": self.company
- })
- gl_entry.insert()
+ gl_entries.append(
+ self.get_gl_dict({
+ "account": expense_account,
+ "credit": self.repair_cost,
+ "credit_in_account_currency": self.repair_cost,
+ "against": repair_and_maintenance_account,
+ "voucher_type": self.doctype,
+ "voucher_no": self.name,
+ "cost_center": self.cost_center,
+ "posting_date": getdate(),
+ "company": self.company
+ }, item=self)
+ )
+
+ gl_entries.append(
+ self.get_gl_dict({
+ "account": expense_account,
+ "credit": self.total_repair_cost - self.repair_cost,
+ "credit_in_account_currency": self.total_repair_cost - self.repair_cost,
+ "against": repair_and_maintenance_account,
+ "voucher_type": self.doctype,
+ "voucher_no": self.name,
+ "cost_center": self.cost_center,
+ "posting_date": getdate(),
+ "company": self.company
+ }, item=self)
+ )
+
+ gl_entries.append(
+ self.get_gl_dict({
+ "account": fixed_asset_account,
+ "debit": self.total_repair_cost,
+ "debit_in_account_currency": self.total_repair_cost,
+ "against": expense_account,
+ "voucher_type": self.doctype,
+ "voucher_no": self.name,
+ "cost_center": self.cost_center,
+ "posting_date": getdate(),
+ "against_voucher_type": "Purchase Invoice",
+ "against_voucher": self.purchase_invoice,
+ "company": self.company
+ }, item=self)
+ )
+
+ return gl_entries
def modify_depreciation_schedule(self):
if self.increase_in_asset_life:
From 9520efb941097765fefce9754beb158699386a25 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Wed, 16 Jun 2021 10:48:07 +0530
Subject: [PATCH 051/386] fix(Asset Repair): Filter Warehouse by Company
---
erpnext/assets/doctype/asset_repair/asset_repair.js | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.js b/erpnext/assets/doctype/asset_repair/asset_repair.js
index 2319b069b0..efa6a9d494 100644
--- a/erpnext/assets/doctype/asset_repair/asset_repair.js
+++ b/erpnext/assets/doctype/asset_repair/asset_repair.js
@@ -41,6 +41,14 @@ cur_frm.fields_dict.cost_center.get_query = function(doc) {
};
cur_frm.fields_dict.project.get_query = function(doc) {
+ return {
+ filters: {
+ 'company': doc.company
+ }
+ };
+};
+
+cur_frm.fields_dict.warehouse.get_query = function(doc) {
return {
filters: {
'is_group': 0,
From d354a301cbc0fd77a5283ca7690b5c82ba053c47 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Thu, 17 Jun 2021 08:28:19 +0530
Subject: [PATCH 052/386] fix(Asset Repair): Display value_after_depreciation
in Finance Books
---
.../assets/doctype/asset_finance_book/asset_finance_book.json | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/erpnext/assets/doctype/asset_finance_book/asset_finance_book.json b/erpnext/assets/doctype/asset_finance_book/asset_finance_book.json
index d9b7b695f7..ee3a2072f0 100644
--- a/erpnext/assets/doctype/asset_finance_book/asset_finance_book.json
+++ b/erpnext/assets/doctype/asset_finance_book/asset_finance_book.json
@@ -67,7 +67,6 @@
{
"fieldname": "value_after_depreciation",
"fieldtype": "Currency",
- "hidden": 1,
"label": "Value After Depreciation",
"no_copy": 1,
"options": "Company:company:default_currency",
@@ -85,7 +84,7 @@
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
- "modified": "2020-11-05 16:30:09.213479",
+ "modified": "2021-06-17 08:02:32.650738",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Finance Book",
From 50826f16ee1c16454cbfa24af316d2bf32e8c1e9 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Thu, 17 Jun 2021 13:02:02 +0530
Subject: [PATCH 053/386] fix(Asset): Replace asset_value with
value_after_depreciation in Finance Books
---
erpnext/assets/doctype/asset/asset.json | 9 +--------
erpnext/assets/doctype/asset/asset.py | 11 ++++++-----
.../asset_finance_book/asset_finance_book.json | 2 +-
.../assets/doctype/asset_repair/asset_repair.py | 16 +++++++++++-----
4 files changed, 19 insertions(+), 19 deletions(-)
diff --git a/erpnext/assets/doctype/asset/asset.json b/erpnext/assets/doctype/asset/asset.json
index 8a0e3ad2a6..d55258c8f6 100644
--- a/erpnext/assets/doctype/asset/asset.json
+++ b/erpnext/assets/doctype/asset/asset.json
@@ -23,7 +23,6 @@
"asset_name",
"asset_category",
"location",
- "asset_value",
"custodian",
"department",
"disposal_date",
@@ -484,12 +483,6 @@
"fieldtype": "Section Break",
"label": "Finance Books"
},
- {
- "fieldname": "asset_value",
- "fieldtype": "Currency",
- "label": "Asset Value",
- "read_only": 1
- },
{
"fieldname": "to_date",
"fieldtype": "Date",
@@ -523,7 +516,7 @@
"link_fieldname": "asset"
}
],
- "modified": "2021-05-21 12:05:29.424083",
+ "modified": "2021-06-17 12:59:39.189106",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset",
diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py
index b3d3a198c3..4820f8b487 100644
--- a/erpnext/assets/doctype/asset/asset.py
+++ b/erpnext/assets/doctype/asset/asset.py
@@ -96,9 +96,6 @@ class Asset(AccountsController):
finance_books = get_item_details(self.item_code, self.asset_category)
self.set('finance_books', finance_books)
- if not(self.asset_value):
- self.asset_value = self.gross_purchase_amount
-
def validate_asset_values(self):
if not self.asset_category:
self.asset_category = frappe.get_cached_value("Item", self.item_code, "asset_category")
@@ -187,8 +184,12 @@ class Asset(AccountsController):
start = n
break
- value_after_depreciation = (flt(self.asset_value) -
- flt(self.opening_accumulated_depreciation)) - flt(d.expected_value_after_useful_life)
+ if d.value_after_depreciation:
+ value_after_depreciation = (flt(d.value_after_depreciation) -
+ flt(self.opening_accumulated_depreciation)) - flt(d.expected_value_after_useful_life)
+ else:
+ value_after_depreciation = (flt(self.gross_purchase_amount) -
+ flt(self.opening_accumulated_depreciation)) - flt(d.expected_value_after_useful_life)
d.value_after_depreciation = value_after_depreciation
diff --git a/erpnext/assets/doctype/asset_finance_book/asset_finance_book.json b/erpnext/assets/doctype/asset_finance_book/asset_finance_book.json
index ee3a2072f0..e5a5f194c1 100644
--- a/erpnext/assets/doctype/asset_finance_book/asset_finance_book.json
+++ b/erpnext/assets/doctype/asset_finance_book/asset_finance_book.json
@@ -84,7 +84,7 @@
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
- "modified": "2021-06-17 08:02:32.650738",
+ "modified": "2021-06-17 12:59:05.743683",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Finance Book",
diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.py b/erpnext/assets/doctype/asset_repair/asset_repair.py
index 92f7408ba7..2d039190e3 100644
--- a/erpnext/assets/doctype/asset_repair/asset_repair.py
+++ b/erpnext/assets/doctype/asset_repair/asset_repair.py
@@ -61,13 +61,19 @@ class AssetRepair(AccountsController):
frappe.throw(_("Please enter Warehouse from which Stock Items consumed during the Repair were taken."), title=_("Missing Warehouse"))
def increase_asset_value(self):
- asset_value = frappe.db.get_value('Asset', self.asset, 'asset_value')
+ total_value_of_stock_consumed = 0
for item in self.stock_items:
- asset_value += item.total_value
+ total_value_of_stock_consumed += item.total_value
- if self.capitalize_repair_cost:
- asset_value += self.repair_cost
- frappe.db.set_value('Asset', self.asset, 'asset_value', asset_value)
+ asset = frappe.get_doc('Asset', self.asset)
+ asset.flags.ignore_validate_update_after_submit = True
+ if asset.calculate_depreciation:
+ for row in asset.finance_books:
+ row.value_after_depreciation += total_value_of_stock_consumed
+
+ if self.capitalize_repair_cost:
+ row.value_after_depreciation += self.repair_cost
+ asset.save()
def decrease_stock_quantity(self):
stock_entry = frappe.get_doc({
From 54cbc8324acac8bdff796d72f7f128fe076eae3f Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Fri, 18 Jun 2021 09:53:18 +0530
Subject: [PATCH 054/386] fix(Asset Repair): Create GL Entries for each item in
Stock Items
---
.../doctype/asset_repair/asset_repair.py | 30 +++++++++++--------
1 file changed, 17 insertions(+), 13 deletions(-)
diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.py b/erpnext/assets/doctype/asset_repair/asset_repair.py
index 2d039190e3..7864cb70a5 100644
--- a/erpnext/assets/doctype/asset_repair/asset_repair.py
+++ b/erpnext/assets/doctype/asset_repair/asset_repair.py
@@ -120,19 +120,23 @@ class AssetRepair(AccountsController):
}, item=self)
)
- gl_entries.append(
- self.get_gl_dict({
- "account": expense_account,
- "credit": self.total_repair_cost - self.repair_cost,
- "credit_in_account_currency": self.total_repair_cost - self.repair_cost,
- "against": repair_and_maintenance_account,
- "voucher_type": self.doctype,
- "voucher_no": self.name,
- "cost_center": self.cost_center,
- "posting_date": getdate(),
- "company": self.company
- }, item=self)
- )
+ if self.stock_consumption:
+ # creating GL Entries for each row in Stock Items based on the Stock Entry created for it
+ stock_entry = frappe.get_last_doc('Stock Entry')
+ for item in stock_entry.items:
+ gl_entries.append(
+ self.get_gl_dict({
+ "account": item.expense_account,
+ "credit": item.amount,
+ "credit_in_account_currency": item.amount,
+ "against": repair_and_maintenance_account,
+ "voucher_type": self.doctype,
+ "voucher_no": self.name,
+ "cost_center": self.cost_center,
+ "posting_date": getdate(),
+ "company": self.company
+ }, item=self)
+ )
gl_entries.append(
self.get_gl_dict({
From bd336c7d8e4d4053fb69c12a669dfc1efcf4250c Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Fri, 18 Jun 2021 09:59:45 +0530
Subject: [PATCH 055/386] fix(Asset): Add function to clear old depreciation
schedule
---
erpnext/assets/doctype/asset/asset.py | 18 +++++++++++-------
1 file changed, 11 insertions(+), 7 deletions(-)
diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py
index 4820f8b487..9273f01da7 100644
--- a/erpnext/assets/doctype/asset/asset.py
+++ b/erpnext/assets/doctype/asset/asset.py
@@ -176,13 +176,8 @@ class Asset(AccountsController):
for d in self.get('finance_books'):
self.validate_asset_finance_books(d)
-
- start = 0
- for n in range(len(self.schedules)):
- if not self.schedules[n].journal_entry:
- del self.schedules[n:]
- start = n
- break
+
+ start = self.clear_depreciation_schedule()
if d.value_after_depreciation:
value_after_depreciation = (flt(d.value_after_depreciation) -
@@ -296,6 +291,15 @@ class Asset(AccountsController):
"finance_book_id": d.idx
})
+ def clear_depreciation_schedule(self):
+ start = 0
+ for n in range(len(self.schedules)):
+ if not self.schedules[n].journal_entry:
+ del self.schedules[n:]
+ start = n
+ break
+ return start
+
def check_is_pro_rata(self, row):
has_pro_rata = False
From be536040df75293c2eb6de9b084b1fa6d10cf495 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Sat, 19 Jun 2021 13:06:27 +0530
Subject: [PATCH 056/386] fix: Add comments
---
erpnext/assets/doctype/asset/asset.py | 12 ++++++--
.../doctype/asset_repair/asset_repair.py | 30 +++++++++++--------
2 files changed, 28 insertions(+), 14 deletions(-)
diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py
index 9273f01da7..18e3ffc8a6 100644
--- a/erpnext/assets/doctype/asset/asset.py
+++ b/erpnext/assets/doctype/asset/asset.py
@@ -179,7 +179,8 @@ class Asset(AccountsController):
start = self.clear_depreciation_schedule()
- if d.value_after_depreciation:
+ # value_after_depreciation - current Asset value
+ if d.value_after_depreciation:
value_after_depreciation = (flt(d.value_after_depreciation) -
flt(self.opening_accumulated_depreciation)) - flt(d.expected_value_after_useful_life)
else:
@@ -291,6 +292,7 @@ class Asset(AccountsController):
"finance_book_id": d.idx
})
+ # used when depreciation schedule needs to be modified due to increase in asset life
def clear_depreciation_schedule(self):
start = 0
for n in range(len(self.schedules)):
@@ -300,10 +302,13 @@ class Asset(AccountsController):
break
return start
+
+ # if it returns True, depreciation_amount will not be equal for the first and last rows
def check_is_pro_rata(self, row):
has_pro_rata = False
-
days = date_diff(row.depreciation_start_date, self.available_for_use_date) + 1
+
+ # if frequency_of_depreciation is 12 months, total_days = 365
total_days = get_total_days(row.depreciation_start_date, row.frequency_of_depreciation)
if days < total_days:
@@ -783,9 +788,12 @@ def get_depreciation_amount(asset, depreciable_value, row):
depreciation_left = flt(row.total_number_of_depreciations) - flt(asset.number_of_depreciations_booked)
if row.depreciation_method in ("Straight Line", "Manual"):
+ # if the Depreciation Schedule is being prepared for the first time
if not asset.to_date:
depreciation_amount = (flt(row.value_after_depreciation) -
flt(row.expected_value_after_useful_life)) / depreciation_left
+
+ # if the Depreciation Schedule is being modified after Asset Repair
else:
depreciation_amount = (flt(row.value_after_depreciation) -
flt(row.expected_value_after_useful_life)) / (date_diff(asset.to_date, asset.available_for_use_date) / 365)
diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.py b/erpnext/assets/doctype/asset_repair/asset_repair.py
index 7864cb70a5..0befee70cb 100644
--- a/erpnext/assets/doctype/asset_repair/asset_repair.py
+++ b/erpnext/assets/doctype/asset_repair/asset_repair.py
@@ -47,7 +47,7 @@ class AssetRepair(AccountsController):
self.decrease_stock_quantity()
if self.capitalize_repair_cost:
self.make_gl_entries()
- if frappe.db.get_value('Asset', self.asset, 'calculate_depreciation'):
+ if frappe.db.get_value('Asset', self.asset, 'calculate_depreciation') and self.increase_in_asset_life:
self.modify_depreciation_schedule()
def check_repair_status(self):
@@ -157,27 +157,33 @@ class AssetRepair(AccountsController):
return gl_entries
def modify_depreciation_schedule(self):
- if self.increase_in_asset_life:
- asset = frappe.get_doc('Asset', self.asset)
- asset.flags.ignore_validate_update_after_submit = True
- for row in asset.finance_books:
- row.total_number_of_depreciations += self.increase_in_asset_life/row.frequency_of_depreciation
+ asset = frappe.get_doc('Asset', self.asset)
+ asset.flags.ignore_validate_update_after_submit = True
+ for row in asset.finance_books:
+ row.total_number_of_depreciations += self.increase_in_asset_life/row.frequency_of_depreciation
- asset.edit_dates = ""
- extra_months = self.increase_in_asset_life % row.frequency_of_depreciation
- if extra_months != 0:
- self.calculate_last_schedule_date(asset, row, extra_months)
+ asset.edit_dates = ""
+ extra_months = self.increase_in_asset_life % row.frequency_of_depreciation
+ if extra_months != 0:
+ self.calculate_last_schedule_date(asset, row, extra_months)
- asset.prepare_depreciation_data()
- asset.save()
+ asset.prepare_depreciation_data()
+ asset.save()
# to help modify depreciation schedule when increase_in_asset_life is not a multiple of frequency_of_depreciation
def calculate_last_schedule_date(self, asset, row, extra_months):
asset.edit_dates = "Don't Edit"
number_of_pending_depreciations = cint(row.total_number_of_depreciations) - \
cint(asset.number_of_depreciations_booked)
+
+ # the Schedule Date in the final row of the old Depreciation Schedule
last_schedule_date = asset.schedules[len(asset.schedules)-1].schedule_date
+
+ # the Schedule Date in the final row of the new Depreciation Schedule
asset.to_date = add_months(last_schedule_date, extra_months)
+
+ # the latest possible date at which the depreciation can occur, without increasing the Total Number of Depreciations
+ # if depreciations happen yearly and the Depreciation Posting Date is 01-01-2020, this could be 01-01-2021, 01-01-2022...
schedule_date = add_months(row.depreciation_start_date,
number_of_pending_depreciations * cint(row.frequency_of_depreciation))
From ae8cb335b6fb458dd7fc405e71c5dfabb272f94a Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Sat, 19 Jun 2021 13:45:37 +0530
Subject: [PATCH 057/386] fix(Asset Repair): Fix depreciation_amount
calculation
---
erpnext/assets/doctype/asset/asset.py | 2 +-
erpnext/regional/india/utils.py | 12 ++++++++++--
2 files changed, 11 insertions(+), 3 deletions(-)
diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py
index 18e3ffc8a6..93b05ebd5c 100644
--- a/erpnext/assets/doctype/asset/asset.py
+++ b/erpnext/assets/doctype/asset/asset.py
@@ -789,7 +789,7 @@ def get_depreciation_amount(asset, depreciable_value, row):
if row.depreciation_method in ("Straight Line", "Manual"):
# if the Depreciation Schedule is being prepared for the first time
- if not asset.to_date:
+ if not asset.edit_dates:
depreciation_amount = (flt(row.value_after_depreciation) -
flt(row.expected_value_after_useful_life)) / depreciation_left
diff --git a/erpnext/regional/india/utils.py b/erpnext/regional/india/utils.py
index a4466e78f2..11b19ae696 100644
--- a/erpnext/regional/india/utils.py
+++ b/erpnext/regional/india/utils.py
@@ -834,8 +834,16 @@ def get_depreciation_amount(asset, depreciable_value, row):
depreciation_left = flt(row.total_number_of_depreciations) - flt(asset.number_of_depreciations_booked)
if row.depreciation_method in ("Straight Line", "Manual"):
- depreciation_amount = (flt(row.value_after_depreciation) -
- flt(row.expected_value_after_useful_life)) / depreciation_left
+ # if the Depreciation Schedule is being prepared for the first time
+ if not asset.edit_dates:
+ depreciation_amount = (flt(row.value_after_depreciation) -
+ flt(row.expected_value_after_useful_life)) / depreciation_left
+
+ # if the Depreciation Schedule is being modified after Asset Repair
+ else:
+ depreciation_amount = (flt(row.value_after_depreciation) -
+ flt(row.expected_value_after_useful_life)) / (date_diff(asset.to_date, asset.available_for_use_date) / 365)
+
else:
rate_of_depreciation = row.rate_of_depreciation
# if its the first depreciation
From bd1796cbb61ff261ee2f5d699e44eeaedbe6638a Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Sat, 19 Jun 2021 14:00:26 +0530
Subject: [PATCH 058/386] fix: Replace edit_dates with
flags.increase_in_asset_life
---
erpnext/assets/doctype/asset/asset.json | 9 +--------
erpnext/assets/doctype/asset/asset.py | 4 ++--
erpnext/assets/doctype/asset_repair/asset_repair.py | 4 ++--
erpnext/regional/india/utils.py | 2 +-
4 files changed, 6 insertions(+), 13 deletions(-)
diff --git a/erpnext/assets/doctype/asset/asset.json b/erpnext/assets/doctype/asset/asset.json
index d55258c8f6..d77eb10418 100644
--- a/erpnext/assets/doctype/asset/asset.json
+++ b/erpnext/assets/doctype/asset/asset.json
@@ -54,7 +54,6 @@
"section_break_14",
"schedules",
"to_date",
- "edit_dates",
"insurance_details",
"policy_number",
"insurer",
@@ -488,12 +487,6 @@
"fieldtype": "Date",
"hidden": 1,
"label": "To Date"
- },
- {
- "fieldname": "edit_dates",
- "fieldtype": "Data",
- "hidden": 1,
- "label": "Edit Dates"
}
],
"idx": 72,
@@ -516,7 +509,7 @@
"link_fieldname": "asset"
}
],
- "modified": "2021-06-17 12:59:39.189106",
+ "modified": "2021-06-19 13:56:58.450182",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset",
diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py
index 93b05ebd5c..63b70f6613 100644
--- a/erpnext/assets/doctype/asset/asset.py
+++ b/erpnext/assets/doctype/asset/asset.py
@@ -223,7 +223,7 @@ class Asset(AccountsController):
# For last row
elif has_pro_rata and n == cint(number_of_pending_depreciations) - 1:
- if not self.edit_dates:
+ if not self.flags.increase_in_asset_life:
self.to_date = add_months(self.available_for_use_date,
n * cint(d.frequency_of_depreciation))
@@ -789,7 +789,7 @@ def get_depreciation_amount(asset, depreciable_value, row):
if row.depreciation_method in ("Straight Line", "Manual"):
# if the Depreciation Schedule is being prepared for the first time
- if not asset.edit_dates:
+ if not asset.flags.increase_in_asset_life:
depreciation_amount = (flt(row.value_after_depreciation) -
flt(row.expected_value_after_useful_life)) / depreciation_left
diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.py b/erpnext/assets/doctype/asset_repair/asset_repair.py
index 0befee70cb..da237f09f0 100644
--- a/erpnext/assets/doctype/asset_repair/asset_repair.py
+++ b/erpnext/assets/doctype/asset_repair/asset_repair.py
@@ -162,7 +162,7 @@ class AssetRepair(AccountsController):
for row in asset.finance_books:
row.total_number_of_depreciations += self.increase_in_asset_life/row.frequency_of_depreciation
- asset.edit_dates = ""
+ asset.flags.increase_in_asset_life = False
extra_months = self.increase_in_asset_life % row.frequency_of_depreciation
if extra_months != 0:
self.calculate_last_schedule_date(asset, row, extra_months)
@@ -172,7 +172,7 @@ class AssetRepair(AccountsController):
# to help modify depreciation schedule when increase_in_asset_life is not a multiple of frequency_of_depreciation
def calculate_last_schedule_date(self, asset, row, extra_months):
- asset.edit_dates = "Don't Edit"
+ asset.flags.increase_in_asset_life = True
number_of_pending_depreciations = cint(row.total_number_of_depreciations) - \
cint(asset.number_of_depreciations_booked)
diff --git a/erpnext/regional/india/utils.py b/erpnext/regional/india/utils.py
index 11b19ae696..81c0918b99 100644
--- a/erpnext/regional/india/utils.py
+++ b/erpnext/regional/india/utils.py
@@ -835,7 +835,7 @@ def get_depreciation_amount(asset, depreciable_value, row):
if row.depreciation_method in ("Straight Line", "Manual"):
# if the Depreciation Schedule is being prepared for the first time
- if not asset.edit_dates:
+ if not asset.flags.increase_in_asset_life:
depreciation_amount = (flt(row.value_after_depreciation) -
flt(row.expected_value_after_useful_life)) / depreciation_left
From 4004bcd4362e2cec8e39977768024ee256c378c7 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Sat, 19 Jun 2021 14:06:45 +0530
Subject: [PATCH 059/386] fix(Asset Repair): Move Total Repair Cost to the
Stock Consumption Details section
---
erpnext/assets/doctype/asset_repair/asset_repair.json | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.json b/erpnext/assets/doctype/asset_repair/asset_repair.json
index 88e75a168f..89f7fa3bca 100644
--- a/erpnext/assets/doctype/asset_repair/asset_repair.json
+++ b/erpnext/assets/doctype/asset_repair/asset_repair.json
@@ -26,11 +26,11 @@
"capitalize_repair_cost",
"stock_consumption",
"column_break_8",
- "total_repair_cost",
"purchase_invoice",
"stock_consumption_details_section",
"warehouse",
"stock_items",
+ "total_repair_cost",
"asset_depreciation_details_section",
"increase_in_asset_life",
"section_break_9",
@@ -209,6 +209,7 @@
},
{
"depends_on": "stock_consumption",
+ "description": "Sum of Repair Cost and the total value of all Stock Items consumed during the repair.",
"fieldname": "total_repair_cost",
"fieldtype": "Currency",
"label": "Total Repair Cost"
@@ -250,7 +251,7 @@
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
- "modified": "2021-06-16 08:32:06.160615",
+ "modified": "2021-06-19 14:04:35.423111",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Repair",
From e755c74a60b84b0c8399196db4a5cabc8c91ae4b Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Sat, 19 Jun 2021 14:54:30 +0530
Subject: [PATCH 060/386] fix(Asset Repair): Add Stock Entry field
---
.../doctype/asset_repair/asset_repair.json | 16 +++++++++++++---
.../assets/doctype/asset_repair/asset_repair.py | 4 +++-
2 files changed, 16 insertions(+), 4 deletions(-)
diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.json b/erpnext/assets/doctype/asset_repair/asset_repair.json
index 89f7fa3bca..ee18c4bdc4 100644
--- a/erpnext/assets/doctype/asset_repair/asset_repair.json
+++ b/erpnext/assets/doctype/asset_repair/asset_repair.json
@@ -31,6 +31,7 @@
"warehouse",
"stock_items",
"total_repair_cost",
+ "stock_entry",
"asset_depreciation_details_section",
"increase_in_asset_life",
"section_break_9",
@@ -118,6 +119,7 @@
"fieldtype": "Column Break"
},
{
+ "default": "0",
"fieldname": "repair_cost",
"fieldtype": "Currency",
"label": "Repair Cost"
@@ -208,11 +210,12 @@
"label": "Stock Consumption Details"
},
{
- "depends_on": "stock_consumption",
+ "depends_on": "eval: doc.stock_consumption && doc.total_repair_cost > 0",
"description": "Sum of Repair Cost and the total value of all Stock Items consumed during the repair.",
"fieldname": "total_repair_cost",
"fieldtype": "Currency",
- "label": "Total Repair Cost"
+ "label": "Total Repair Cost",
+ "read_only": 1
},
{
"depends_on": "stock_consumption",
@@ -246,12 +249,19 @@
"fieldtype": "Link",
"label": "Company",
"options": "Company"
+ },
+ {
+ "fieldname": "stock_entry",
+ "fieldtype": "Link",
+ "label": "Stock Entry",
+ "options": "Stock Entry",
+ "read_only": 1
}
],
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
- "modified": "2021-06-19 14:04:35.423111",
+ "modified": "2021-06-19 14:47:25.875814",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Repair",
diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.py b/erpnext/assets/doctype/asset_repair/asset_repair.py
index da237f09f0..c074cc930e 100644
--- a/erpnext/assets/doctype/asset_repair/asset_repair.py
+++ b/erpnext/assets/doctype/asset_repair/asset_repair.py
@@ -92,6 +92,8 @@ class AssetRepair(AccountsController):
stock_entry.insert()
stock_entry.submit()
+ self.stock_entry = stock_entry.name
+
def on_cancel(self):
self.make_gl_entries(cancel=True)
@@ -122,7 +124,7 @@ class AssetRepair(AccountsController):
if self.stock_consumption:
# creating GL Entries for each row in Stock Items based on the Stock Entry created for it
- stock_entry = frappe.get_last_doc('Stock Entry')
+ stock_entry = frappe.get_doc('Stock Entry', self.stock_entry)
for item in stock_entry.items:
gl_entries.append(
self.get_gl_dict({
From 399d17e40efde2ef674becd036ce3ffd5cb7fc0f Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Sat, 19 Jun 2021 15:18:54 +0530
Subject: [PATCH 061/386] fix(Asset Repair): Make Error Description
non-mandatory
---
erpnext/assets/doctype/asset_repair/asset_repair.json | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.json b/erpnext/assets/doctype/asset_repair/asset_repair.json
index ee18c4bdc4..cfa084e606 100644
--- a/erpnext/assets/doctype/asset_repair/asset_repair.json
+++ b/erpnext/assets/doctype/asset_repair/asset_repair.json
@@ -95,8 +95,7 @@
{
"fieldname": "description",
"fieldtype": "Long Text",
- "label": "Error Description",
- "reqd": 1
+ "label": "Error Description"
},
{
"fieldname": "column_break_9",
@@ -261,7 +260,7 @@
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
- "modified": "2021-06-19 14:47:25.875814",
+ "modified": "2021-06-19 15:18:10.625833",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Repair",
From 68e0c96c0366a18da4215b2834644db44f35171c Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Sat, 19 Jun 2021 15:23:06 +0530
Subject: [PATCH 062/386] fix(Asset Repair): Prevent some fields from being
copied on duplicating the doc
---
erpnext/assets/doctype/asset_repair/asset_repair.json | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.json b/erpnext/assets/doctype/asset_repair/asset_repair.json
index cfa084e606..a0fe632802 100644
--- a/erpnext/assets/doctype/asset_repair/asset_repair.json
+++ b/erpnext/assets/doctype/asset_repair/asset_repair.json
@@ -75,7 +75,8 @@
"depends_on": "eval:!doc.__islocal",
"fieldname": "completion_date",
"fieldtype": "Datetime",
- "label": "Completion Date"
+ "label": "Completion Date",
+ "no_copy": 1
},
{
"default": "Pending",
@@ -232,7 +233,8 @@
{
"fieldname": "increase_in_asset_life",
"fieldtype": "Int",
- "label": "Increase In Asset Life(Months)"
+ "label": "Increase In Asset Life(Months)",
+ "no_copy": 1
},
{
"depends_on": "eval:!doc.__islocal",
@@ -240,6 +242,7 @@
"fieldtype": "Link",
"label": "Purchase Invoice",
"mandatory_depends_on": "eval: doc.repair_status == 'Completed' && doc.repair_cost > 0",
+ "no_copy": 1,
"options": "Purchase Invoice"
},
{
@@ -260,7 +263,7 @@
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
- "modified": "2021-06-19 15:18:10.625833",
+ "modified": "2021-06-19 15:20:24.056706",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Repair",
From 42fd7ffbc01c59b901b46953ead07096da957887 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Sun, 20 Jun 2021 17:44:35 +0530
Subject: [PATCH 063/386] fix(Asset Repair): Set completion_date on changing
repair_status to 'Completed'
---
erpnext/assets/doctype/asset_repair/asset_repair.js | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.js b/erpnext/assets/doctype/asset_repair/asset_repair.js
index efa6a9d494..ced3dad1e5 100644
--- a/erpnext/assets/doctype/asset_repair/asset_repair.js
+++ b/erpnext/assets/doctype/asset_repair/asset_repair.js
@@ -28,6 +28,10 @@ frappe.ui.form.on('Asset Repair', {
}
});
}
+
+ if (frm.doc.repair_status == "Completed") {
+ frm.set_value('completion_date', frappe.datetime.now_datetime());
+ }
}
});
From 852881e33e5bbe887b801e11cee3282928dc3a7b Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Mon, 21 Jun 2021 14:52:00 +0530
Subject: [PATCH 064/386] fix(Asset Repair): Fix tests
---
.../doctype/asset_repair/asset_repair.json | 2 +-
.../doctype/asset_repair/asset_repair.py | 55 ++++++++-----------
.../doctype/asset_repair/test_asset_repair.py | 7 ++-
3 files changed, 30 insertions(+), 34 deletions(-)
diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.json b/erpnext/assets/doctype/asset_repair/asset_repair.json
index a0fe632802..6bcddbfb94 100644
--- a/erpnext/assets/doctype/asset_repair/asset_repair.json
+++ b/erpnext/assets/doctype/asset_repair/asset_repair.json
@@ -263,7 +263,7 @@
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
- "modified": "2021-06-19 15:20:24.056706",
+ "modified": "2021-06-20 17:35:51.075537",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Repair",
diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.py b/erpnext/assets/doctype/asset_repair/asset_repair.py
index c074cc930e..5fccfb76a5 100644
--- a/erpnext/assets/doctype/asset_repair/asset_repair.py
+++ b/erpnext/assets/doctype/asset_repair/asset_repair.py
@@ -6,74 +6,72 @@ from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.utils import time_diff_in_hours, getdate, add_months, flt, cint
-from frappe.model.document import Document
from erpnext.accounts.general_ledger import make_gl_entries
from erpnext.assets.doctype.asset.asset import get_asset_account
from erpnext.controllers.accounts_controller import AccountsController
class AssetRepair(AccountsController):
def validate(self):
- if self.repair_status == "Completed" and not self.completion_date:
- frappe.throw(_("Please select Completion Date for Completed Repair"))
-
+ self.asset_doc = frappe.get_doc('Asset', self.asset)
self.update_status()
- self.set_total_value() # change later
+ if self.get('stock_items'):
+ self.set_total_value() # change later
self.calculate_total_repair_cost()
def update_status(self):
if self.repair_status == 'Pending':
frappe.db.set_value('Asset', self.asset, 'status', 'Out of Order')
else:
- asset = frappe.get_doc('Asset', self.asset)
- asset.set_status()
+ self.asset_doc.set_status()
def set_total_value(self):
- for item in self.stock_items:
+ for item in self.get('stock_items'):
item.total_value = flt(item.valuation_rate) * flt(item.consumed_quantity)
def calculate_total_repair_cost(self):
self.total_repair_cost = self.repair_cost
- if self.stock_consumption:
- for item in self.stock_items:
+ if self.get('stock_items'):
+ for item in self.get('stock_items'):
self.total_repair_cost += item.total_value
def on_submit(self):
self.check_repair_status()
- if self.stock_consumption or self.capitalize_repair_cost:
+ if self.get('stock_consumption') or self.get('capitalize_repair_cost'):
self.increase_asset_value()
- if self.stock_consumption:
+ if self.get('stock_consumption'):
self.check_for_stock_items_and_warehouse()
self.decrease_stock_quantity()
- if self.capitalize_repair_cost:
+ if self.get('capitalize_repair_cost'):
self.make_gl_entries()
if frappe.db.get_value('Asset', self.asset, 'calculate_depreciation') and self.increase_in_asset_life:
self.modify_depreciation_schedule()
+ self.asset_doc.flags.ignore_validate_update_after_submit = True
+ self.asset_doc.save()
+
def check_repair_status(self):
if self.repair_status == "Pending":
frappe.throw(_("Please update Repair Status."))
def check_for_stock_items_and_warehouse(self):
- if not self.stock_items:
+ if not self.get('stock_items'):
frappe.throw(_("Please enter Stock Items consumed during the Repair."), title=_("Missing Items"))
if not self.warehouse:
frappe.throw(_("Please enter Warehouse from which Stock Items consumed during the Repair were taken."), title=_("Missing Warehouse"))
def increase_asset_value(self):
total_value_of_stock_consumed = 0
- for item in self.stock_items:
- total_value_of_stock_consumed += item.total_value
+ if self.get('stock_consumption'):
+ for item in self.get('stock_items'):
+ total_value_of_stock_consumed += item.total_value
- asset = frappe.get_doc('Asset', self.asset)
- asset.flags.ignore_validate_update_after_submit = True
- if asset.calculate_depreciation:
- for row in asset.finance_books:
+ if self.asset_doc.calculate_depreciation:
+ for row in self.asset_doc.finance_books:
row.value_after_depreciation += total_value_of_stock_consumed
if self.capitalize_repair_cost:
row.value_after_depreciation += self.repair_cost
- asset.save()
def decrease_stock_quantity(self):
stock_entry = frappe.get_doc({
@@ -82,7 +80,7 @@ class AssetRepair(AccountsController):
"company": self.company
})
- for stock_item in self.stock_items:
+ for stock_item in self.get('stock_items'):
stock_entry.append('items', {
"s_warehouse": self.warehouse,
"item_code": stock_item.item,
@@ -122,7 +120,7 @@ class AssetRepair(AccountsController):
}, item=self)
)
- if self.stock_consumption:
+ if self.get('stock_consumption'):
# creating GL Entries for each row in Stock Items based on the Stock Entry created for it
stock_entry = frappe.get_doc('Stock Entry', self.stock_entry)
for item in stock_entry.items:
@@ -159,18 +157,13 @@ class AssetRepair(AccountsController):
return gl_entries
def modify_depreciation_schedule(self):
- asset = frappe.get_doc('Asset', self.asset)
- asset.flags.ignore_validate_update_after_submit = True
- for row in asset.finance_books:
+ for row in self.asset_doc.finance_books:
row.total_number_of_depreciations += self.increase_in_asset_life/row.frequency_of_depreciation
- asset.flags.increase_in_asset_life = False
+ self.asset_doc.flags.increase_in_asset_life = False
extra_months = self.increase_in_asset_life % row.frequency_of_depreciation
if extra_months != 0:
- self.calculate_last_schedule_date(asset, row, extra_months)
-
- asset.prepare_depreciation_data()
- asset.save()
+ self.calculate_last_schedule_date(self.asset_doc, row, extra_months)
# to help modify depreciation schedule when increase_in_asset_life is not a multiple of frequency_of_depreciation
def calculate_last_schedule_date(self, asset, row, extra_months):
diff --git a/erpnext/assets/doctype/asset_repair/test_asset_repair.py b/erpnext/assets/doctype/asset_repair/test_asset_repair.py
index 9c9dd44971..d1b417fd38 100644
--- a/erpnext/assets/doctype/asset_repair/test_asset_repair.py
+++ b/erpnext/assets/doctype/asset_repair/test_asset_repair.py
@@ -105,7 +105,9 @@ class TestAssetRepair(unittest.TestCase):
initial_num_of_depreciations = num_of_depreciations(asset)
create_asset_repair(asset= asset, capitalize_repair_cost = 1, submit = 1)
asset.reload()
+
self.assertEqual((initial_num_of_depreciations + 1), num_of_depreciations(asset))
+ self.assertEqual(asset.schedules[-1].accumulated_depreciation_amount, asset.finance_books[0].value_after_depreciation)
def num_of_depreciations(asset):
return asset.finance_books[0].total_number_of_depreciations
@@ -126,7 +128,8 @@ def create_asset_repair(**args):
"asset_name": asset.asset_name,
"failure_date": nowdate(),
"description": "Test Description",
- "repair_cost": 0
+ "repair_cost": 0,
+ "company": asset.company
})
if args.stock_consumption:
@@ -142,7 +145,7 @@ def create_asset_repair(**args):
asset_repair.save()
except frappe.DuplicateEntryError:
pass
-
+
if args.submit:
asset_repair.repair_status = "Completed"
asset_repair.cost_center = "_Test Cost Center - _TC"
From e92187863347ff5421fb209942b36a26cc9115b8 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Mon, 21 Jun 2021 14:55:34 +0530
Subject: [PATCH 065/386] fix: Rename 'Stock Item' to 'Asset Repair Consumed
Item'
---
.../assets/doctype/asset_maintenance/asset_maintenance.json | 4 ++--
erpnext/assets/doctype/asset_repair/asset_repair.json | 4 ++--
.../{stock_item => asset_repair_consumed_item}/__init__.py | 0
.../asset_repair_consumed_item.json} | 2 +-
.../asset_repair_consumed_item.py} | 2 +-
5 files changed, 6 insertions(+), 6 deletions(-)
rename erpnext/assets/doctype/{stock_item => asset_repair_consumed_item}/__init__.py (100%)
rename erpnext/assets/doctype/{stock_item/stock_item.json => asset_repair_consumed_item/asset_repair_consumed_item.json} (96%)
rename erpnext/assets/doctype/{stock_item/stock_item.py => asset_repair_consumed_item/asset_repair_consumed_item.py} (81%)
diff --git a/erpnext/assets/doctype/asset_maintenance/asset_maintenance.json b/erpnext/assets/doctype/asset_maintenance/asset_maintenance.json
index da2fd75451..63a55389d8 100644
--- a/erpnext/assets/doctype/asset_maintenance/asset_maintenance.json
+++ b/erpnext/assets/doctype/asset_maintenance/asset_maintenance.json
@@ -126,11 +126,11 @@
"fieldname": "stock_items",
"fieldtype": "Table",
"label": "Stock Items",
- "options": "Stock Item"
+ "options": "Asset Repair Consumed Item"
}
],
"links": [],
- "modified": "2021-05-13 05:24:58.480132",
+ "modified": "2021-06-21 14:53:46.041123",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Maintenance",
diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.json b/erpnext/assets/doctype/asset_repair/asset_repair.json
index 6bcddbfb94..14f18b5309 100644
--- a/erpnext/assets/doctype/asset_repair/asset_repair.json
+++ b/erpnext/assets/doctype/asset_repair/asset_repair.json
@@ -169,7 +169,7 @@
"fieldtype": "Table",
"label": "Stock Items",
"mandatory_depends_on": "stock_consumption",
- "options": "Stock Item"
+ "options": "Asset Repair Consumed Item"
},
{
"fieldname": "section_break_23",
@@ -263,7 +263,7 @@
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
- "modified": "2021-06-20 17:35:51.075537",
+ "modified": "2021-06-21 14:53:46.665576",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Repair",
diff --git a/erpnext/assets/doctype/stock_item/__init__.py b/erpnext/assets/doctype/asset_repair_consumed_item/__init__.py
similarity index 100%
rename from erpnext/assets/doctype/stock_item/__init__.py
rename to erpnext/assets/doctype/asset_repair_consumed_item/__init__.py
diff --git a/erpnext/assets/doctype/stock_item/stock_item.json b/erpnext/assets/doctype/asset_repair_consumed_item/asset_repair_consumed_item.json
similarity index 96%
rename from erpnext/assets/doctype/stock_item/stock_item.json
rename to erpnext/assets/doctype/asset_repair_consumed_item/asset_repair_consumed_item.json
index b1f05db395..528f0ec986 100644
--- a/erpnext/assets/doctype/stock_item/stock_item.json
+++ b/erpnext/assets/doctype/asset_repair_consumed_item/asset_repair_consumed_item.json
@@ -46,7 +46,7 @@
"modified": "2021-05-12 03:19:55.006300",
"modified_by": "Administrator",
"module": "Assets",
- "name": "Stock Item",
+ "name": "Asset Repair Consumed Item",
"owner": "Administrator",
"permissions": [],
"sort_field": "modified",
diff --git a/erpnext/assets/doctype/stock_item/stock_item.py b/erpnext/assets/doctype/asset_repair_consumed_item/asset_repair_consumed_item.py
similarity index 81%
rename from erpnext/assets/doctype/stock_item/stock_item.py
rename to erpnext/assets/doctype/asset_repair_consumed_item/asset_repair_consumed_item.py
index 0e3cc3f8ba..fa22a5712f 100644
--- a/erpnext/assets/doctype/stock_item/stock_item.py
+++ b/erpnext/assets/doctype/asset_repair_consumed_item/asset_repair_consumed_item.py
@@ -4,5 +4,5 @@
# import frappe
from frappe.model.document import Document
-class StockItem(Document):
+class AssetRepairConsumedItem(Document):
pass
From ad78888c867335a8ececa2e307a3740a4a234283 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Mon, 21 Jun 2021 15:02:40 +0530
Subject: [PATCH 066/386] fix(Asset Repair): Compute total_value instantly
---
erpnext/assets/doctype/asset_repair/asset_repair.js | 7 +++++++
erpnext/assets/doctype/asset_repair/asset_repair.py | 6 ------
2 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.js b/erpnext/assets/doctype/asset_repair/asset_repair.js
index ced3dad1e5..91bed4fdd0 100644
--- a/erpnext/assets/doctype/asset_repair/asset_repair.js
+++ b/erpnext/assets/doctype/asset_repair/asset_repair.js
@@ -35,6 +35,13 @@ frappe.ui.form.on('Asset Repair', {
}
});
+frappe.ui.form.on('Asset Repair Consumed Item', {
+ consumed_quantity: function(frm, cdt, cdn) {
+ var row = locals[cdt][cdn];
+ frappe.model.set_value(cdt, cdn, 'total_value', row.consumed_quantity * row.valuation_rate);
+ },
+});
+
cur_frm.fields_dict.cost_center.get_query = function(doc) {
return {
filters: {
diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.py b/erpnext/assets/doctype/asset_repair/asset_repair.py
index 5fccfb76a5..79b9a6a2b5 100644
--- a/erpnext/assets/doctype/asset_repair/asset_repair.py
+++ b/erpnext/assets/doctype/asset_repair/asset_repair.py
@@ -14,8 +14,6 @@ class AssetRepair(AccountsController):
def validate(self):
self.asset_doc = frappe.get_doc('Asset', self.asset)
self.update_status()
- if self.get('stock_items'):
- self.set_total_value() # change later
self.calculate_total_repair_cost()
def update_status(self):
@@ -24,10 +22,6 @@ class AssetRepair(AccountsController):
else:
self.asset_doc.set_status()
- def set_total_value(self):
- for item in self.get('stock_items'):
- item.total_value = flt(item.valuation_rate) * flt(item.consumed_quantity)
-
def calculate_total_repair_cost(self):
self.total_repair_cost = self.repair_cost
if self.get('stock_items'):
From 6c2f4ce6a5b12d3fbfd2675c6fa23e12f7a8285a Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Mon, 21 Jun 2021 15:22:02 +0530
Subject: [PATCH 067/386] fix(Asset Repair): Increase stock quantity and
decrease asset value on cancellation
---
.../doctype/asset_repair/asset_repair.py | 55 ++++++++++++++++---
1 file changed, 46 insertions(+), 9 deletions(-)
diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.py b/erpnext/assets/doctype/asset_repair/asset_repair.py
index 79b9a6a2b5..e7b8b45b7e 100644
--- a/erpnext/assets/doctype/asset_repair/asset_repair.py
+++ b/erpnext/assets/doctype/asset_repair/asset_repair.py
@@ -24,9 +24,9 @@ class AssetRepair(AccountsController):
def calculate_total_repair_cost(self):
self.total_repair_cost = self.repair_cost
- if self.get('stock_items'):
- for item in self.get('stock_items'):
- self.total_repair_cost += item.total_value
+
+ total_value_of_stock_consumed = self.get_total_value_of_stock_consumed()
+ self.total_repair_cost += total_value_of_stock_consumed
def on_submit(self):
self.check_repair_status()
@@ -44,6 +44,14 @@ class AssetRepair(AccountsController):
self.asset_doc.flags.ignore_validate_update_after_submit = True
self.asset_doc.save()
+ def on_cancel(self):
+ if self.get('stock_consumption') or self.get('capitalize_repair_cost'):
+ self.decrease_asset_value()
+ if self.get('stock_consumption'):
+ self.increase_stock_quantity()
+ if self.get('capitalize_repair_cost'):
+ self.make_gl_entries(cancel=True)
+
def check_repair_status(self):
if self.repair_status == "Pending":
frappe.throw(_("Please update Repair Status."))
@@ -55,10 +63,7 @@ class AssetRepair(AccountsController):
frappe.throw(_("Please enter Warehouse from which Stock Items consumed during the Repair were taken."), title=_("Missing Warehouse"))
def increase_asset_value(self):
- total_value_of_stock_consumed = 0
- if self.get('stock_consumption'):
- for item in self.get('stock_items'):
- total_value_of_stock_consumed += item.total_value
+ total_value_of_stock_consumed = self.get_total_value_of_stock_consumed()
if self.asset_doc.calculate_depreciation:
for row in self.asset_doc.finance_books:
@@ -67,6 +72,24 @@ class AssetRepair(AccountsController):
if self.capitalize_repair_cost:
row.value_after_depreciation += self.repair_cost
+ def decrease_asset_value(self):
+ total_value_of_stock_consumed = self.get_total_value_of_stock_consumed()
+
+ if self.asset_doc.calculate_depreciation:
+ for row in self.asset_doc.finance_books:
+ row.value_after_depreciation -= total_value_of_stock_consumed
+
+ if self.capitalize_repair_cost:
+ row.value_after_depreciation -= self.repair_cost
+
+ def get_total_value_of_stock_consumed(self):
+ total_value_of_stock_consumed = 0
+ if self.get('stock_consumption'):
+ for item in self.get('stock_items'):
+ total_value_of_stock_consumed += item.total_value
+
+ return total_value_of_stock_consumed
+
def decrease_stock_quantity(self):
stock_entry = frappe.get_doc({
"doctype": "Stock Entry",
@@ -86,8 +109,22 @@ class AssetRepair(AccountsController):
self.stock_entry = stock_entry.name
- def on_cancel(self):
- self.make_gl_entries(cancel=True)
+ def increase_stock_quantity(self):
+ stock_entry = frappe.get_doc({
+ "doctype": "Stock Entry",
+ "stock_entry_type": "Material Receipt",
+ "company": self.company
+ })
+
+ for stock_item in self.get('stock_items'):
+ stock_entry.append('items', {
+ "s_warehouse": self.warehouse,
+ "item_code": stock_item.item,
+ "qty": stock_item.consumed_quantity
+ })
+
+ stock_entry.insert()
+ stock_entry.submit()
def make_gl_entries(self, cancel=False):
if flt(self.repair_cost) > 0:
From ba9558527d78b75b0bb22356a290c37cd8f1d273 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Mon, 21 Jun 2021 18:57:11 +0530
Subject: [PATCH 068/386] fix(Asset Repair): Return Depreciation Schedule to
original state on cancellation
---
.../doctype/asset_repair/asset_repair.py | 45 ++++++++++++++++++-
1 file changed, 43 insertions(+), 2 deletions(-)
diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.py b/erpnext/assets/doctype/asset_repair/asset_repair.py
index e7b8b45b7e..01b36880be 100644
--- a/erpnext/assets/doctype/asset_repair/asset_repair.py
+++ b/erpnext/assets/doctype/asset_repair/asset_repair.py
@@ -42,15 +42,25 @@ class AssetRepair(AccountsController):
self.modify_depreciation_schedule()
self.asset_doc.flags.ignore_validate_update_after_submit = True
+ self.asset_doc.prepare_depreciation_data()
self.asset_doc.save()
def on_cancel(self):
+ self.asset_doc = frappe.get_doc('Asset', self.asset)
+
if self.get('stock_consumption') or self.get('capitalize_repair_cost'):
self.decrease_asset_value()
if self.get('stock_consumption'):
self.increase_stock_quantity()
if self.get('capitalize_repair_cost'):
+ self.ignore_linked_doctypes = ('GL Entry', 'Stock Ledger Entry')
self.make_gl_entries(cancel=True)
+ if frappe.db.get_value('Asset', self.asset, 'calculate_depreciation') and self.increase_in_asset_life:
+ self.revert_depreciation_schedule_on_cancellation()
+
+ self.asset_doc.flags.ignore_validate_update_after_submit = True
+ self.asset_doc.prepare_depreciation_data()
+ self.asset_doc.save()
def check_repair_status(self):
if self.repair_status == "Pending":
@@ -101,7 +111,8 @@ class AssetRepair(AccountsController):
stock_entry.append('items', {
"s_warehouse": self.warehouse,
"item_code": stock_item.item,
- "qty": stock_item.consumed_quantity
+ "qty": stock_item.consumed_quantity,
+ "basic_rate": stock_item.valuation_rate
})
stock_entry.insert()
@@ -118,7 +129,7 @@ class AssetRepair(AccountsController):
for stock_item in self.get('stock_items'):
stock_entry.append('items', {
- "s_warehouse": self.warehouse,
+ "t_warehouse": self.warehouse,
"item_code": stock_item.item,
"qty": stock_item.consumed_quantity
})
@@ -126,6 +137,8 @@ class AssetRepair(AccountsController):
stock_entry.insert()
stock_entry.submit()
+ self.stock_entry = stock_entry.name
+
def make_gl_entries(self, cancel=False):
if flt(self.repair_cost) > 0:
gl_entries = self.get_gl_entries()
@@ -216,6 +229,34 @@ class AssetRepair(AccountsController):
if asset.to_date > schedule_date:
row.total_number_of_depreciations += 1
+ def revert_depreciation_schedule_on_cancellation(self):
+ for row in self.asset_doc.finance_books:
+ row.total_number_of_depreciations -= self.increase_in_asset_life/row.frequency_of_depreciation
+
+ self.asset_doc.flags.increase_in_asset_life = False
+ extra_months = self.increase_in_asset_life % row.frequency_of_depreciation
+ if extra_months != 0:
+ self.calculate_last_schedule_date_before_modification(self.asset_doc, row, extra_months)
+
+ def calculate_last_schedule_date_before_modification(self, asset, row, extra_months):
+ asset.flags.increase_in_asset_life = True
+ number_of_pending_depreciations = cint(row.total_number_of_depreciations) - \
+ cint(asset.number_of_depreciations_booked)
+
+ # the Schedule Date in the final row of the modified Depreciation Schedule
+ last_schedule_date = asset.schedules[len(asset.schedules)-1].schedule_date
+
+ # the Schedule Date in the final row of the original Depreciation Schedule
+ asset.to_date = add_months(last_schedule_date, -extra_months)
+
+ # the latest possible date at which the depreciation can occur, without decreasing the Total Number of Depreciations
+ # if depreciations happen yearly and the Depreciation Posting Date is 01-01-2020, this could be 01-01-2021, 01-01-2022...
+ schedule_date = add_months(row.depreciation_start_date,
+ (number_of_pending_depreciations - 1) * cint(row.frequency_of_depreciation))
+
+ if asset.to_date < schedule_date:
+ row.total_number_of_depreciations -= 1
+
@frappe.whitelist()
def get_downtime(failure_date, completion_date):
downtime = time_diff_in_hours(completion_date, failure_date)
From c34e6b1889dfc49f4a40e2157f13f037feb88c9a Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Tue, 22 Jun 2021 16:28:29 +0530
Subject: [PATCH 069/386] fix(Asset): Fix tests for Asset Repair
---
erpnext/assets/doctype/asset/test_asset.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/assets/doctype/asset/test_asset.py b/erpnext/assets/doctype/asset/test_asset.py
index 29fbc9f15d..f3667c7b95 100644
--- a/erpnext/assets/doctype/asset/test_asset.py
+++ b/erpnext/assets/doctype/asset/test_asset.py
@@ -707,7 +707,7 @@ def create_asset(**args):
"available_for_use_date": "2020-06-06",
"location": "Test Location",
"asset_owner": "Company",
- "is_existing_asset": args.is_existing_asset or 0
+ "is_existing_asset": 1
})
if asset.calculate_depreciation:
From 55bca4cbc704217294f9fb1fc71ced01f58fb8c8 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Tue, 22 Jun 2021 16:33:10 +0530
Subject: [PATCH 070/386] fix(Asset Repair): Revert Stock Entry on cancellation
---
.../doctype/asset_repair/asset_repair.py | 21 +++----------------
1 file changed, 3 insertions(+), 18 deletions(-)
diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.py b/erpnext/assets/doctype/asset_repair/asset_repair.py
index 01b36880be..0049dcaded 100644
--- a/erpnext/assets/doctype/asset_repair/asset_repair.py
+++ b/erpnext/assets/doctype/asset_repair/asset_repair.py
@@ -118,26 +118,11 @@ class AssetRepair(AccountsController):
stock_entry.insert()
stock_entry.submit()
- self.stock_entry = stock_entry.name
+ self.db_set('stock_entry', stock_entry.name)
def increase_stock_quantity(self):
- stock_entry = frappe.get_doc({
- "doctype": "Stock Entry",
- "stock_entry_type": "Material Receipt",
- "company": self.company
- })
-
- for stock_item in self.get('stock_items'):
- stock_entry.append('items', {
- "t_warehouse": self.warehouse,
- "item_code": stock_item.item,
- "qty": stock_item.consumed_quantity
- })
-
- stock_entry.insert()
- stock_entry.submit()
-
- self.stock_entry = stock_entry.name
+ stock_entry = frappe.get_doc('Stock Entry', self.stock_entry)
+ stock_entry.cancel()
def make_gl_entries(self, cancel=False):
if flt(self.repair_cost) > 0:
From 307fe43e08919252c983935779b92f5679c5a307 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Tue, 22 Jun 2021 17:16:12 +0530
Subject: [PATCH 071/386] fix: Remove changes made to Asset Maintenance
---
.../asset_maintenance/asset_maintenance.js | 3 --
.../asset_maintenance/asset_maintenance.json | 31 +---------------
.../asset_maintenance/asset_maintenance.py | 37 +------------------
3 files changed, 3 insertions(+), 68 deletions(-)
diff --git a/erpnext/assets/doctype/asset_maintenance/asset_maintenance.js b/erpnext/assets/doctype/asset_maintenance/asset_maintenance.js
index 19393b7e9d..70b8654509 100644
--- a/erpnext/assets/doctype/asset_maintenance/asset_maintenance.js
+++ b/erpnext/assets/doctype/asset_maintenance/asset_maintenance.js
@@ -30,10 +30,7 @@ frappe.ui.form.on('Asset Maintenance', {
if(!frm.is_new()) {
frm.trigger('make_dashboard');
}
-
- frm.toggle_display(['stock_consumption_details_section'], frm.doc.stock_consumption);
},
-
make_dashboard: (frm) => {
if(!frm.is_new()) {
frappe.call({
diff --git a/erpnext/assets/doctype/asset_maintenance/asset_maintenance.json b/erpnext/assets/doctype/asset_maintenance/asset_maintenance.json
index 63a55389d8..c0c2566fe2 100644
--- a/erpnext/assets/doctype/asset_maintenance/asset_maintenance.json
+++ b/erpnext/assets/doctype/asset_maintenance/asset_maintenance.json
@@ -12,17 +12,13 @@
"column_break_3",
"item_code",
"item_name",
- "stock_consumption",
"section_break_6",
"maintenance_team",
"column_break_9",
"maintenance_manager",
"maintenance_manager_name",
"section_break_8",
- "asset_maintenance_tasks",
- "stock_consumption_details_section",
- "warehouse",
- "stock_items"
+ "asset_maintenance_tasks"
],
"fields": [
{
@@ -104,33 +100,10 @@
"label": "Maintenance Tasks",
"options": "Asset Maintenance Task",
"reqd": 1
- },
- {
- "default": "0",
- "fieldname": "stock_consumption",
- "fieldtype": "Check",
- "label": "Stock Consumed During Maintenance"
- },
- {
- "fieldname": "stock_consumption_details_section",
- "fieldtype": "Section Break",
- "label": "Stock Consumption Details"
- },
- {
- "fieldname": "warehouse",
- "fieldtype": "Link",
- "label": "Warehouse",
- "options": "Warehouse"
- },
- {
- "fieldname": "stock_items",
- "fieldtype": "Table",
- "label": "Stock Items",
- "options": "Asset Repair Consumed Item"
}
],
"links": [],
- "modified": "2021-06-21 14:53:46.041123",
+ "modified": "2020-05-28 20:28:32.993823",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Maintenance",
diff --git a/erpnext/assets/doctype/asset_maintenance/asset_maintenance.py b/erpnext/assets/doctype/asset_maintenance/asset_maintenance.py
index e3e654c398..a506deec93 100644
--- a/erpnext/assets/doctype/asset_maintenance/asset_maintenance.py
+++ b/erpnext/assets/doctype/asset_maintenance/asset_maintenance.py
@@ -19,45 +19,10 @@ class AssetMaintenance(Document):
if not task.assign_to and self.docstatus == 0:
throw(_("Row #{}: Please asign task to a member.").format(task.idx))
- if self.stock_consumption:
- self.check_for_stock_items_and_warehouse()
- self.increase_asset_value()
- self.decrease_stock_quantity()
-
def on_update(self):
for task in self.get('asset_maintenance_tasks'):
assign_tasks(self.name, task.assign_to, task.maintenance_task, task.next_due_date)
- self.sync_maintenance_tasks()
-
- def check_for_stock_items_and_warehouse(self):
- if self.stock_consumption:
- if not self.stock_items:
- frappe.throw(_("Please enter Stock Items consumed during Asset Maintenance."))
- if not self.warehouse:
- frappe.throw(_("Please enter Warehouse from which Stock Items consumed during Asset Maintenance were taken."))
-
- def increase_asset_value(self):
- asset_value = frappe.db.get_value('Asset', self.asset_name, 'asset_value')
- for item in self.stock_items:
- asset_value += item.total_value
-
- frappe.db.set_value('Asset', self.asset_name, 'asset_value', asset_value)
-
- def decrease_stock_quantity(self):
- stock_entry = frappe.get_doc({
- "doctype": "Stock Entry",
- "stock_entry_type": "Material Issue"
- })
-
- for stock_item in self.stock_items:
- stock_entry.append('items', {
- "s_warehouse": self.warehouse,
- "item_code": stock_item.item,
- "qty": stock_item.consumed_quantity
- })
-
- stock_entry.insert()
- stock_entry.submit()
+ self.sync_maintenance_tasks()
def sync_maintenance_tasks(self):
tasks_names = []
From 72ea64f6ac3de658758dd9249d361f28337053e5 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Tue, 22 Jun 2021 17:24:14 +0530
Subject: [PATCH 072/386] fix: Sider issues
---
erpnext/assets/doctype/asset_repair/asset_repair.py | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.py b/erpnext/assets/doctype/asset_repair/asset_repair.py
index 0049dcaded..6054258ea6 100644
--- a/erpnext/assets/doctype/asset_repair/asset_repair.py
+++ b/erpnext/assets/doctype/asset_repair/asset_repair.py
@@ -14,6 +14,9 @@ class AssetRepair(AccountsController):
def validate(self):
self.asset_doc = frappe.get_doc('Asset', self.asset)
self.update_status()
+
+ if self.get('stock_items'):
+ self.set_total_value()
self.calculate_total_repair_cost()
def update_status(self):
@@ -22,6 +25,10 @@ class AssetRepair(AccountsController):
else:
self.asset_doc.set_status()
+ def set_total_value(self):
+ for item in self.get('stock_items'):
+ item.total_value = flt(item.valuation_rate) * flt(item.consumed_quantity)
+
def calculate_total_repair_cost(self):
self.total_repair_cost = self.repair_cost
From 3ba9fb32de38fbaaa3109938308b84ab3c9b31e6 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Wed, 23 Jun 2021 13:26:47 +0530
Subject: [PATCH 073/386] fix(Asset Repair): Replace asset_value with
value_after_depreciation in tests
---
.../doctype/asset_repair/test_asset_repair.py | 15 +++++++++------
1 file changed, 9 insertions(+), 6 deletions(-)
diff --git a/erpnext/assets/doctype/asset_repair/test_asset_repair.py b/erpnext/assets/doctype/asset_repair/test_asset_repair.py
index d1b417fd38..52a960e850 100644
--- a/erpnext/assets/doctype/asset_repair/test_asset_repair.py
+++ b/erpnext/assets/doctype/asset_repair/test_asset_repair.py
@@ -74,21 +74,21 @@ class TestAssetRepair(unittest.TestCase):
self.assertEqual(stock_entry.items[0].qty, asset_repair.stock_items[0].consumed_quantity)
def test_increase_in_asset_value_due_to_stock_consumption(self):
- asset = create_asset()
- initial_asset_value = asset.asset_value
+ asset = create_asset(calculate_depreciation = 1)
+ initial_asset_value = get_asset_value(asset)
asset_repair = create_asset_repair(asset= asset, stock_consumption = 1, submit = 1)
asset.reload()
- increase_in_asset_value = asset.asset_value - initial_asset_value
+ increase_in_asset_value = get_asset_value(asset) - initial_asset_value
self.assertEqual(asset_repair.stock_items[0].total_value, increase_in_asset_value)
def test_increase_in_asset_value_due_to_repair_cost_capitalisation(self):
- asset = create_asset()
- initial_asset_value = asset.asset_value
+ asset = create_asset(calculate_depreciation = 1)
+ initial_asset_value = get_asset_value(asset)
asset_repair = create_asset_repair(asset= asset, capitalize_repair_cost = 1, submit = 1)
asset.reload()
- increase_in_asset_value = asset.asset_value - initial_asset_value
+ increase_in_asset_value = get_asset_value(asset) - initial_asset_value
self.assertEqual(asset_repair.repair_cost, increase_in_asset_value)
def test_purchase_invoice(self):
@@ -109,6 +109,9 @@ class TestAssetRepair(unittest.TestCase):
self.assertEqual((initial_num_of_depreciations + 1), num_of_depreciations(asset))
self.assertEqual(asset.schedules[-1].accumulated_depreciation_amount, asset.finance_books[0].value_after_depreciation)
+def get_asset_value(asset):
+ return asset.finance_books[0].value_after_depreciation
+
def num_of_depreciations(asset):
return asset.finance_books[0].total_number_of_depreciations
From 39dba43b87423d82821b2da3dc87cf79c62025ca Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Wed, 23 Jun 2021 22:19:05 +0530
Subject: [PATCH 074/386] fix(Asset): Fix value_after_depreciation calculation
---
erpnext/assets/doctype/asset/asset.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py
index 63b70f6613..110922e66b 100644
--- a/erpnext/assets/doctype/asset/asset.py
+++ b/erpnext/assets/doctype/asset/asset.py
@@ -182,10 +182,10 @@ class Asset(AccountsController):
# value_after_depreciation - current Asset value
if d.value_after_depreciation:
value_after_depreciation = (flt(d.value_after_depreciation) -
- flt(self.opening_accumulated_depreciation)) - flt(d.expected_value_after_useful_life)
+ flt(self.opening_accumulated_depreciation))
else:
value_after_depreciation = (flt(self.gross_purchase_amount) -
- flt(self.opening_accumulated_depreciation)) - flt(d.expected_value_after_useful_life)
+ flt(self.opening_accumulated_depreciation))
d.value_after_depreciation = value_after_depreciation
From 18bbfdf343cca9bfed4dd648c5394cf6ced81bc9 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Wed, 23 Jun 2021 22:26:45 +0530
Subject: [PATCH 075/386] fix(Asset Repair): Remove test that's no longer
necessary
---
erpnext/assets/doctype/asset_repair/test_asset_repair.py | 6 ------
1 file changed, 6 deletions(-)
diff --git a/erpnext/assets/doctype/asset_repair/test_asset_repair.py b/erpnext/assets/doctype/asset_repair/test_asset_repair.py
index 52a960e850..b3d78b3bfb 100644
--- a/erpnext/assets/doctype/asset_repair/test_asset_repair.py
+++ b/erpnext/assets/doctype/asset_repair/test_asset_repair.py
@@ -13,12 +13,6 @@ class TestAssetRepair(unittest.TestCase):
create_asset_data()
frappe.db.sql("delete from `tabTax Rule`")
- def test_completion_date(self):
- asset_repair = create_asset_repair()
- asset_repair.repair_status = "Completed"
- asset_repair.save()
- self.assertTrue(asset_repair.completion_date)
-
def test_update_status(self):
asset = create_asset()
initial_status = asset.status
From f3ae1dd23b05aed611c657931583474f2b5070c2 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Thu, 24 Jun 2021 12:44:13 +0530
Subject: [PATCH 076/386] fix(Asset): Fix test
---
erpnext/assets/doctype/asset/test_asset.py | 1 -
1 file changed, 1 deletion(-)
diff --git a/erpnext/assets/doctype/asset/test_asset.py b/erpnext/assets/doctype/asset/test_asset.py
index f3667c7b95..32bdb5224a 100644
--- a/erpnext/assets/doctype/asset/test_asset.py
+++ b/erpnext/assets/doctype/asset/test_asset.py
@@ -125,7 +125,6 @@ class TestAsset(unittest.TestCase):
"frequency_of_depreciation": 12,
"depreciation_start_date": "2030-12-31"
})
- asset.insert()
self.assertEqual(asset.status, "Draft")
asset.save()
expected_schedules = [
From 81bcae7433206d99d6f5cffbe857b96478a14909 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Thu, 24 Jun 2021 13:22:26 +0530
Subject: [PATCH 077/386] fix(Asset): Remove redundant code
---
erpnext/assets/doctype/asset/test_asset.py | 12 +++---------
1 file changed, 3 insertions(+), 9 deletions(-)
diff --git a/erpnext/assets/doctype/asset/test_asset.py b/erpnext/assets/doctype/asset/test_asset.py
index 32bdb5224a..59fbe3b030 100644
--- a/erpnext/assets/doctype/asset/test_asset.py
+++ b/erpnext/assets/doctype/asset/test_asset.py
@@ -153,9 +153,8 @@ class TestAsset(unittest.TestCase):
"frequency_of_depreciation": 12,
"depreciation_start_date": '2030-12-31'
})
- asset.insert()
- self.assertEqual(asset.status, "Draft")
asset.save()
+ self.assertEqual(asset.status, "Draft")
expected_schedules = [
['2030-12-31', 66667.00, 66667.00],
@@ -184,7 +183,7 @@ class TestAsset(unittest.TestCase):
"frequency_of_depreciation": 12,
"depreciation_start_date": "2030-12-31"
})
- asset.insert()
+ asset.save()
self.assertEqual(asset.status, "Draft")
expected_schedules = [
@@ -215,7 +214,6 @@ class TestAsset(unittest.TestCase):
"depreciation_start_date": "2030-12-31"
})
- asset.insert()
asset.save()
expected_schedules = [
@@ -246,7 +244,6 @@ class TestAsset(unittest.TestCase):
"frequency_of_depreciation": 10,
"depreciation_start_date": "2020-12-31"
})
- asset.insert()
asset.submit()
asset.load_from_db()
self.assertEqual(asset.status, "Submitted")
@@ -349,7 +346,6 @@ class TestAsset(unittest.TestCase):
"frequency_of_depreciation": 10,
"depreciation_start_date": "2020-12-31"
})
- asset.insert()
asset.submit()
post_depreciation_entries(date="2021-01-01")
@@ -379,7 +375,6 @@ class TestAsset(unittest.TestCase):
"total_number_of_depreciations": 10,
"frequency_of_depreciation": 1
})
- asset.insert()
asset.submit()
post_depreciation_entries(date=add_months('2020-01-01', 4))
@@ -423,7 +418,6 @@ class TestAsset(unittest.TestCase):
"frequency_of_depreciation": 10,
"depreciation_start_date": "2020-12-31"
})
- asset.insert()
asset.submit()
post_depreciation_entries(date="2021-01-01")
@@ -467,7 +461,7 @@ class TestAsset(unittest.TestCase):
"total_number_of_depreciations": 3,
"frequency_of_depreciation": 10
})
- asset.insert()
+ asset.save()
accumulated_depreciation_after_full_schedule = \
max(d.accumulated_depreciation_amount for d in asset.get("schedules"))
From cba0966ec59e719ae52c10e38b234f4dd4958525 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Thu, 24 Jun 2021 14:56:34 +0530
Subject: [PATCH 078/386] fix(Asset Repair): Change controller hooks
---
erpnext/assets/doctype/asset_repair/asset_repair.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.py b/erpnext/assets/doctype/asset_repair/asset_repair.py
index 6054258ea6..64c51fd8c3 100644
--- a/erpnext/assets/doctype/asset_repair/asset_repair.py
+++ b/erpnext/assets/doctype/asset_repair/asset_repair.py
@@ -35,7 +35,7 @@ class AssetRepair(AccountsController):
total_value_of_stock_consumed = self.get_total_value_of_stock_consumed()
self.total_repair_cost += total_value_of_stock_consumed
- def on_submit(self):
+ def before_submit(self):
self.check_repair_status()
if self.get('stock_consumption') or self.get('capitalize_repair_cost'):
@@ -52,7 +52,7 @@ class AssetRepair(AccountsController):
self.asset_doc.prepare_depreciation_data()
self.asset_doc.save()
- def on_cancel(self):
+ def before_cancel(self):
self.asset_doc = frappe.get_doc('Asset', self.asset)
if self.get('stock_consumption') or self.get('capitalize_repair_cost'):
From 7c37e83535b0c2a7ddc7ff50718fb1ed3e69409c Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Thu, 24 Jun 2021 15:04:44 +0530
Subject: [PATCH 079/386] fix(Asset): Remove to_date field
---
erpnext/assets/doctype/asset/asset.json | 9 +--------
1 file changed, 1 insertion(+), 8 deletions(-)
diff --git a/erpnext/assets/doctype/asset/asset.json b/erpnext/assets/doctype/asset/asset.json
index d77eb10418..de060757e2 100644
--- a/erpnext/assets/doctype/asset/asset.json
+++ b/erpnext/assets/doctype/asset/asset.json
@@ -53,7 +53,6 @@
"next_depreciation_date",
"section_break_14",
"schedules",
- "to_date",
"insurance_details",
"policy_number",
"insurer",
@@ -481,12 +480,6 @@
"fieldname": "section_break_36",
"fieldtype": "Section Break",
"label": "Finance Books"
- },
- {
- "fieldname": "to_date",
- "fieldtype": "Date",
- "hidden": 1,
- "label": "To Date"
}
],
"idx": 72,
@@ -509,7 +502,7 @@
"link_fieldname": "asset"
}
],
- "modified": "2021-06-19 13:56:58.450182",
+ "modified": "2021-06-24 14:58:51.097908",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset",
From 597016bb34942170354994f7b90eeb6b529c60f5 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Thu, 24 Jun 2021 22:18:59 +0530
Subject: [PATCH 080/386] fix(Asset): Remove extra tabs
---
erpnext/assets/doctype/asset/asset.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py
index 110922e66b..0e1bba6362 100644
--- a/erpnext/assets/doctype/asset/asset.py
+++ b/erpnext/assets/doctype/asset/asset.py
@@ -196,7 +196,7 @@ class Asset(AccountsController):
if has_pro_rata:
number_of_pending_depreciations += 1
-
+
skip_row = False
for n in range(start, number_of_pending_depreciations):
# If depreciation is already completed (for double declining balance)
From 267fed2d239b240e12f3d4526e1db79c3ce8dd92 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Thu, 24 Jun 2021 22:21:08 +0530
Subject: [PATCH 081/386] fix(Asset): Add comment
---
erpnext/assets/doctype/asset/asset.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py
index 0e1bba6362..2fe71672b3 100644
--- a/erpnext/assets/doctype/asset/asset.py
+++ b/erpnext/assets/doctype/asset/asset.py
@@ -224,6 +224,7 @@ class Asset(AccountsController):
# For last row
elif has_pro_rata and n == cint(number_of_pending_depreciations) - 1:
if not self.flags.increase_in_asset_life:
+ # In case of increase_in_asset_life, the self.to_date is already set on asset_repair submission
self.to_date = add_months(self.available_for_use_date,
n * cint(d.frequency_of_depreciation))
From c8caafa680edeeea0f16655bed200187be4010b8 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Thu, 24 Jun 2021 22:25:45 +0530
Subject: [PATCH 082/386] fix(Asset Repair): Move filters for cost_center,
warehouse and project to setup
---
.../doctype/asset_repair/asset_repair.js | 56 ++++++++++---------
1 file changed, 29 insertions(+), 27 deletions(-)
diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.js b/erpnext/assets/doctype/asset_repair/asset_repair.js
index 91bed4fdd0..1cebfff66e 100644
--- a/erpnext/assets/doctype/asset_repair/asset_repair.js
+++ b/erpnext/assets/doctype/asset_repair/asset_repair.js
@@ -2,6 +2,34 @@
// For license information, please see license.txt
frappe.ui.form.on('Asset Repair', {
+ setup: function(frm) {
+ frm.fields_dict.cost_center.get_query = function(doc) {
+ return {
+ filters: {
+ 'is_group': 0,
+ 'company': doc.company
+ }
+ };
+ };
+
+ frm.fields_dict.project.get_query = function(doc) {
+ return {
+ filters: {
+ 'company': doc.company
+ }
+ };
+ };
+
+ frm.fields_dict.warehouse.get_query = function(doc) {
+ return {
+ filters: {
+ 'is_group': 0,
+ 'company': doc.company
+ }
+ };
+ };
+ },
+
refresh: function(frm) {
if (frm.doc.docstatus) {
frm.add_custom_button("View General Ledger", function() {
@@ -40,30 +68,4 @@ frappe.ui.form.on('Asset Repair Consumed Item', {
var row = locals[cdt][cdn];
frappe.model.set_value(cdt, cdn, 'total_value', row.consumed_quantity * row.valuation_rate);
},
-});
-
-cur_frm.fields_dict.cost_center.get_query = function(doc) {
- return {
- filters: {
- 'is_group': 0,
- 'company': doc.company
- }
- };
-};
-
-cur_frm.fields_dict.project.get_query = function(doc) {
- return {
- filters: {
- 'company': doc.company
- }
- };
-};
-
-cur_frm.fields_dict.warehouse.get_query = function(doc) {
- return {
- filters: {
- 'is_group': 0,
- 'company': doc.company
- }
- };
-};
\ No newline at end of file
+});
\ No newline at end of file
From e328e3b48a51fb44b2fd744d80421bb555f777d1 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Thu, 24 Jun 2021 22:27:30 +0530
Subject: [PATCH 083/386] fix(Asset Repair): Edit description for
total_repair_cost
---
erpnext/assets/doctype/asset_repair/asset_repair.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.json b/erpnext/assets/doctype/asset_repair/asset_repair.json
index 14f18b5309..3f62443bda 100644
--- a/erpnext/assets/doctype/asset_repair/asset_repair.json
+++ b/erpnext/assets/doctype/asset_repair/asset_repair.json
@@ -211,7 +211,7 @@
},
{
"depends_on": "eval: doc.stock_consumption && doc.total_repair_cost > 0",
- "description": "Sum of Repair Cost and the total value of all Stock Items consumed during the repair.",
+ "description": "Sum of Repair Cost and Value of Consumed Stock Items.",
"fieldname": "total_repair_cost",
"fieldtype": "Currency",
"label": "Total Repair Cost",
From fd7fb37697a7720f9e752588799514f917416648 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Thu, 24 Jun 2021 22:30:08 +0530
Subject: [PATCH 084/386] fix(Asset Repair): Simplify code for Asset Repair
creation in tests
---
erpnext/assets/doctype/asset_repair/test_asset_repair.py | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/erpnext/assets/doctype/asset_repair/test_asset_repair.py b/erpnext/assets/doctype/asset_repair/test_asset_repair.py
index b3d78b3bfb..30bbb37851 100644
--- a/erpnext/assets/doctype/asset_repair/test_asset_repair.py
+++ b/erpnext/assets/doctype/asset_repair/test_asset_repair.py
@@ -138,10 +138,7 @@ def create_asset_repair(**args):
"consumed_quantity": args.qty or 1
})
- try:
- asset_repair.save()
- except frappe.DuplicateEntryError:
- pass
+ asset_repair.insert(ignore_if_duplicate=True)
if args.submit:
asset_repair.repair_status = "Completed"
From 073b50f7fd0a6c89f86d09bb5b497d7e3a2b188d Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Sat, 26 Jun 2021 01:32:17 +0530
Subject: [PATCH 085/386] fix(Asset Repair): Rearrange fields
---
erpnext/assets/doctype/asset_repair/asset_repair.json | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.json b/erpnext/assets/doctype/asset_repair/asset_repair.json
index 3f62443bda..19528a26cc 100644
--- a/erpnext/assets/doctype/asset_repair/asset_repair.json
+++ b/erpnext/assets/doctype/asset_repair/asset_repair.json
@@ -8,10 +8,10 @@
"engine": "InnoDB",
"field_order": [
"asset",
- "naming_series",
+ "company",
"column_break_2",
"asset_name",
- "company",
+ "naming_series",
"section_break_5",
"failure_date",
"repair_status",
@@ -263,7 +263,7 @@
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
- "modified": "2021-06-21 14:53:46.665576",
+ "modified": "2021-06-25 13:14:38.307723",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Repair",
From 2e507b47a8f82b62cf4674fe962cf6cc9e035da1 Mon Sep 17 00:00:00 2001
From: Saqib
Date: Mon, 28 Jun 2021 11:42:28 +0530
Subject: [PATCH 086/386] fix(Asset Repair): cancellation
---
erpnext/assets/doctype/asset_repair/asset_repair.py | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.py b/erpnext/assets/doctype/asset_repair/asset_repair.py
index 64c51fd8c3..d32fdf7054 100644
--- a/erpnext/assets/doctype/asset_repair/asset_repair.py
+++ b/erpnext/assets/doctype/asset_repair/asset_repair.py
@@ -30,7 +30,7 @@ class AssetRepair(AccountsController):
item.total_value = flt(item.valuation_rate) * flt(item.consumed_quantity)
def calculate_total_repair_cost(self):
- self.total_repair_cost = self.repair_cost
+ self.total_repair_cost = flt(self.repair_cost)
total_value_of_stock_consumed = self.get_total_value_of_stock_consumed()
self.total_repair_cost += total_value_of_stock_consumed
@@ -129,6 +129,7 @@ class AssetRepair(AccountsController):
def increase_stock_quantity(self):
stock_entry = frappe.get_doc('Stock Entry', self.stock_entry)
+ stock_entry.flags.ignore_links = True
stock_entry.cancel()
def make_gl_entries(self, cancel=False):
@@ -252,4 +253,4 @@ class AssetRepair(AccountsController):
@frappe.whitelist()
def get_downtime(failure_date, completion_date):
downtime = time_diff_in_hours(completion_date, failure_date)
- return round(downtime, 2)
\ No newline at end of file
+ return round(downtime, 2)
From 40793f4a18c4a23d1414654116657323d7ea800c Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Tue, 13 Jul 2021 13:17:19 +0530
Subject: [PATCH 087/386] test: introduce cypress tests
Co-authored-by: Ankush
Co-authored-by: Nabin Hait
---
.eslintrc | 6 +-
.github/helper/install.sh | 2 +-
.github/workflows/ui-tests.yml | 108 +++++++++++++++++++++++++++
cypress.json | 11 +++
cypress/fixtures/example.json | 5 ++
cypress/integration/test_customer.js | 13 ++++
cypress/plugins/index.js | 17 +++++
cypress/support/commands.js | 31 ++++++++
cypress/support/index.js | 26 +++++++
cypress/tsconfig.json | 12 +++
10 files changed, 229 insertions(+), 2 deletions(-)
create mode 100644 .github/workflows/ui-tests.yml
create mode 100644 cypress.json
create mode 100644 cypress/fixtures/example.json
create mode 100644 cypress/integration/test_customer.js
create mode 100644 cypress/plugins/index.js
create mode 100644 cypress/support/commands.js
create mode 100644 cypress/support/index.js
create mode 100644 cypress/tsconfig.json
diff --git a/.eslintrc b/.eslintrc
index 3b6ab7498d..ecfaab23ee 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -147,10 +147,14 @@
"Chart": true,
"Cypress": true,
"cy": true,
+ "describe": true,
+ "expect": true,
"it": true,
"context": true,
"before": true,
"beforeEach": true,
- "onScan": true
+ "onScan": true,
+ "extend_cscript": true,
+ "localforage": true
}
}
diff --git a/.github/helper/install.sh b/.github/helper/install.sh
index 7b0f944c66..a6a6069d35 100644
--- a/.github/helper/install.sh
+++ b/.github/helper/install.sh
@@ -42,5 +42,5 @@ sed -i 's/socketio:/# socketio:/g' Procfile
sed -i 's/redis_socketio:/# redis_socketio:/g' Procfile
bench get-app erpnext "${GITHUB_WORKSPACE}"
-bench start &
+bench start &> bench_run_logs.txt &
bench --site test_site reinstall --yes
diff --git a/.github/workflows/ui-tests.yml b/.github/workflows/ui-tests.yml
new file mode 100644
index 0000000000..412a05b0a1
--- /dev/null
+++ b/.github/workflows/ui-tests.yml
@@ -0,0 +1,108 @@
+name: UI
+
+on:
+ pull_request:
+ workflow_dispatch:
+
+jobs:
+ test:
+ runs-on: ubuntu-18.04
+
+ strategy:
+ fail-fast: false
+
+ name: UI Tests (Cypress)
+
+ services:
+ mysql:
+ image: mariadb:10.3
+ env:
+ MYSQL_ALLOW_EMPTY_PASSWORD: YES
+ ports:
+ - 3306:3306
+ options: --health-cmd="mysqladmin ping" --health-interval=5s --health-timeout=2s --health-retries=3
+
+ steps:
+ - name: Clone
+ uses: actions/checkout@v2
+
+ - name: Setup Python
+ uses: actions/setup-python@v2
+ with:
+ python-version: 3.7
+
+ - uses: actions/setup-node@v2
+ with:
+ node-version: 14
+ check-latest: true
+
+ - name: Add to Hosts
+ run: |
+ echo "127.0.0.1 test_site" | sudo tee -a /etc/hosts
+
+ - name: Cache pip
+ uses: actions/cache@v2
+ with:
+ path: ~/.cache/pip
+ key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
+ restore-keys: |
+ ${{ runner.os }}-pip-
+ ${{ runner.os }}-
+
+ - name: Cache node modules
+ uses: actions/cache@v2
+ env:
+ cache-name: cache-node-modules
+ with:
+ path: ~/.npm
+ key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
+ restore-keys: |
+ ${{ runner.os }}-build-${{ env.cache-name }}-
+ ${{ runner.os }}-build-
+ ${{ runner.os }}-
+
+ - name: Get yarn cache directory path
+ id: yarn-cache-dir-path
+ run: echo "::set-output name=dir::$(yarn cache dir)"
+
+ - uses: actions/cache@v2
+ id: yarn-cache
+ with:
+ path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
+ key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
+ restore-keys: |
+ ${{ runner.os }}-yarn-
+
+ - name: Cache cypress binary
+ uses: actions/cache@v2
+ with:
+ path: ~/.cache
+ key: ${{ runner.os }}-cypress-
+ restore-keys: |
+ ${{ runner.os }}-cypress-
+ ${{ runner.os }}-
+
+ - name: Install
+ run: bash ${GITHUB_WORKSPACE}/.github/helper/install.sh
+ env:
+ DB: mariadb
+ TYPE: ui
+
+ - name: Site Setup
+ run: cd ~/frappe-bench/ && bench --site test_site execute erpnext.setup.utils.before_tests
+
+ - name: cypress pre-requisites
+ run: cd ~/frappe-bench/apps/frappe && yarn add cypress-file-upload@^5 --no-lockfile
+
+
+ - name: Build Assets
+ run: cd ~/frappe-bench/ && bench build
+
+ - name: UI Tests
+ run: cd ~/frappe-bench/ && bench --site test_site run-ui-tests erpnext --headless
+ env:
+ CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
+
+ - name: Show bench console if tests failed
+ if: ${{ failure() }}
+ run: cat ~/frappe-bench/bench_run_logs.txt
diff --git a/cypress.json b/cypress.json
new file mode 100644
index 0000000000..2f5026f62c
--- /dev/null
+++ b/cypress.json
@@ -0,0 +1,11 @@
+{
+ "baseUrl": "http://test_site:8000/",
+ "projectId": "da59y9",
+ "adminPassword": "admin",
+ "defaultCommandTimeout": 20000,
+ "pageLoadTimeout": 15000,
+ "retries": {
+ "runMode": 2,
+ "openMode": 2
+ }
+}
\ No newline at end of file
diff --git a/cypress/fixtures/example.json b/cypress/fixtures/example.json
new file mode 100644
index 0000000000..da18d9352a
--- /dev/null
+++ b/cypress/fixtures/example.json
@@ -0,0 +1,5 @@
+{
+ "name": "Using fixtures to represent data",
+ "email": "hello@cypress.io",
+ "body": "Fixtures are a great way to mock data for responses to routes"
+}
\ No newline at end of file
diff --git a/cypress/integration/test_customer.js b/cypress/integration/test_customer.js
new file mode 100644
index 0000000000..3d6ed5d0d8
--- /dev/null
+++ b/cypress/integration/test_customer.js
@@ -0,0 +1,13 @@
+
+context('Customer', () => {
+ before(() => {
+ cy.login();
+ });
+ it('Check Customer Group', () => {
+ cy.visit(`app/customer/`);
+ cy.get('.primary-action').click();
+ cy.wait(500);
+ cy.get('.custom-actions > .btn').click();
+ cy.get_field('customer_group', 'Link').should('have.value', 'All Customer Groups');
+ });
+});
diff --git a/cypress/plugins/index.js b/cypress/plugins/index.js
new file mode 100644
index 0000000000..07d9804a73
--- /dev/null
+++ b/cypress/plugins/index.js
@@ -0,0 +1,17 @@
+// ***********************************************************
+// This example plugins/index.js can be used to load plugins
+//
+// You can change the location of this file or turn off loading
+// the plugins file with the 'pluginsFile' configuration option.
+//
+// You can read more here:
+// https://on.cypress.io/plugins-guide
+// ***********************************************************
+
+// This function is called when a project is opened or re-opened (e.g. due to
+// the project's config changing)
+
+module.exports = () => {
+ // `on` is used to hook into various events Cypress emits
+ // `config` is the resolved Cypress config
+};
diff --git a/cypress/support/commands.js b/cypress/support/commands.js
new file mode 100644
index 0000000000..7ddc80ab8d
--- /dev/null
+++ b/cypress/support/commands.js
@@ -0,0 +1,31 @@
+// ***********************************************
+// This example commands.js shows you how to
+// create various custom commands and overwrite
+// existing commands.
+//
+// For more comprehensive examples of custom
+// commands please read more here:
+// https://on.cypress.io/custom-commands
+// ***********************************************
+//
+//
+// -- This is a parent command --
+// Cypress.Commands.add("login", (email, password) => { ... });
+//
+//
+// -- This is a child command --
+// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... });
+//
+//
+// -- This is a dual command --
+// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... });
+//
+//
+// -- This is will overwrite an existing command --
+// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... });
+
+const slug = (name) => name.toLowerCase().replace(" ", "-");
+
+Cypress.Commands.add("go_to_doc", (doctype, name) => {
+ cy.visit(`/app/${slug(doctype)}/${encodeURIComponent(name)}`);
+});
diff --git a/cypress/support/index.js b/cypress/support/index.js
new file mode 100644
index 0000000000..72070cc81c
--- /dev/null
+++ b/cypress/support/index.js
@@ -0,0 +1,26 @@
+// ***********************************************************
+// This example support/index.js is processed and
+// loaded automatically before your test files.
+//
+// This is a great place to put global configuration and
+// behavior that modifies Cypress.
+//
+// You can change the location of this file or turn off
+// automatically serving support files with the
+// 'supportFile' configuration option.
+//
+// You can read more here:
+// https://on.cypress.io/configuration
+// ***********************************************************
+
+// Import commands.js using ES2015 syntax:
+import './commands';
+import '../../../frappe/cypress/support/commands' // eslint-disable-line
+
+
+// Alternatively you can use CommonJS syntax:
+// require('./commands')
+
+Cypress.Cookies.defaults({
+ preserve: 'sid'
+});
diff --git a/cypress/tsconfig.json b/cypress/tsconfig.json
new file mode 100644
index 0000000000..d90ebf6856
--- /dev/null
+++ b/cypress/tsconfig.json
@@ -0,0 +1,12 @@
+{
+ "compilerOptions": {
+ "allowJs": true,
+ "baseUrl": "../node_modules",
+ "types": [
+ "cypress"
+ ]
+ },
+ "include": [
+ "**/*.*"
+ ]
+}
\ No newline at end of file
From f004b404d1ed344790600d3a1d2e038a53370031 Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Wed, 14 Jul 2021 23:50:54 +0530
Subject: [PATCH 088/386] test: UI tests for org chart desktop
---
.../test_organizational_chart_desktop.js | 102 ++++++++++++++++++
.../hierarchy_chart_desktop.js | 3 +-
erpnext/tests/ui_test_helpers.py | 53 +++++++++
3 files changed, 157 insertions(+), 1 deletion(-)
create mode 100644 cypress/integration/test_organizational_chart_desktop.js
create mode 100644 erpnext/tests/ui_test_helpers.py
diff --git a/cypress/integration/test_organizational_chart_desktop.js b/cypress/integration/test_organizational_chart_desktop.js
new file mode 100644
index 0000000000..d50d551330
--- /dev/null
+++ b/cypress/integration/test_organizational_chart_desktop.js
@@ -0,0 +1,102 @@
+context('Organizational Chart', () => {
+ before(() => {
+ cy.login();
+ cy.visit('/app/website');
+
+ cy.visit(`app/organizational-chart`);
+ cy.fill_field('company', 'Test Org Chart');
+ cy.get('body').click();
+ cy.wait(500);
+ });
+
+ beforeEach(() => {
+ cy.window().its('frappe').then(frappe => {
+ return frappe.call('erpnext.tests.ui_test_helpers.create_employee_records');
+ }).as('employee_records');
+ });
+
+ it('renders root nodes and loads children for the first expandable node', () => {
+ // check rendered root nodes and the node name, title, connections
+ cy.get('.hierarchy').find('.root-level ul.node-children').children()
+ .should('have.length', 2)
+ .first()
+ .as('first-child');
+
+ cy.get('@first-child').get('.node-name').contains('Test Employee 1');
+ cy.get('@first-child').get('.node-info').find('.node-title').contains('CEO');
+ cy.get('@first-child').get('.node-info').find('.node-connections').contains('· 2 Connections');
+
+ // check children of first node
+ cy.get('@employee_records').then(employee_records => {
+ // children of 1st root visible
+ cy.get(`[data-parent="${employee_records.message[0]}"]`).as('child-node')
+ cy.get('@child-node')
+ .should('have.length', 1)
+ .should('be.visible');
+ cy.get('@child-node').get('.node-name').contains('Test Employee 3');
+
+ // connectors between first root node and immediate child
+ cy.get(`path[data-parent="${employee_records.message[0]}"]`)
+ .should('be.visible')
+ .invoke('attr', 'data-child')
+ .should('equal', employee_records.message[2]);
+ });
+ });
+
+ it('hides active nodes children and connectors on expanding sibling node', () => {
+ cy.get('@employee_records').then(employee_records => {
+ // click sibling
+ cy.get(`#${employee_records.message[1]}`)
+ .click()
+ .should('have.class', 'active');
+
+ // child nodes and connectors hidden
+ cy.get(`[data-parent="${employee_records.message[0]}"]`).should('not.be.visible');
+ cy.get(`path[data-parent="${employee_records.message[0]}"]`).should('not.be.visible');
+ });
+ });
+
+ it('collapses previous level nodes and refreshes connectors on expanding child node', () => {
+ cy.get('@employee_records').then(employee_records => {
+ // click child node
+ cy.get(`#${employee_records.message[3]}`)
+ .click()
+ .should('have.class', 'active');
+
+ // previous level nodes: parent should be on active-path; other nodes should be collapsed
+ cy.get(`#${employee_records.message[0]}`).should('have.class', 'collapsed');
+ cy.get(`#${employee_records.message[1]}`).should('have.class', 'active-path');
+
+ // previous level connectors refreshed
+ cy.get(`path[data-parent="${employee_records.message[1]}"]`)
+ .should('have.class', 'collapsed-connector');
+
+ // child node's children and connectors rendered
+ cy.get(`[data-parent="${employee_records.message[3]}"]`).should('be.visible');
+ cy.get(`path[data-parent="${employee_records.message[3]}"]`).should('be.visible');
+ });
+ });
+
+ it('expands previous level nodes', () => {
+ cy.get('@employee_records').then(employee_records => {
+ cy.get(`#${employee_records.message[0]}`)
+ .click()
+ .should('have.class', 'active');
+
+ cy.get(`[data-parent="${employee_records.message[0]}"]`)
+ .should('be.visible');
+
+ cy.get('ul.hierarchy').children().should('have.length', 2);
+ cy.get(`#connectors`).children().should('have.length', 1);
+ });
+ });
+
+ it('edit node navigates to employee master', () => {
+ cy.get('@employee_records').then(employee_records => {
+ cy.get(`#${employee_records.message[0]}`).find('.btn-edit-node')
+ .click();
+
+ cy.url().should('include', `/employee/${employee_records.message[0]}`);
+ });
+ });
+});
diff --git a/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js b/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
index 374787c6ef..fe4d17c210 100644
--- a/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
+++ b/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
@@ -49,7 +49,8 @@ erpnext.HierarchyChart = class {
title: node.title,
image: node.image,
parent: node.parent_id,
- connections: node.connections
+ connections: node.connections,
+ is_mobile: false
});
node.parent.append(node_card);
diff --git a/erpnext/tests/ui_test_helpers.py b/erpnext/tests/ui_test_helpers.py
new file mode 100644
index 0000000000..8e67b1cd34
--- /dev/null
+++ b/erpnext/tests/ui_test_helpers.py
@@ -0,0 +1,53 @@
+import frappe
+from frappe import _
+from frappe.utils import getdate
+
+@frappe.whitelist()
+def create_employee_records():
+ company = create_company()
+ create_missing_designation()
+
+ emp1 = create_employee('Test Employee 1', 'CEO')
+ emp2 = create_employee('Test Employee 2', 'CTO')
+ emp3 = create_employee('Test Employee 3', 'Head of Marketing and Sales', emp1)
+ emp4 = create_employee('Test Employee 4', 'Project Manager', emp2)
+ emp5 = create_employee('Test Employee 5', 'Analyst', emp3)
+ emp6 = create_employee('Test Employee 6', 'Software Developer', emp4)
+
+ employees = [emp1, emp2, emp3, emp4, emp5, emp6]
+ return employees
+
+def create_company():
+ company = frappe.db.exists('Company', 'Test Org Chart')
+ if not company:
+ company = frappe.get_doc({
+ 'doctype': 'Company',
+ 'company_name': 'Test Org Chart',
+ 'country': 'India',
+ 'default_currency': 'INR'
+ }).insert().name
+
+ return company
+
+def create_employee(first_name, designation, reports_to=None):
+ employee = frappe.db.exists('Employee', {'first_name': first_name, 'designation': designation})
+ if not employee:
+ employee = frappe.get_doc({
+ 'doctype': 'Employee',
+ 'first_name': first_name,
+ 'company': 'Test Org Chart',
+ 'gender': 'Female',
+ 'date_of_birth': getdate('08-12-1998'),
+ 'date_of_joining': getdate('01-01-2021'),
+ 'designation': designation,
+ 'reports_to': reports_to
+ }).insert().name
+
+ return employee
+
+def create_missing_designation():
+ if not frappe.db.exists('Designation', 'CTO'):
+ frappe.get_doc({
+ 'doctype': 'Designation',
+ 'designation_name': 'CTO'
+ }).insert()
\ No newline at end of file
From ee7eaf9c70484dec3db6f282ca2f74a4a4ac2a2d Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Thu, 15 Jul 2021 19:19:09 +0530
Subject: [PATCH 089/386] test: UI tests for org chart mobile
fix(mobile): detach node before emptying hierarchy
fix(mobile): sibling group not rendering for first level
---
.../test_organizational_chart_mobile.js | 182 ++++++++++++++++++
.../hierarchy_chart/hierarchy_chart_mobile.js | 13 +-
erpnext/tests/ui_test_helpers.py | 7 +-
3 files changed, 195 insertions(+), 7 deletions(-)
create mode 100644 cypress/integration/test_organizational_chart_mobile.js
diff --git a/cypress/integration/test_organizational_chart_mobile.js b/cypress/integration/test_organizational_chart_mobile.js
new file mode 100644
index 0000000000..656051289f
--- /dev/null
+++ b/cypress/integration/test_organizational_chart_mobile.js
@@ -0,0 +1,182 @@
+context('Organizational Chart Mobile', () => {
+ before(() => {
+ cy.login();
+ cy.viewport(375, 667);
+ cy.visit('/app/website');
+
+ cy.visit(`app/organizational-chart`);
+ cy.wait(500);
+ cy.fill_field('company', 'Test Org Chart');
+ cy.get('body').click();
+ cy.wait(500);
+ });
+
+ beforeEach(() => {
+ cy.viewport(375, 667);
+ cy.wait(500);
+
+ cy.window().its('frappe').then(frappe => {
+ return frappe.call('erpnext.tests.ui_test_helpers.create_employee_records');
+ }).as('employee_records');
+ });
+
+ it('renders root nodes', () => {
+ // check rendered root nodes and the node name, title, connections
+ cy.get('.hierarchy-mobile').find('.root-level').children()
+ .should('have.length', 2)
+ .first()
+ .as('first-child');
+
+ cy.get('@first-child').get('.node-name').contains('Test Employee 1');
+ cy.get('@first-child').get('.node-info').find('.node-title').contains('CEO');
+ cy.get('@first-child').get('.node-info').find('.node-connections').contains('· 2');
+ });
+
+ it('expands root node', () => {
+ cy.get('@employee_records').then(employee_records => {
+ cy.get(`#${employee_records.message[1]}`)
+ .click()
+ .should('have.class', 'active');
+
+ // other root node removed
+ cy.get(`#${employee_records.message[0]}`).should('not.exist');
+
+ // children of active root node
+ cy.get('.hierarchy-mobile').find('.level').first().find('ul.node-children').children()
+ .should('have.length', 2)
+
+ cy.get(`[data-parent="${employee_records.message[1]}"]`).first().as('child-node');
+ cy.get('@child-node').should('be.visible');
+
+ cy.get('@child-node')
+ .get('.node-name')
+ .contains('Test Employee 4');
+
+ // connectors between root node and immediate children
+ cy.get(`path[data-parent="${employee_records.message[1]}"]`).as('connectors');
+ cy.get('@connectors')
+ .should('have.length', 2)
+ .should('be.visible')
+
+ cy.get('@connectors')
+ .first()
+ .invoke('attr', 'data-child')
+ .should('eq', employee_records.message[3]);
+ });
+ });
+
+ it('expands child node', () => {
+ cy.get('@employee_records').then(employee_records => {
+ cy.get(`#${employee_records.message[3]}`)
+ .click()
+ .should('have.class', 'active')
+ .as('expanded_node');
+
+ // 2 levels on screen; 1 on active path; 1 collapsed
+ cy.get('.hierarchy-mobile').children().should('have.length', 2);
+ cy.get(`#${employee_records.message[1]}`).should('have.class', 'active-path');
+
+ // children of expanded node visible
+ cy.get('@expanded_node')
+ .next()
+ .should('have.class', 'node-children')
+ .as('node-children');
+
+ cy.get('@node-children').children().should('have.length', 1);
+ cy.get('@node-children')
+ .first()
+ .get('.node-card')
+ .should('have.class', 'active-child')
+ .contains('Test Employee 7');
+
+ // orphan connectors removed
+ cy.get(`#connectors`).children().should('have.length', 2);
+ });
+ });
+
+ it('renders sibling group', () => {
+ cy.get('@employee_records').then(employee_records => {
+ // sibling group visible for parent
+ cy.get(`#${employee_records.message[1]}`)
+ .next()
+ .as('sibling_group');
+
+ cy.get('@sibling_group')
+ .should('have.attr', 'data-parent', 'undefined')
+ .should('have.class', 'node-group')
+ .and('have.class', 'collapsed')
+
+ cy.get('@sibling_group').get('.avatar-group').children().as('siblings');
+ cy.get('@siblings').should('have.length', 1);
+ cy.get('@siblings')
+ .first()
+ .should('have.attr', 'title', 'Test Employee 1');
+
+ });
+ });
+
+ it('expands previous level nodes', () => {
+ cy.get('@employee_records').then(employee_records => {
+ cy.get(`#${employee_records.message[6]}`)
+ .click()
+ .should('have.class', 'active');
+
+ // clicking on previous level node should remove all the nodes ahead
+ // and expand that node
+ cy.get(`#${employee_records.message[3]}`).click();
+ cy.get(`#${employee_records.message[3]}`)
+ .should('have.class', 'active')
+ .should('not.have.class', 'active-path');
+
+ cy.get(`#${employee_records.message[6]}`).should('have.class', 'active-child');
+ cy.get('.hierarchy-mobile').children().should('have.length', 2);
+ cy.get(`#connectors`).children().should('have.length', 2);
+ });
+ });
+
+ it('expands sibling group', () => {
+ cy.get('@employee_records').then(employee_records => {
+ // sibling group visible for parent
+ cy.get(`#${employee_records.message[6]}`).click()
+
+ cy.get(`#${employee_records.message[3]}`)
+ .next()
+ .click();
+
+ // siblings of parent should be visible
+ cy.get('.hierarchy-mobile').prev().as('sibling_group');
+ cy.get('@sibling_group')
+ .should('exist')
+ .should('have.class', 'sibling-group')
+ .should('not.have.class', 'collapsed');
+
+ cy.get(`#${employee_records.message[1]}`)
+ .should('be.visible')
+ .should('have.class', 'active');
+
+ cy.get(`[data-parent="${employee_records.message[1]}"]`)
+ .should('be.visible')
+ .should('have.length', 2)
+ .should('have.class', 'active-child');
+ });
+ });
+
+ it('goes to the respective level after clicking on non-collapsed sibling group', () => {
+ // click on non-collapsed sibling group
+ cy.get('.hierarchy-mobile')
+ .prev()
+ .click();
+
+ // should take you to that level
+ cy.get('.hierarchy-mobile').find('li.level .node-card').should('have.length', 2);
+ });
+
+ it('edit node navigates to employee master', () => {
+ cy.get('@employee_records').then(employee_records => {
+ cy.get(`#${employee_records.message[0]}`).find('.btn-edit-node')
+ .click();
+
+ cy.url().should('include', `/employee/${employee_records.message[0]}`);
+ });
+ });
+});
diff --git a/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js b/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
index 5a6f168876..bd7946a1e1 100644
--- a/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
+++ b/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
@@ -128,6 +128,9 @@ erpnext.HierarchyChartMobile = class {
if (this.$hierarchy)
this.$hierarchy.remove();
+ if (this.$sibling_group)
+ this.$sibling_group.empty();
+
this.$hierarchy = $(
`
@@ -173,7 +176,7 @@ erpnext.HierarchyChartMobile = class {
if (this.$sibling_group) {
const sibling_parent = this.$sibling_group.find('.node-group').attr('data-parent');
- if (node.parent_id !== sibling_parent)
+ if (node.parent_id !== undefined && node.parent_id != sibling_parent)
this.$sibling_group.empty();
}
@@ -376,9 +379,10 @@ erpnext.HierarchyChartMobile = class {
let node_element = $(`#${node.id}`);
node_element.click(function() {
- let el = $(this).detach();
+ let el = undefined;
if (node.is_root) {
+ el = $(this).detach();
me.$hierarchy.empty();
$(`#connectors`).empty();
me.add_node_to_hierarchy(el, node);
@@ -386,6 +390,7 @@ erpnext.HierarchyChartMobile = class {
me.remove_levels_after_node(node);
me.remove_orphaned_connectors();
} else {
+ el = $(this).detach();
me.add_node_to_hierarchy(el, node);
me.collapse_node();
}
@@ -514,10 +519,10 @@ erpnext.HierarchyChartMobile = class {
level = $('.hierarchy-mobile > li:eq('+ level + ')');
level.nextAll('li').remove();
- let current_node = level.find(`#${node.id}`);
let node_object = this.nodes[node.id];
-
+ let current_node = level.find(`#${node.id}`).detach();
current_node.removeClass('active-child active-path');
+
node_object.expanded = 0;
node_object.$children = undefined;
diff --git a/erpnext/tests/ui_test_helpers.py b/erpnext/tests/ui_test_helpers.py
index 8e67b1cd34..99748dca02 100644
--- a/erpnext/tests/ui_test_helpers.py
+++ b/erpnext/tests/ui_test_helpers.py
@@ -11,10 +11,11 @@ def create_employee_records():
emp2 = create_employee('Test Employee 2', 'CTO')
emp3 = create_employee('Test Employee 3', 'Head of Marketing and Sales', emp1)
emp4 = create_employee('Test Employee 4', 'Project Manager', emp2)
- emp5 = create_employee('Test Employee 5', 'Analyst', emp3)
- emp6 = create_employee('Test Employee 6', 'Software Developer', emp4)
+ emp5 = create_employee('Test Employee 5', 'Engineer', emp2)
+ emp6 = create_employee('Test Employee 6', 'Analyst', emp3)
+ emp7 = create_employee('Test Employee 7', 'Software Developer', emp4)
- employees = [emp1, emp2, emp3, emp4, emp5, emp6]
+ employees = [emp1, emp2, emp3, emp4, emp5, emp6, emp7]
return employees
def create_company():
From 8961a267f649f487eb9f9e3fc63aa6d40765e193 Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Thu, 15 Jul 2021 19:32:15 +0530
Subject: [PATCH 090/386] fix: sider
---
cypress/integration/test_organizational_chart_desktop.js | 4 ++--
cypress/integration/test_organizational_chart_mobile.js | 8 ++++----
erpnext/tests/ui_test_helpers.py | 3 +--
3 files changed, 7 insertions(+), 8 deletions(-)
diff --git a/cypress/integration/test_organizational_chart_desktop.js b/cypress/integration/test_organizational_chart_desktop.js
index d50d551330..807ef5731a 100644
--- a/cypress/integration/test_organizational_chart_desktop.js
+++ b/cypress/integration/test_organizational_chart_desktop.js
@@ -29,7 +29,7 @@ context('Organizational Chart', () => {
// check children of first node
cy.get('@employee_records').then(employee_records => {
// children of 1st root visible
- cy.get(`[data-parent="${employee_records.message[0]}"]`).as('child-node')
+ cy.get(`[data-parent="${employee_records.message[0]}"]`).as('child-node');
cy.get('@child-node')
.should('have.length', 1)
.should('be.visible');
@@ -39,7 +39,7 @@ context('Organizational Chart', () => {
cy.get(`path[data-parent="${employee_records.message[0]}"]`)
.should('be.visible')
.invoke('attr', 'data-child')
- .should('equal', employee_records.message[2]);
+ .should('equal', employee_records.message[2]);
});
});
diff --git a/cypress/integration/test_organizational_chart_mobile.js b/cypress/integration/test_organizational_chart_mobile.js
index 656051289f..f48972bdc6 100644
--- a/cypress/integration/test_organizational_chart_mobile.js
+++ b/cypress/integration/test_organizational_chart_mobile.js
@@ -43,7 +43,7 @@ context('Organizational Chart Mobile', () => {
// children of active root node
cy.get('.hierarchy-mobile').find('.level').first().find('ul.node-children').children()
- .should('have.length', 2)
+ .should('have.length', 2);
cy.get(`[data-parent="${employee_records.message[1]}"]`).first().as('child-node');
cy.get('@child-node').should('be.visible');
@@ -56,7 +56,7 @@ context('Organizational Chart Mobile', () => {
cy.get(`path[data-parent="${employee_records.message[1]}"]`).as('connectors');
cy.get('@connectors')
.should('have.length', 2)
- .should('be.visible')
+ .should('be.visible');
cy.get('@connectors')
.first()
@@ -104,7 +104,7 @@ context('Organizational Chart Mobile', () => {
cy.get('@sibling_group')
.should('have.attr', 'data-parent', 'undefined')
.should('have.class', 'node-group')
- .and('have.class', 'collapsed')
+ .and('have.class', 'collapsed');
cy.get('@sibling_group').get('.avatar-group').children().as('siblings');
cy.get('@siblings').should('have.length', 1);
@@ -137,7 +137,7 @@ context('Organizational Chart Mobile', () => {
it('expands sibling group', () => {
cy.get('@employee_records').then(employee_records => {
// sibling group visible for parent
- cy.get(`#${employee_records.message[6]}`).click()
+ cy.get(`#${employee_records.message[6]}`).click();
cy.get(`#${employee_records.message[3]}`)
.next()
diff --git a/erpnext/tests/ui_test_helpers.py b/erpnext/tests/ui_test_helpers.py
index 99748dca02..f66d69ba23 100644
--- a/erpnext/tests/ui_test_helpers.py
+++ b/erpnext/tests/ui_test_helpers.py
@@ -1,10 +1,9 @@
import frappe
-from frappe import _
from frappe.utils import getdate
@frappe.whitelist()
def create_employee_records():
- company = create_company()
+ create_company()
create_missing_designation()
emp1 = create_employee('Test Employee 1', 'CEO')
From 56cdcebbf4d4daa0bffeead320c1187507cc40f6 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Fri, 16 Jul 2021 02:23:55 +0530
Subject: [PATCH 091/386] fix: Sider issues
---
erpnext/assets/doctype/asset/asset.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py
index 2fe71672b3..ecc35b05b3 100644
--- a/erpnext/assets/doctype/asset/asset.py
+++ b/erpnext/assets/doctype/asset/asset.py
@@ -228,7 +228,7 @@ class Asset(AccountsController):
self.to_date = add_months(self.available_for_use_date,
n * cint(d.frequency_of_depreciation))
- depreciation_amount, days, months = get_pro_rata_amt(d,
+ depreciation_amount, days, months = self.get_pro_rata_amt(d,
depreciation_amount, schedule_date, self.to_date)
monthly_schedule_date = add_months(schedule_date, 1)
From 2c3866a53ea29c20029b5dba75f5184a490b36ff Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Fri, 16 Jul 2021 10:32:38 +0530
Subject: [PATCH 092/386] ci(cypress): use env variable for key
documentation ref: https://docs.cypress.io/guides/guides/command-line\#cypress-run
---
.github/workflows/ui-tests.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/ui-tests.yml b/.github/workflows/ui-tests.yml
index 412a05b0a1..0f13e653ec 100644
--- a/.github/workflows/ui-tests.yml
+++ b/.github/workflows/ui-tests.yml
@@ -101,7 +101,7 @@ jobs:
- name: UI Tests
run: cd ~/frappe-bench/ && bench --site test_site run-ui-tests erpnext --headless
env:
- CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
+ CYPRESS_RECORD_KEY: 60a8e3bf-08f5-45b1-9269-2b207d7d30cd
- name: Show bench console if tests failed
if: ${{ failure() }}
From cad11707822064aa6fa85cebe4d6d54d53b186ee Mon Sep 17 00:00:00 2001
From: Deepesh Garg
Date: Mon, 19 Jul 2021 14:36:54 +0530
Subject: [PATCH 093/386] fix: Add missing cess amount in GSTR-3B report
---
erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.py | 3 +++
1 file changed, 3 insertions(+)
diff --git a/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.py b/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.py
index 641520437f..6de228fbc7 100644
--- a/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.py
+++ b/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.py
@@ -322,6 +322,9 @@ class GSTR3BReport(Document):
inter_state_supply_details[(gst_category, place_of_supply)]['txval'] += taxable_value
inter_state_supply_details[(gst_category, place_of_supply)]['iamt'] += (taxable_value * rate /100)
+ if self.invoice_cess.get(inv):
+ self.report_dict['sup_details']['osup_det']['csamt'] += flt(self.invoice_cess.get(inv), 2)
+
self.set_inter_state_supply(inter_state_supply_details)
def set_supplies_liable_to_reverse_charge(self):
From 9d89b2afcf2cb2cffa8857dc66b0289a165b711b Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Mon, 19 Jul 2021 15:47:31 +0530
Subject: [PATCH 094/386] fix: UI tests
---
cypress.json | 2 +-
cypress/integration/test_organizational_chart_desktop.js | 6 ++++--
cypress/integration/test_organizational_chart_mobile.js | 7 ++++---
3 files changed, 9 insertions(+), 6 deletions(-)
diff --git a/cypress.json b/cypress.json
index 2f5026f62c..afcd657c53 100644
--- a/cypress.json
+++ b/cypress.json
@@ -1,5 +1,5 @@
{
- "baseUrl": "http://test_site:8000/",
+ "baseUrl": "http://test_site:8000",
"projectId": "da59y9",
"adminPassword": "admin",
"defaultCommandTimeout": 20000,
diff --git a/cypress/integration/test_organizational_chart_desktop.js b/cypress/integration/test_organizational_chart_desktop.js
index 807ef5731a..b11b9ea6ab 100644
--- a/cypress/integration/test_organizational_chart_desktop.js
+++ b/cypress/integration/test_organizational_chart_desktop.js
@@ -2,9 +2,11 @@ context('Organizational Chart', () => {
before(() => {
cy.login();
cy.visit('/app/website');
+ cy.awesomebar('Organizational Chart');
+
+ cy.get('.frappe-control[data-fieldname=company] input').focus().as('input');
+ cy.get('@input').type('Test Org Chart');
- cy.visit(`app/organizational-chart`);
- cy.fill_field('company', 'Test Org Chart');
cy.get('body').click();
cy.wait(500);
});
diff --git a/cypress/integration/test_organizational_chart_mobile.js b/cypress/integration/test_organizational_chart_mobile.js
index f48972bdc6..a42562ff2e 100644
--- a/cypress/integration/test_organizational_chart_mobile.js
+++ b/cypress/integration/test_organizational_chart_mobile.js
@@ -3,10 +3,11 @@ context('Organizational Chart Mobile', () => {
cy.login();
cy.viewport(375, 667);
cy.visit('/app/website');
+ cy.awesomebar('Organizational Chart');
+
+ cy.get('.frappe-control[data-fieldname=company] input').focus().as('input');
+ cy.get('@input').type('Test Org Chart');
- cy.visit(`app/organizational-chart`);
- cy.wait(500);
- cy.fill_field('company', 'Test Org Chart');
cy.get('body').click();
cy.wait(500);
});
From 7270ab5c2057ec21b2baf37daf937905f1886dc1 Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Mon, 19 Jul 2021 16:26:17 +0530
Subject: [PATCH 095/386] fix(tests): clear filter before typing
---
cypress/integration/test_organizational_chart_desktop.js | 2 +-
cypress/integration/test_organizational_chart_mobile.js | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/cypress/integration/test_organizational_chart_desktop.js b/cypress/integration/test_organizational_chart_desktop.js
index b11b9ea6ab..516d254b81 100644
--- a/cypress/integration/test_organizational_chart_desktop.js
+++ b/cypress/integration/test_organizational_chart_desktop.js
@@ -5,7 +5,7 @@ context('Organizational Chart', () => {
cy.awesomebar('Organizational Chart');
cy.get('.frappe-control[data-fieldname=company] input').focus().as('input');
- cy.get('@input').type('Test Org Chart');
+ cy.get('@input').clear().type('Test Org Chart');
cy.get('body').click();
cy.wait(500);
diff --git a/cypress/integration/test_organizational_chart_mobile.js b/cypress/integration/test_organizational_chart_mobile.js
index a42562ff2e..503db68c18 100644
--- a/cypress/integration/test_organizational_chart_mobile.js
+++ b/cypress/integration/test_organizational_chart_mobile.js
@@ -6,7 +6,7 @@ context('Organizational Chart Mobile', () => {
cy.awesomebar('Organizational Chart');
cy.get('.frappe-control[data-fieldname=company] input').focus().as('input');
- cy.get('@input').type('Test Org Chart');
+ cy.get('@input').clear().type('Test Org Chart');
cy.get('body').click();
cy.wait(500);
From 6e46be5058be06ecbd180f507f8267c1bc44b07c Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Mon, 19 Jul 2021 17:03:17 +0530
Subject: [PATCH 096/386] fix(tests): apply filters correctly
---
.../test_organizational_chart_desktop.js | 7 ++++---
.../test_organizational_chart_mobile.js | 21 +++++++++++--------
2 files changed, 16 insertions(+), 12 deletions(-)
diff --git a/cypress/integration/test_organizational_chart_desktop.js b/cypress/integration/test_organizational_chart_desktop.js
index 516d254b81..cb12eb5c0c 100644
--- a/cypress/integration/test_organizational_chart_desktop.js
+++ b/cypress/integration/test_organizational_chart_desktop.js
@@ -5,14 +5,15 @@ context('Organizational Chart', () => {
cy.awesomebar('Organizational Chart');
cy.get('.frappe-control[data-fieldname=company] input').focus().as('input');
- cy.get('@input').clear().type('Test Org Chart');
+ cy.get('@input').clear().wait(200).type('Test Org Chart');
+ cy.get('@input').type('{enter}', { delay: 100 });
+ cy.get('@input').blur();
- cy.get('body').click();
cy.wait(500);
});
beforeEach(() => {
- cy.window().its('frappe').then(frappe => {
+ return cy.window().its('frappe').then(frappe => {
return frappe.call('erpnext.tests.ui_test_helpers.create_employee_records');
}).as('employee_records');
});
diff --git a/cypress/integration/test_organizational_chart_mobile.js b/cypress/integration/test_organizational_chart_mobile.js
index 503db68c18..a1d3c0083c 100644
--- a/cypress/integration/test_organizational_chart_mobile.js
+++ b/cypress/integration/test_organizational_chart_mobile.js
@@ -6,9 +6,10 @@ context('Organizational Chart Mobile', () => {
cy.awesomebar('Organizational Chart');
cy.get('.frappe-control[data-fieldname=company] input').focus().as('input');
- cy.get('@input').clear().type('Test Org Chart');
+ cy.get('@input').clear().wait(200).type('Test Org Chart');
+ cy.get('@input').type('{enter}', { delay: 100 });
+ cy.get('@input').blur();
- cy.get('body').click();
cy.wait(500);
});
@@ -16,7 +17,7 @@ context('Organizational Chart Mobile', () => {
cy.viewport(375, 667);
cy.wait(500);
- cy.window().its('frappe').then(frappe => {
+ return cy.window().its('frappe').then(frappe => {
return frappe.call('erpnext.tests.ui_test_helpers.create_employee_records');
}).as('employee_records');
});
@@ -163,13 +164,15 @@ context('Organizational Chart Mobile', () => {
});
it('goes to the respective level after clicking on non-collapsed sibling group', () => {
- // click on non-collapsed sibling group
- cy.get('.hierarchy-mobile')
- .prev()
- .click();
+ cy.get('@employee_records').then(() => {
+ // click on non-collapsed sibling group
+ cy.get('.hierarchy-mobile')
+ .prev()
+ .click();
- // should take you to that level
- cy.get('.hierarchy-mobile').find('li.level .node-card').should('have.length', 2);
+ // should take you to that level
+ cy.get('.hierarchy-mobile').find('li.level .node-card').should('have.length', 2);
+ });
});
it('edit node navigates to employee master', () => {
From e327148edf315dec5a284868a9013e2e8a1a04eb Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Mon, 19 Jul 2021 17:34:15 +0530
Subject: [PATCH 097/386] fix: tests
---
cypress/integration/test_organizational_chart_desktop.js | 6 +++---
cypress/integration/test_organizational_chart_mobile.js | 6 +++---
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/cypress/integration/test_organizational_chart_desktop.js b/cypress/integration/test_organizational_chart_desktop.js
index cb12eb5c0c..95592e2f6a 100644
--- a/cypress/integration/test_organizational_chart_desktop.js
+++ b/cypress/integration/test_organizational_chart_desktop.js
@@ -4,10 +4,10 @@ context('Organizational Chart', () => {
cy.visit('/app/website');
cy.awesomebar('Organizational Chart');
- cy.get('.frappe-control[data-fieldname=company] input').focus().as('input');
- cy.get('@input').clear().wait(200).type('Test Org Chart');
+ cy.get('.frappe-control[data-fieldname=company] input').first().focus().as('input');
+ cy.get('@input').clear().wait(200).type('Test Org Chart', { force: true });
cy.get('@input').type('{enter}', { delay: 100 });
- cy.get('@input').blur();
+ cy.get('@input').blur({ force: true });
cy.wait(500);
});
diff --git a/cypress/integration/test_organizational_chart_mobile.js b/cypress/integration/test_organizational_chart_mobile.js
index a1d3c0083c..632d15ba6c 100644
--- a/cypress/integration/test_organizational_chart_mobile.js
+++ b/cypress/integration/test_organizational_chart_mobile.js
@@ -5,10 +5,10 @@ context('Organizational Chart Mobile', () => {
cy.visit('/app/website');
cy.awesomebar('Organizational Chart');
- cy.get('.frappe-control[data-fieldname=company] input').focus().as('input');
- cy.get('@input').clear().wait(200).type('Test Org Chart');
+ cy.get('.frappe-control[data-fieldname=company] input').first().focus().as('input');
+ cy.get('@input').clear().wait(200).type('Test Org Chart', { force: true });
cy.get('@input').type('{enter}', { delay: 100 });
- cy.get('@input').blur();
+ cy.get('@input').blur({ force: true });
cy.wait(500);
});
From ff9d631f1525fe4f27caac4afc65eddb165cc27b Mon Sep 17 00:00:00 2001
From: Subin Tom
Date: Mon, 19 Jul 2021 20:09:37 +0530
Subject: [PATCH 098/386] fix:Ignore mandatory fields while creating payment
reconciliation Journal Entry
---
.../doctype/payment_reconciliation/payment_reconciliation.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
index 6635128f9e..d788d91855 100644
--- a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
+++ b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
@@ -306,5 +306,5 @@ def reconcile_dr_cr_note(dr_cr_notes, company):
}
]
})
-
+ jv.flags.ignore_mandatory = True
jv.submit()
\ No newline at end of file
From 89c5bb6066737418a01c18ec202c8fa78424a9b2 Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Mon, 19 Jul 2021 22:19:28 +0530
Subject: [PATCH 099/386] fix: tests
---
.../test_organizational_chart_desktop.js | 31 +++++++---------
.../test_organizational_chart_mobile.js | 37 ++++++++-----------
erpnext/tests/ui_test_helpers.py | 6 +++
3 files changed, 34 insertions(+), 40 deletions(-)
diff --git a/cypress/integration/test_organizational_chart_desktop.js b/cypress/integration/test_organizational_chart_desktop.js
index 95592e2f6a..0493732812 100644
--- a/cypress/integration/test_organizational_chart_desktop.js
+++ b/cypress/integration/test_organizational_chart_desktop.js
@@ -1,21 +1,17 @@
context('Organizational Chart', () => {
before(() => {
cy.login();
- cy.visit('/app/website');
+ cy.visit('/app');
+
+ cy.call('erpnext.tests.ui_test_helpers.create_employee_records');
cy.awesomebar('Organizational Chart');
- cy.get('.frappe-control[data-fieldname=company] input').first().focus().as('input');
- cy.get('@input').clear().wait(200).type('Test Org Chart', { force: true });
- cy.get('@input').type('{enter}', { delay: 100 });
+ cy.get('.frappe-control[data-fieldname=company] input').focus().as('input');
+ cy.get('@input')
+ .clear({ force: true })
+ .type('Test Org Chart', { force: true });
+ cy.wait(200);
cy.get('@input').blur({ force: true });
-
- cy.wait(500);
- });
-
- beforeEach(() => {
- return cy.window().its('frappe').then(frappe => {
- return frappe.call('erpnext.tests.ui_test_helpers.create_employee_records');
- }).as('employee_records');
});
it('renders root nodes and loads children for the first expandable node', () => {
@@ -29,8 +25,7 @@ context('Organizational Chart', () => {
cy.get('@first-child').get('.node-info').find('.node-title').contains('CEO');
cy.get('@first-child').get('.node-info').find('.node-connections').contains('· 2 Connections');
- // check children of first node
- cy.get('@employee_records').then(employee_records => {
+ cy.call('erpnext.tests.ui_test_helpers.get_employee_records').then(employee_records => {
// children of 1st root visible
cy.get(`[data-parent="${employee_records.message[0]}"]`).as('child-node');
cy.get('@child-node')
@@ -47,7 +42,7 @@ context('Organizational Chart', () => {
});
it('hides active nodes children and connectors on expanding sibling node', () => {
- cy.get('@employee_records').then(employee_records => {
+ cy.call('erpnext.tests.ui_test_helpers.get_employee_records').then(employee_records => {
// click sibling
cy.get(`#${employee_records.message[1]}`)
.click()
@@ -60,7 +55,7 @@ context('Organizational Chart', () => {
});
it('collapses previous level nodes and refreshes connectors on expanding child node', () => {
- cy.get('@employee_records').then(employee_records => {
+ cy.call('erpnext.tests.ui_test_helpers.get_employee_records').then(employee_records => {
// click child node
cy.get(`#${employee_records.message[3]}`)
.click()
@@ -81,7 +76,7 @@ context('Organizational Chart', () => {
});
it('expands previous level nodes', () => {
- cy.get('@employee_records').then(employee_records => {
+ cy.call('erpnext.tests.ui_test_helpers.get_employee_records').then(employee_records => {
cy.get(`#${employee_records.message[0]}`)
.click()
.should('have.class', 'active');
@@ -95,7 +90,7 @@ context('Organizational Chart', () => {
});
it('edit node navigates to employee master', () => {
- cy.get('@employee_records').then(employee_records => {
+ cy.call('erpnext.tests.ui_test_helpers.get_employee_records').then(employee_records => {
cy.get(`#${employee_records.message[0]}`).find('.btn-edit-node')
.click();
diff --git a/cypress/integration/test_organizational_chart_mobile.js b/cypress/integration/test_organizational_chart_mobile.js
index 632d15ba6c..1dcfbcfeb1 100644
--- a/cypress/integration/test_organizational_chart_mobile.js
+++ b/cypress/integration/test_organizational_chart_mobile.js
@@ -2,24 +2,17 @@ context('Organizational Chart Mobile', () => {
before(() => {
cy.login();
cy.viewport(375, 667);
- cy.visit('/app/website');
+ cy.visit('/app');
+
+ cy.call('erpnext.tests.ui_test_helpers.create_employee_records');
cy.awesomebar('Organizational Chart');
- cy.get('.frappe-control[data-fieldname=company] input').first().focus().as('input');
- cy.get('@input').clear().wait(200).type('Test Org Chart', { force: true });
- cy.get('@input').type('{enter}', { delay: 100 });
+ cy.get('.frappe-control[data-fieldname=company] input').focus().as('input');
+ cy.get('@input')
+ .clear({ force: true })
+ .type('Test Org Chart', { force: true });
+ cy.wait(200);
cy.get('@input').blur({ force: true });
-
- cy.wait(500);
- });
-
- beforeEach(() => {
- cy.viewport(375, 667);
- cy.wait(500);
-
- return cy.window().its('frappe').then(frappe => {
- return frappe.call('erpnext.tests.ui_test_helpers.create_employee_records');
- }).as('employee_records');
});
it('renders root nodes', () => {
@@ -35,7 +28,7 @@ context('Organizational Chart Mobile', () => {
});
it('expands root node', () => {
- cy.get('@employee_records').then(employee_records => {
+ cy.call('erpnext.tests.ui_test_helpers.get_employee_records').then(employee_records => {
cy.get(`#${employee_records.message[1]}`)
.click()
.should('have.class', 'active');
@@ -68,7 +61,7 @@ context('Organizational Chart Mobile', () => {
});
it('expands child node', () => {
- cy.get('@employee_records').then(employee_records => {
+ cy.call('erpnext.tests.ui_test_helpers.get_employee_records').then(employee_records => {
cy.get(`#${employee_records.message[3]}`)
.click()
.should('have.class', 'active')
@@ -97,7 +90,7 @@ context('Organizational Chart Mobile', () => {
});
it('renders sibling group', () => {
- cy.get('@employee_records').then(employee_records => {
+ cy.call('erpnext.tests.ui_test_helpers.get_employee_records').then(employee_records => {
// sibling group visible for parent
cy.get(`#${employee_records.message[1]}`)
.next()
@@ -118,7 +111,7 @@ context('Organizational Chart Mobile', () => {
});
it('expands previous level nodes', () => {
- cy.get('@employee_records').then(employee_records => {
+ cy.call('erpnext.tests.ui_test_helpers.get_employee_records').then(employee_records => {
cy.get(`#${employee_records.message[6]}`)
.click()
.should('have.class', 'active');
@@ -137,7 +130,7 @@ context('Organizational Chart Mobile', () => {
});
it('expands sibling group', () => {
- cy.get('@employee_records').then(employee_records => {
+ cy.call('erpnext.tests.ui_test_helpers.get_employee_records').then(employee_records => {
// sibling group visible for parent
cy.get(`#${employee_records.message[6]}`).click();
@@ -164,7 +157,7 @@ context('Organizational Chart Mobile', () => {
});
it('goes to the respective level after clicking on non-collapsed sibling group', () => {
- cy.get('@employee_records').then(() => {
+ cy.call('erpnext.tests.ui_test_helpers.get_employee_records').then(() => {
// click on non-collapsed sibling group
cy.get('.hierarchy-mobile')
.prev()
@@ -176,7 +169,7 @@ context('Organizational Chart Mobile', () => {
});
it('edit node navigates to employee master', () => {
- cy.get('@employee_records').then(employee_records => {
+ cy.call('erpnext.tests.ui_test_helpers.get_employee_records').then(employee_records => {
cy.get(`#${employee_records.message[0]}`).find('.btn-edit-node')
.click();
diff --git a/erpnext/tests/ui_test_helpers.py b/erpnext/tests/ui_test_helpers.py
index f66d69ba23..fc3aa29824 100644
--- a/erpnext/tests/ui_test_helpers.py
+++ b/erpnext/tests/ui_test_helpers.py
@@ -17,6 +17,12 @@ def create_employee_records():
employees = [emp1, emp2, emp3, emp4, emp5, emp6, emp7]
return employees
+@frappe.whitelist()
+def get_employee_records():
+ return frappe.db.get_list('Employee', filters={
+ 'company': 'Test Org Chart'
+ }, pluck='name', order_by='name')
+
def create_company():
company = frappe.db.exists('Company', 'Test Org Chart')
if not company:
From 7176c0847e6aeb10dd0f68e501707074cf3345e1 Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Mon, 19 Jul 2021 23:34:02 +0530
Subject: [PATCH 100/386] fix: tests
---
.../test_organizational_chart_desktop.js | 19 +++++++++----------
.../test_organizational_chart_mobile.js | 19 +++++++++----------
2 files changed, 18 insertions(+), 20 deletions(-)
diff --git a/cypress/integration/test_organizational_chart_desktop.js b/cypress/integration/test_organizational_chart_desktop.js
index 0493732812..52863f18e0 100644
--- a/cypress/integration/test_organizational_chart_desktop.js
+++ b/cypress/integration/test_organizational_chart_desktop.js
@@ -1,17 +1,16 @@
context('Organizational Chart', () => {
before(() => {
cy.login();
- cy.visit('/app');
-
- cy.call('erpnext.tests.ui_test_helpers.create_employee_records');
+ cy.visit('/app/website');
cy.awesomebar('Organizational Chart');
- cy.get('.frappe-control[data-fieldname=company] input').focus().as('input');
- cy.get('@input')
- .clear({ force: true })
- .type('Test Org Chart', { force: true });
- cy.wait(200);
- cy.get('@input').blur({ force: true });
+ cy.call('erpnext.tests.ui_test_helpers.create_employee_records').then(() => {
+ cy.get('.frappe-control[data-fieldname=company] input').focus().as('input');
+ cy.get('@input')
+ .clear({ force: true })
+ .type('Test Org Chart{enter}', { force: true })
+ .blur({ force: true });
+ });
});
it('renders root nodes and loads children for the first expandable node', () => {
@@ -27,7 +26,7 @@ context('Organizational Chart', () => {
cy.call('erpnext.tests.ui_test_helpers.get_employee_records').then(employee_records => {
// children of 1st root visible
- cy.get(`[data-parent="${employee_records.message[0]}"]`).as('child-node');
+ cy.get(`div[data-parent="${employee_records.message[0]}"]`).as('child-node');
cy.get('@child-node')
.should('have.length', 1)
.should('be.visible');
diff --git a/cypress/integration/test_organizational_chart_mobile.js b/cypress/integration/test_organizational_chart_mobile.js
index 1dcfbcfeb1..2272a31046 100644
--- a/cypress/integration/test_organizational_chart_mobile.js
+++ b/cypress/integration/test_organizational_chart_mobile.js
@@ -2,17 +2,16 @@ context('Organizational Chart Mobile', () => {
before(() => {
cy.login();
cy.viewport(375, 667);
- cy.visit('/app');
-
- cy.call('erpnext.tests.ui_test_helpers.create_employee_records');
+ cy.visit('/app/website');
cy.awesomebar('Organizational Chart');
- cy.get('.frappe-control[data-fieldname=company] input').focus().as('input');
- cy.get('@input')
- .clear({ force: true })
- .type('Test Org Chart', { force: true });
- cy.wait(200);
- cy.get('@input').blur({ force: true });
+ cy.call('erpnext.tests.ui_test_helpers.create_employee_records').then(() => {
+ cy.get('.frappe-control[data-fieldname=company] input').focus().as('input');
+ cy.get('@input')
+ .clear({ force: true })
+ .type('Test Org Chart{enter}', { force: true })
+ .blur({ force: true });
+ });
});
it('renders root nodes', () => {
@@ -40,7 +39,7 @@ context('Organizational Chart Mobile', () => {
cy.get('.hierarchy-mobile').find('.level').first().find('ul.node-children').children()
.should('have.length', 2);
- cy.get(`[data-parent="${employee_records.message[1]}"]`).first().as('child-node');
+ cy.get(`div[data-parent="${employee_records.message[1]}"]`).first().as('child-node');
cy.get('@child-node').should('be.visible');
cy.get('@child-node')
From eb65ce662a5bdde4bd8a54a8268363d2651a3c09 Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Tue, 20 Jul 2021 10:23:52 +0530
Subject: [PATCH 101/386] fix(test): increase timeout for record creation
---
.../test_organizational_chart_desktop.js | 27 ++++++++++++++-----
.../test_organizational_chart_mobile.js | 27 ++++++++++++++-----
2 files changed, 42 insertions(+), 12 deletions(-)
diff --git a/cypress/integration/test_organizational_chart_desktop.js b/cypress/integration/test_organizational_chart_desktop.js
index 52863f18e0..0da4e560a7 100644
--- a/cypress/integration/test_organizational_chart_desktop.js
+++ b/cypress/integration/test_organizational_chart_desktop.js
@@ -4,12 +4,27 @@ context('Organizational Chart', () => {
cy.visit('/app/website');
cy.awesomebar('Organizational Chart');
- cy.call('erpnext.tests.ui_test_helpers.create_employee_records').then(() => {
- cy.get('.frappe-control[data-fieldname=company] input').focus().as('input');
- cy.get('@input')
- .clear({ force: true })
- .type('Test Org Chart{enter}', { force: true })
- .blur({ force: true });
+ cy.window().its('frappe.csrf_token').then(csrf_token => {
+ return cy.request({
+ url: `/api/method/erpnext.tests.ui_test_helpers.create_employee_records`,
+ method: 'POST',
+ headers: {
+ Accept: 'application/json',
+ 'Content-Type': 'application/json',
+ 'X-Frappe-CSRF-Token': csrf_token
+ },
+ timeout: 60000
+ })
+ .then(res => {
+ expect(res.status).eq(200);
+ cy.get('.frappe-control[data-fieldname=company] input').focus().as('input');
+ cy.get('@input')
+ .clear({ force: true })
+ .type('Test Org Chart{enter}', { force: true })
+ .blur({ force: true });
+
+ cy.get('body').click();
+ });
});
});
diff --git a/cypress/integration/test_organizational_chart_mobile.js b/cypress/integration/test_organizational_chart_mobile.js
index 2272a31046..0374678a1a 100644
--- a/cypress/integration/test_organizational_chart_mobile.js
+++ b/cypress/integration/test_organizational_chart_mobile.js
@@ -5,12 +5,27 @@ context('Organizational Chart Mobile', () => {
cy.visit('/app/website');
cy.awesomebar('Organizational Chart');
- cy.call('erpnext.tests.ui_test_helpers.create_employee_records').then(() => {
- cy.get('.frappe-control[data-fieldname=company] input').focus().as('input');
- cy.get('@input')
- .clear({ force: true })
- .type('Test Org Chart{enter}', { force: true })
- .blur({ force: true });
+ cy.window().its('frappe.csrf_token').then(csrf_token => {
+ return cy.request({
+ url: `/api/method/erpnext.tests.ui_test_helpers.create_employee_records`,
+ method: 'POST',
+ headers: {
+ Accept: 'application/json',
+ 'Content-Type': 'application/json',
+ 'X-Frappe-CSRF-Token': csrf_token
+ },
+ timeout: 60000
+ })
+ .then(res => {
+ expect(res.status).eq(200);
+ cy.get('.frappe-control[data-fieldname=company] input').focus().as('input');
+ cy.get('@input')
+ .clear({ force: true })
+ .type('Test Org Chart{enter}', { force: true })
+ .blur({ force: true });
+
+ cy.get('body').click();
+ });
});
});
From 41dd0c5a8a75d674f151f09fe9412fdd42347d82 Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Tue, 20 Jul 2021 10:55:05 +0530
Subject: [PATCH 102/386] fix: sider
---
.../test_organizational_chart_desktop.js | 3 +-
.../test_organizational_chart_mobile.js | 36 +++++++++----------
2 files changed, 19 insertions(+), 20 deletions(-)
diff --git a/cypress/integration/test_organizational_chart_desktop.js b/cypress/integration/test_organizational_chart_desktop.js
index 0da4e560a7..57b7f7dced 100644
--- a/cypress/integration/test_organizational_chart_desktop.js
+++ b/cypress/integration/test_organizational_chart_desktop.js
@@ -14,8 +14,7 @@ context('Organizational Chart', () => {
'X-Frappe-CSRF-Token': csrf_token
},
timeout: 60000
- })
- .then(res => {
+ }).then(res => {
expect(res.status).eq(200);
cy.get('.frappe-control[data-fieldname=company] input').focus().as('input');
cy.get('@input')
diff --git a/cypress/integration/test_organizational_chart_mobile.js b/cypress/integration/test_organizational_chart_mobile.js
index 0374678a1a..214229f6f6 100644
--- a/cypress/integration/test_organizational_chart_mobile.js
+++ b/cypress/integration/test_organizational_chart_mobile.js
@@ -7,25 +7,25 @@ context('Organizational Chart Mobile', () => {
cy.window().its('frappe.csrf_token').then(csrf_token => {
return cy.request({
- url: `/api/method/erpnext.tests.ui_test_helpers.create_employee_records`,
- method: 'POST',
- headers: {
- Accept: 'application/json',
- 'Content-Type': 'application/json',
- 'X-Frappe-CSRF-Token': csrf_token
- },
- timeout: 60000
- })
- .then(res => {
- expect(res.status).eq(200);
- cy.get('.frappe-control[data-fieldname=company] input').focus().as('input');
- cy.get('@input')
- .clear({ force: true })
- .type('Test Org Chart{enter}', { force: true })
- .blur({ force: true });
+ url: `/api/method/erpnext.tests.ui_test_helpers.create_employee_records`,
+ method: 'POST',
+ headers: {
+ Accept: 'application/json',
+ 'Content-Type': 'application/json',
+ 'X-Frappe-CSRF-Token': csrf_token
+ },
+ timeout: 60000
+ })
+ .then(res => {
+ expect(res.status).eq(200);
+ cy.get('.frappe-control[data-fieldname=company] input').focus().as('input');
+ cy.get('@input')
+ .clear({ force: true })
+ .type('Test Org Chart{enter}', { force: true })
+ .blur({ force: true });
- cy.get('body').click();
- });
+ cy.get('body').click();
+ });
});
});
From 0222ee03580a37cc304b70a7e698d0fcc416c686 Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Tue, 20 Jul 2021 12:19:44 +0530
Subject: [PATCH 103/386] fix: sider
---
.../test_organizational_chart_desktop.js | 2 --
.../test_organizational_chart_mobile.js | 35 +++++++++----------
2 files changed, 16 insertions(+), 21 deletions(-)
diff --git a/cypress/integration/test_organizational_chart_desktop.js b/cypress/integration/test_organizational_chart_desktop.js
index 57b7f7dced..fb46bbb433 100644
--- a/cypress/integration/test_organizational_chart_desktop.js
+++ b/cypress/integration/test_organizational_chart_desktop.js
@@ -21,8 +21,6 @@ context('Organizational Chart', () => {
.clear({ force: true })
.type('Test Org Chart{enter}', { force: true })
.blur({ force: true });
-
- cy.get('body').click();
});
});
});
diff --git a/cypress/integration/test_organizational_chart_mobile.js b/cypress/integration/test_organizational_chart_mobile.js
index 214229f6f6..df90dbfa22 100644
--- a/cypress/integration/test_organizational_chart_mobile.js
+++ b/cypress/integration/test_organizational_chart_mobile.js
@@ -7,25 +7,22 @@ context('Organizational Chart Mobile', () => {
cy.window().its('frappe.csrf_token').then(csrf_token => {
return cy.request({
- url: `/api/method/erpnext.tests.ui_test_helpers.create_employee_records`,
- method: 'POST',
- headers: {
- Accept: 'application/json',
- 'Content-Type': 'application/json',
- 'X-Frappe-CSRF-Token': csrf_token
- },
- timeout: 60000
- })
- .then(res => {
- expect(res.status).eq(200);
- cy.get('.frappe-control[data-fieldname=company] input').focus().as('input');
- cy.get('@input')
- .clear({ force: true })
- .type('Test Org Chart{enter}', { force: true })
- .blur({ force: true });
-
- cy.get('body').click();
- });
+ url: `/api/method/erpnext.tests.ui_test_helpers.create_employee_records`,
+ method: 'POST',
+ headers: {
+ Accept: 'application/json',
+ 'Content-Type': 'application/json',
+ 'X-Frappe-CSRF-Token': csrf_token
+ },
+ timeout: 60000
+ }).then(res => {
+ expect(res.status).eq(200);
+ cy.get('.frappe-control[data-fieldname=company] input').focus().as('input');
+ cy.get('@input')
+ .clear({ force: true })
+ .type('Test Org Chart{enter}', { force: true })
+ .blur({ force: true });
+ });
});
});
From 8a64a84d1afdfd18cefcc99a0860ed63fff34b84 Mon Sep 17 00:00:00 2001
From: Deepesh Garg
Date: Wed, 21 Jul 2021 13:25:53 +0530
Subject: [PATCH 104/386] fix: GST Reports timeout issue
---
erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.py | 5 ++---
erpnext/regional/report/gstr_1/gstr_1.py | 5 ++---
2 files changed, 4 insertions(+), 6 deletions(-)
diff --git a/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.py b/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.py
index 641520437f..6a61ae2b42 100644
--- a/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.py
+++ b/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.py
@@ -214,9 +214,8 @@ class GSTR3BReport(Document):
for d in item_details:
if d.item_code not in self.invoice_items.get(d.parent, {}):
- self.invoice_items.setdefault(d.parent, {}).setdefault(d.item_code,
- sum((i.get('taxable_value', 0) or i.get('base_net_amount', 0)) for i in item_details
- if i.item_code == d.item_code and i.parent == d.parent))
+ self.invoice_items.setdefault(d.parent, {}).setdefault(d.item_code, 0.0)
+ self.invoice_items[d.parent][d.item_code] += d.get('taxable_value', 0) or d.get('base_net_amount', 0)
if d.is_nil_exempt and d.item_code not in self.is_nil_exempt:
self.is_nil_exempt.append(d.item_code)
diff --git a/erpnext/regional/report/gstr_1/gstr_1.py b/erpnext/regional/report/gstr_1/gstr_1.py
index cfcb8c3444..b81fa810fe 100644
--- a/erpnext/regional/report/gstr_1/gstr_1.py
+++ b/erpnext/regional/report/gstr_1/gstr_1.py
@@ -217,9 +217,8 @@ class Gstr1Report(object):
for d in items:
if d.item_code not in self.invoice_items.get(d.parent, {}):
- self.invoice_items.setdefault(d.parent, {}).setdefault(d.item_code,
- sum((i.get('taxable_value', 0) or i.get('base_net_amount', 0)) for i in items
- if i.item_code == d.item_code and i.parent == d.parent))
+ self.invoice_items.setdefault(d.parent, {}).setdefault(d.item_code, 0.0)
+ self.invoice_items[d.parent][d.item_code] += d.get('taxable_value', 0) or d.get('base_net_amount', 0)
item_tax_rate = {}
From e1dc6980d09266b3db115546403d8bbdc0946b1e Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Mon, 5 Jul 2021 14:58:32 +0530
Subject: [PATCH 105/386] feat(Accounts Settings): Add 'Enable Discount
Accounting' checkbox
---
.../doctype/accounts_settings/accounts_settings.json | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/erpnext/accounts/doctype/accounts_settings/accounts_settings.json b/erpnext/accounts/doctype/accounts_settings/accounts_settings.json
index 703e93c075..676c6a8b47 100644
--- a/erpnext/accounts/doctype/accounts_settings/accounts_settings.json
+++ b/erpnext/accounts/doctype/accounts_settings/accounts_settings.json
@@ -12,6 +12,7 @@
"role_allowed_to_over_bill",
"make_payment_via_journal_entry",
"column_break_11",
+ "enable_discount_accounting",
"check_supplier_invoice_uniqueness",
"unlink_payment_on_cancellation_of_invoice",
"automatically_fetch_payment_terms",
@@ -261,6 +262,12 @@
"fieldname": "post_change_gl_entries",
"fieldtype": "Check",
"label": "Create Ledger Entries for Change Amount"
+ },
+ {
+ "default": "0",
+ "fieldname": "enable_discount_accounting",
+ "fieldtype": "Check",
+ "label": "Enable Discount Accounting"
}
],
"icon": "icon-cog",
@@ -268,7 +275,7 @@
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
- "modified": "2021-06-17 20:26:03.721202",
+ "modified": "2021-07-05 14:56:19.820731",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Accounts Settings",
From a6690a8a3df1e467850f98c7a561d2b5b0b295eb Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Mon, 5 Jul 2021 15:09:05 +0530
Subject: [PATCH 106/386] feat(Sales Invoice): Add 'Discount Account' field in
Items table
---
.../doctype/sales_invoice_item/sales_invoice_item.json | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json
index 8e6952a93c..b65903bf5e 100644
--- a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json
+++ b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json
@@ -63,6 +63,7 @@
"finance_book",
"col_break4",
"expense_account",
+ "discount_account",
"deferred_revenue",
"deferred_revenue_account",
"service_stop_date",
@@ -821,12 +822,18 @@
"no_copy": 1,
"options": "currency",
"read_only": 1
+ },
+ {
+ "fieldname": "discount_account",
+ "fieldtype": "Link",
+ "label": "Discount Account",
+ "options": "Account"
}
],
"idx": 1,
"istable": 1,
"links": [],
- "modified": "2021-02-23 01:05:22.123527",
+ "modified": "2021-07-05 15:07:22.857128",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice Item",
From f6a9374356658f6375b50312838620ae6e14de5a Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Tue, 6 Jul 2021 00:36:06 +0530
Subject: [PATCH 107/386] feat: Create GL Entries for discount accounting
---
.../doctype/sales_invoice/sales_invoice.py | 35 +++++++++++++++++++
1 file changed, 35 insertions(+)
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index 6d1f6249c1..04c789d30a 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -846,6 +846,7 @@ class SalesInvoice(SellingController):
self.allocate_advance_taxes(gl_entries)
self.make_item_gl_entries(gl_entries)
+ self.make_discount_gl_entries(gl_entries)
# merge gl entries before adding pos entries
gl_entries = merge_similar_entries(gl_entries)
@@ -959,6 +960,40 @@ class SalesInvoice(SellingController):
erpnext.is_perpetual_inventory_enabled(self.company):
gl_entries += super(SalesInvoice, self).get_gl_entries()
+ def make_discount_gl_entries(self, gl_entries):
+ enable_discount_accounting = cint(frappe.db.get_single_value('Accounts Settings', 'enable_discount_accounting'))
+
+ if enable_discount_accounting:
+ for item in self.get("items"):
+ if item.get('discount_amount') and item.get('discount_account'):
+ account_currency = get_account_currency(item.discount_account)
+ gl_entries.append(
+ self.get_gl_dict({
+ "account": item.discount_account,
+ "against": self.customer,
+ "debit": flt(item.discount_amount),
+ "debit_in_account_currency": flt(item.discount_amount),
+ "cost_center": self.cost_center,
+ "project": self.project
+ }, account_currency, item=self)
+ )
+
+ income_account = (item.income_account
+ if (not item.enable_deferred_revenue or self.is_return)
+ else item.deferred_revenue_account)
+
+ account_currency = get_account_currency(income_account)
+ gl_entries.append(
+ self.get_gl_dict({
+ "account": income_account,
+ "against": self.customer,
+ "credit": flt(item.discount_amount),
+ "credit_in_account_currency": flt(item.discount_amount),
+ "cost_center": item.cost_center,
+ "project": item.project or self.project
+ }, account_currency, item=item)
+ )
+
def make_loyalty_point_redemption_gle(self, gl_entries):
if cint(self.redeem_loyalty_points):
gl_entries.append(
From c4e54295601b4dd6da940212ed561cb5f3abb20c Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Tue, 6 Jul 2021 16:28:19 +0530
Subject: [PATCH 108/386] feat: Filter list for Discount Account field in Items
table
---
erpnext/accounts/doctype/sales_invoice/sales_invoice.js | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
index f813425e6b..dc0d9da97b 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
@@ -510,6 +510,14 @@ cur_frm.set_query("income_account", "items", function(doc) {
}
});
+// Discount Account in Details Table
+// --------------------------------
+cur_frm.set_query("discount_account", "items", function(doc) {
+ return{
+ query: "erpnext.controllers.queries.get_income_account",
+ filters: {'company': doc.company}
+ }
+});
// Cost Center in Details Table
// -----------------------------
From acb9e207ec96f642d5ce935157af4315717c0f57 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Tue, 6 Jul 2021 16:29:19 +0530
Subject: [PATCH 109/386] feat: Add Default Discount Account field
---
erpnext/stock/doctype/item/item.json | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/erpnext/stock/doctype/item/item.json b/erpnext/stock/doctype/item/item.json
index 6fed9efa63..f1c413e00a 100644
--- a/erpnext/stock/doctype/item/item.json
+++ b/erpnext/stock/doctype/item/item.json
@@ -91,6 +91,7 @@
"is_sales_item",
"column_break3",
"max_discount",
+ "default_discount_account",
"deferred_revenue",
"deferred_revenue_account",
"enable_deferred_revenue",
@@ -1058,6 +1059,12 @@
"fieldname": "website_image_alt",
"fieldtype": "Data",
"label": "Image Description"
+ },
+ {
+ "fieldname": "default_discount_account",
+ "fieldtype": "Link",
+ "label": "Default Discount Account",
+ "options": "Account"
}
],
"has_web_view": 1,
@@ -1067,7 +1074,7 @@
"index_web_pages_for_search": 1,
"links": [],
"max_attachments": 1,
- "modified": "2021-03-18 14:04:38.575519",
+ "modified": "2021-07-06 00:46:15.878648",
"modified_by": "Administrator",
"module": "Stock",
"name": "Item",
@@ -1138,4 +1145,4 @@
"sort_order": "DESC",
"title_field": "item_name",
"track_changes": 1
-}
+}
\ No newline at end of file
From cdfefa261e021dcba4d1f09b064f2b7baf6d72f1 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Tue, 6 Jul 2021 16:51:12 +0530
Subject: [PATCH 110/386] feat: Assign Item's Default Discount Account if
present
---
erpnext/stock/get_item_details.py | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py
index cf52803fca..bf082f89be 100644
--- a/erpnext/stock/get_item_details.py
+++ b/erpnext/stock/get_item_details.py
@@ -287,6 +287,7 @@ def get_basic_details(args, item, overwrite_warehouse=True):
"warehouse": warehouse,
"income_account": get_default_income_account(args, item_defaults, item_group_defaults, brand_defaults),
"expense_account": expense_account or get_default_expense_account(args, item_defaults, item_group_defaults, brand_defaults) ,
+ "discount_account": None or get_default_discount_account(args, item_defaults),
"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,
@@ -589,6 +590,10 @@ def get_default_expense_account(args, item, item_group, brand):
or brand.get("expense_account")
or args.expense_account)
+def get_default_discount_account(args, item_defaults):
+ return (item_defaults.default_discount_account
+ or args.discount_account)
+
def get_default_deferred_account(args, item, fieldname=None):
if item.get("enable_deferred_revenue") or item.get("enable_deferred_expense"):
return (item.get(fieldname)
From f48fa2e7f3893020b9ccbd546ff83e53a2c1c581 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Tue, 6 Jul 2021 20:22:13 +0530
Subject: [PATCH 111/386] feat: Toggle display for discount accounting fields
according to enable_discount_accounting
---
.../doctype/accounts_settings/accounts_settings.py | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/erpnext/accounts/doctype/accounts_settings/accounts_settings.py b/erpnext/accounts/doctype/accounts_settings/accounts_settings.py
index ac4a2d6f16..9e33eb395b 100644
--- a/erpnext/accounts/doctype/accounts_settings/accounts_settings.py
+++ b/erpnext/accounts/doctype/accounts_settings/accounts_settings.py
@@ -21,6 +21,7 @@ class AccountsSettings(Document):
self.validate_stale_days()
self.enable_payment_schedule_in_print()
+ self.toggle_discount_accounting_fields()
def validate_stale_days(self):
if not self.allow_stale and cint(self.stale_days) <= 0:
@@ -33,3 +34,9 @@ class AccountsSettings(Document):
for doctype in ("Sales Order", "Sales Invoice", "Purchase Order", "Purchase Invoice"):
make_property_setter(doctype, "due_date", "print_hide", show_in_print, "Check", validate_fields_for_doctype=False)
make_property_setter(doctype, "payment_schedule", "print_hide", 0 if show_in_print else 1, "Check", validate_fields_for_doctype=False)
+
+ def toggle_discount_accounting_fields(self):
+ enable_discount_accounting = cint(self.enable_discount_accounting)
+
+ make_property_setter("Sales Invoice Item", "discount_account", "hidden", not(enable_discount_accounting), "Check", validate_fields_for_doctype=False)
+ make_property_setter("Item", "default_discount_account", "hidden", not(enable_discount_accounting), "Check", validate_fields_for_doctype=False)
\ No newline at end of file
From d24b5f707a870e1e1c44ce0caadff9005c79f633 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Mon, 12 Jul 2021 18:56:06 +0530
Subject: [PATCH 112/386] fix: Add description for Enable Discount Accounting
checkbox
---
.../doctype/accounts_settings/accounts_settings.json | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/erpnext/accounts/doctype/accounts_settings/accounts_settings.json b/erpnext/accounts/doctype/accounts_settings/accounts_settings.json
index 676c6a8b47..49a2afee85 100644
--- a/erpnext/accounts/doctype/accounts_settings/accounts_settings.json
+++ b/erpnext/accounts/doctype/accounts_settings/accounts_settings.json
@@ -12,7 +12,6 @@
"role_allowed_to_over_bill",
"make_payment_via_journal_entry",
"column_break_11",
- "enable_discount_accounting",
"check_supplier_invoice_uniqueness",
"unlink_payment_on_cancellation_of_invoice",
"automatically_fetch_payment_terms",
@@ -20,6 +19,7 @@
"book_asset_depreciation_entry_automatically",
"unlink_advance_payment_on_cancelation_of_order",
"post_change_gl_entries",
+ "enable_discount_accounting",
"tax_settings_section",
"determine_address_tax_category_from",
"column_break_19",
@@ -265,6 +265,7 @@
},
{
"default": "0",
+ "description": "If enabled, additional ledger entries will be made for discounts in a separate Discount Account",
"fieldname": "enable_discount_accounting",
"fieldtype": "Check",
"label": "Enable Discount Accounting"
@@ -275,7 +276,7 @@
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
- "modified": "2021-07-05 14:56:19.820731",
+ "modified": "2021-07-12 18:54:29.084958",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Accounts Settings",
From cfb94175a2458b47ec54fb0ccabcb0a682004504 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Mon, 12 Jul 2021 19:07:54 +0530
Subject: [PATCH 113/386] fix: Filter Discount Account list
---
.../doctype/sales_invoice/sales_invoice.js | 22 +++++++++++--------
1 file changed, 13 insertions(+), 9 deletions(-)
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
index dc0d9da97b..17228a3c28 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
@@ -510,15 +510,6 @@ cur_frm.set_query("income_account", "items", function(doc) {
}
});
-// Discount Account in Details Table
-// --------------------------------
-cur_frm.set_query("discount_account", "items", function(doc) {
- return{
- query: "erpnext.controllers.queries.get_income_account",
- filters: {'company': doc.company}
- }
-});
-
// Cost Center in Details Table
// -----------------------------
cur_frm.fields_dict["items"].grid.get_field("cost_center").get_query = function(doc) {
@@ -626,6 +617,19 @@ frappe.ui.form.on('Sales Invoice', {
}
}
+ // discount account
+ frm.fields_dict['items'].grid.get_field('discount_account').get_query = function(doc) {
+ if (erpnext.is_perpetual_inventory_enabled(doc.company)) {
+ return {
+ filters: {
+ 'report_type': 'Profit and Loss',
+ 'company': doc.company,
+ "is_group": 0
+ }
+ }
+ }
+ }
+
frm.fields_dict['items'].grid.get_field('deferred_revenue_account').get_query = function(doc) {
return {
filters: {
From 613d08faad544cd0c6855e30bf082538c2c992cf Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Mon, 12 Jul 2021 22:32:38 +0530
Subject: [PATCH 114/386] fix: Copy discount account from first row to all
Items
---
erpnext/accounts/doctype/sales_invoice/sales_invoice.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
index 17228a3c28..2b48d66dca 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
@@ -347,8 +347,8 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
items_add: function(doc, cdt, cdn) {
var row = frappe.get_doc(cdt, cdn);
- this.frm.script_manager.copy_from_first_row("items", row, ["income_account", "cost_center"]);
- },
+ this.frm.script_manager.copy_from_first_row("items", row, ["income_account", "discount_account", "cost_center"]);
+ }
set_dynamic_labels: function() {
this._super();
From 546c8d125c6563ffa57f31b08a79948c7ce0d8ba Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Tue, 13 Jul 2021 01:37:30 +0530
Subject: [PATCH 115/386] fix: Move Default Discount Account field to Item
Defaults
---
erpnext/stock/doctype/item/item.json | 9 +-
.../doctype/item_default/item_default.json | 548 ++++--------------
erpnext/stock/get_item_details.py | 4 +-
3 files changed, 104 insertions(+), 457 deletions(-)
diff --git a/erpnext/stock/doctype/item/item.json b/erpnext/stock/doctype/item/item.json
index f1c413e00a..f662bbd1c7 100644
--- a/erpnext/stock/doctype/item/item.json
+++ b/erpnext/stock/doctype/item/item.json
@@ -91,7 +91,6 @@
"is_sales_item",
"column_break3",
"max_discount",
- "default_discount_account",
"deferred_revenue",
"deferred_revenue_account",
"enable_deferred_revenue",
@@ -1059,12 +1058,6 @@
"fieldname": "website_image_alt",
"fieldtype": "Data",
"label": "Image Description"
- },
- {
- "fieldname": "default_discount_account",
- "fieldtype": "Link",
- "label": "Default Discount Account",
- "options": "Account"
}
],
"has_web_view": 1,
@@ -1074,7 +1067,7 @@
"index_web_pages_for_search": 1,
"links": [],
"max_attachments": 1,
- "modified": "2021-07-06 00:46:15.878648",
+ "modified": "2021-07-13 01:29:06.071827",
"modified_by": "Administrator",
"module": "Stock",
"name": "Item",
diff --git a/erpnext/stock/doctype/item_default/item_default.json b/erpnext/stock/doctype/item_default/item_default.json
index 96b5dfdc8f..bc171604f4 100644
--- a/erpnext/stock/doctype/item_default/item_default.json
+++ b/erpnext/stock/doctype/item_default/item_default.json
@@ -1,464 +1,118 @@
{
- "allow_copy": 0,
- "allow_events_in_timeline": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "beta": 0,
- "creation": "2018-05-03 02:29:24.444341",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "",
- "editable_grid": 1,
- "engine": "InnoDB",
+ "actions": [],
+ "creation": "2018-05-03 02:29:24.444341",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "company",
+ "default_warehouse",
+ "column_break_3",
+ "default_price_list",
+ "default_discount_account",
+ "purchase_defaults",
+ "buying_cost_center",
+ "default_supplier",
+ "column_break_8",
+ "expense_account",
+ "selling_defaults",
+ "selling_cost_center",
+ "column_break_12",
+ "income_account"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "company",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 1,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Company",
- "length": 0,
- "no_copy": 0,
- "options": "Company",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "ignore_user_permissions": 1,
+ "in_list_view": 1,
+ "label": "Company",
+ "options": "Company",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "default_warehouse",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "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
- },
+ "fieldname": "default_warehouse",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Default Warehouse",
+ "options": "Warehouse"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_3",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "column_break_3",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "default_price_list",
- "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 Price List",
- "length": 0,
- "no_copy": 0,
- "options": "Price List",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "default_price_list",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Default Price List",
+ "options": "Price List"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "purchase_defaults",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Purchase Defaults",
- "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": "purchase_defaults",
+ "fieldtype": "Section Break",
+ "label": "Purchase Defaults"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "buying_cost_center",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Default Buying Cost Center",
- "length": 0,
- "no_copy": 0,
- "options": "Cost Center",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "buying_cost_center",
+ "fieldtype": "Link",
+ "label": "Default Buying Cost Center",
+ "options": "Cost Center"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "default_supplier",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Default Supplier",
- "length": 0,
- "no_copy": 0,
- "options": "Supplier",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "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": "default_supplier",
+ "fieldtype": "Link",
+ "label": "Default Supplier",
+ "options": "Supplier"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_8",
- "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_8",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "expense_account",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Default Expense Account",
- "length": 0,
- "no_copy": 0,
- "options": "Account",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "expense_account",
+ "fieldtype": "Link",
+ "label": "Default Expense Account",
+ "options": "Account"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "selling_defaults",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Sales Defaults",
- "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": "selling_defaults",
+ "fieldtype": "Section Break",
+ "label": "Sales Defaults"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "selling_cost_center",
- "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 Selling Cost Center",
- "length": 0,
- "no_copy": 0,
- "options": "Cost Center",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "selling_cost_center",
+ "fieldtype": "Link",
+ "label": "Default Selling Cost Center",
+ "options": "Cost Center"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_12",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "column_break_12",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "income_account",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Default Income Account",
- "length": 0,
- "no_copy": 0,
- "options": "Account",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "fieldname": "income_account",
+ "fieldtype": "Link",
+ "label": "Default Income Account",
+ "options": "Account"
+ },
+ {
+ "fieldname": "default_discount_account",
+ "fieldtype": "Link",
+ "label": "Default Discount Account",
+ "options": "Account"
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 1,
- "max_attachments": 0,
- "modified": "2018-12-07 11:48:07.638935",
- "modified_by": "Administrator",
- "module": "Stock",
- "name": "Item Default",
- "name_case": "",
- "owner": "Administrator",
- "permissions": [],
- "quick_entry": 1,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1,
- "track_seen": 0,
- "track_views": 0
+ ],
+ "istable": 1,
+ "links": [],
+ "modified": "2021-07-13 01:26:03.860065",
+ "modified_by": "Administrator",
+ "module": "Stock",
+ "name": "Item Default",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
}
\ No newline at end of file
diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py
index bf082f89be..cadb4aa97b 100644
--- a/erpnext/stock/get_item_details.py
+++ b/erpnext/stock/get_item_details.py
@@ -590,8 +590,8 @@ def get_default_expense_account(args, item, item_group, brand):
or brand.get("expense_account")
or args.expense_account)
-def get_default_discount_account(args, item_defaults):
- return (item_defaults.default_discount_account
+def get_default_discount_account(args, item):
+ return (item.get("default_discount_account")
or args.discount_account)
def get_default_deferred_account(args, item, fieldname=None):
From ee025b501fbb15ab21ceaf8f3bf36f892279c4ed Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Tue, 13 Jul 2021 01:43:41 +0530
Subject: [PATCH 116/386] fix: Filter options for Default Discount Account
---
erpnext/stock/doctype/item/item.js | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/erpnext/stock/doctype/item/item.js b/erpnext/stock/doctype/item/item.js
index 264baeaa47..2fee57f2d1 100644
--- a/erpnext/stock/doctype/item/item.js
+++ b/erpnext/stock/doctype/item/item.js
@@ -274,6 +274,17 @@ $.extend(erpnext.item, {
}
}
+ frm.fields_dict["item_defaults"].grid.get_field("default_discount_account").get_query = function(doc, cdt, cdn) {
+ const row = locals[cdt][cdn];
+ return {
+ filters: {
+ 'report_type': 'Profit and Loss',
+ 'company': row.company,
+ "is_group": 0
+ }
+ }
+ }
+
frm.fields_dict["item_defaults"].grid.get_field("buying_cost_center").get_query = function(doc, cdt, cdn) {
const row = locals[cdt][cdn];
return {
From bde5c619db8e80796a923cc57af1d97cc235f125 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Tue, 13 Jul 2021 02:06:03 +0530
Subject: [PATCH 117/386] fix: Add Discount Account field
---
.../purchase_invoice_item/purchase_invoice_item.json | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
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 8a55ff87e3..922b567d15 100644
--- a/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json
+++ b/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json
@@ -73,6 +73,7 @@
"manufacturer_part_no",
"accounting",
"expense_account",
+ "discount_account",
"col_break5",
"is_fixed_asset",
"asset_location",
@@ -849,12 +850,18 @@
"options": "Company:company:default_currency",
"print_hide": 1,
"read_only": 1
+ },
+ {
+ "fieldname": "discount_account",
+ "fieldtype": "Link",
+ "label": "Discount Account",
+ "options": "Account"
}
],
"idx": 1,
"istable": 1,
"links": [],
- "modified": "2021-06-16 19:57:03.101571",
+ "modified": "2021-07-13 02:04:37.787882",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Invoice Item",
From e2c83c3bafe00951a66bb9405bd6da911539a875 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Tue, 13 Jul 2021 02:07:46 +0530
Subject: [PATCH 118/386] fix: Display Discount Account only if Enable Discount
Accounting is checked
---
.../accounts/doctype/accounts_settings/accounts_settings.py | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/erpnext/accounts/doctype/accounts_settings/accounts_settings.py b/erpnext/accounts/doctype/accounts_settings/accounts_settings.py
index 9e33eb395b..d1abdba379 100644
--- a/erpnext/accounts/doctype/accounts_settings/accounts_settings.py
+++ b/erpnext/accounts/doctype/accounts_settings/accounts_settings.py
@@ -38,5 +38,7 @@ class AccountsSettings(Document):
def toggle_discount_accounting_fields(self):
enable_discount_accounting = cint(self.enable_discount_accounting)
- make_property_setter("Sales Invoice Item", "discount_account", "hidden", not(enable_discount_accounting), "Check", validate_fields_for_doctype=False)
+ for doctype in ["Sales Invoice Item", "Purchase Invoice Item"]:
+ make_property_setter(doctype, "discount_account", "hidden", not(enable_discount_accounting), "Check", validate_fields_for_doctype=False)
+
make_property_setter("Item", "default_discount_account", "hidden", not(enable_discount_accounting), "Check", validate_fields_for_doctype=False)
\ No newline at end of file
From 377775ad8ead56e000717ce769e4da06fb5e7855 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Tue, 13 Jul 2021 02:09:40 +0530
Subject: [PATCH 119/386] fix: Copy Discount Account from first row
---
erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
index dc9094c3e9..81e3aaa8a5 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
@@ -365,7 +365,7 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
items_add: function(doc, cdt, cdn) {
var row = frappe.get_doc(cdt, cdn);
this.frm.script_manager.copy_from_first_row("items", row,
- ["expense_account", "cost_center", "project"]);
+ ["expense_account", "discount_account", "cost_center", "project"]);
},
on_submit: function() {
From e06eb8e6a9fe6f6c36bf83f49bb5f72f1203b794 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Tue, 13 Jul 2021 02:14:18 +0530
Subject: [PATCH 120/386] fix: Filter options for Discount Account
---
.../doctype/purchase_invoice/purchase_invoice.js | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
index 81e3aaa8a5..a1ee5d0076 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
@@ -508,6 +508,16 @@ frappe.ui.form.on("Purchase Invoice", {
}
}
}
+
+ frm.fields_dict['items'].grid.get_field('discount_account').get_query = function(doc) {
+ return {
+ filters: {
+ 'report_type': 'Profit and Loss',
+ 'company': doc.company,
+ "is_group": 0
+ }
+ }
+ }
},
refresh: function(frm) {
From fd2852e87e3b03c019cff84669f908fdc70f3704 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Tue, 13 Jul 2021 03:01:02 +0530
Subject: [PATCH 121/386] fix: Create common function for discount accounting
---
.../purchase_invoice/purchase_invoice.py | 1 +
.../doctype/sales_invoice/sales_invoice.py | 34 --------------
erpnext/controllers/accounts_controller.py | 45 +++++++++++++++++++
3 files changed, 46 insertions(+), 34 deletions(-)
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
index f7992797ed..78d1ee972f 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
@@ -446,6 +446,7 @@ class PurchaseInvoice(BuyingController):
self.make_supplier_gl_entry(gl_entries)
self.make_item_gl_entries(gl_entries)
+ self.make_discount_gl_entries(gl_entries)
if self.check_asset_cwip_enabled():
self.get_asset_gl_entry(gl_entries)
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index 04c789d30a..15fae84b79 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -960,40 +960,6 @@ class SalesInvoice(SellingController):
erpnext.is_perpetual_inventory_enabled(self.company):
gl_entries += super(SalesInvoice, self).get_gl_entries()
- def make_discount_gl_entries(self, gl_entries):
- enable_discount_accounting = cint(frappe.db.get_single_value('Accounts Settings', 'enable_discount_accounting'))
-
- if enable_discount_accounting:
- for item in self.get("items"):
- if item.get('discount_amount') and item.get('discount_account'):
- account_currency = get_account_currency(item.discount_account)
- gl_entries.append(
- self.get_gl_dict({
- "account": item.discount_account,
- "against": self.customer,
- "debit": flt(item.discount_amount),
- "debit_in_account_currency": flt(item.discount_amount),
- "cost_center": self.cost_center,
- "project": self.project
- }, account_currency, item=self)
- )
-
- income_account = (item.income_account
- if (not item.enable_deferred_revenue or self.is_return)
- else item.deferred_revenue_account)
-
- account_currency = get_account_currency(income_account)
- gl_entries.append(
- self.get_gl_dict({
- "account": income_account,
- "against": self.customer,
- "credit": flt(item.discount_amount),
- "credit_in_account_currency": flt(item.discount_amount),
- "cost_center": item.cost_center,
- "project": item.project or self.project
- }, account_currency, item=item)
- )
-
def make_loyalty_point_redemption_gle(self, gl_entries):
if cint(self.redeem_loyalty_points):
gl_entries.append(
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index 4c313c43a7..0a11582508 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -808,6 +808,51 @@ class AccountsController(TransactionBase):
tax_map[tax.account_head] -= allocated_amount
allocated_tax_map[tax.account_head] -= allocated_amount
+ def make_discount_gl_entries(self, gl_entries):
+ enable_discount_accounting = cint(frappe.db.get_single_value('Accounts Settings', 'enable_discount_accounting'))
+
+ if enable_discount_accounting:
+ for item in self.get("items"):
+ if item.get('discount_amount') and item.get('discount_account'):
+ if self.doctype == "Purchase Invoice":
+ dr_or_cr = "credit"
+ rev_dr_cr = "debit"
+ supplier_or_customer = self.supplier
+ income_or_expense_account = (item.expense_account
+ if (not item.enable_deferred_expense or self.is_return)
+ else item.deferred_expense_account)
+ else:
+ dr_or_cr = "debit"
+ rev_dr_cr = "credit"
+ supplier_or_customer = self.customer
+ income_or_expense_account = (item.income_account
+ if (not item.enable_deferred_revenue or self.is_return)
+ else item.deferred_revenue_account)
+
+ account_currency = get_account_currency(item.discount_account)
+ gl_entries.append(
+ self.get_gl_dict({
+ "account": item.discount_account,
+ "against": supplier_or_customer,
+ dr_or_cr: flt(item.discount_amount),
+ dr_or_cr + "_in_account_currency": flt(item.discount_amount),
+ "cost_center": self.cost_center,
+ "project": self.project
+ }, account_currency, item=self)
+ )
+
+ account_currency = get_account_currency(income_or_expense_account)
+ gl_entries.append(
+ self.get_gl_dict({
+ "account": income_or_expense_account,
+ "against": supplier_or_customer,
+ rev_dr_cr: flt(item.discount_amount),
+ rev_dr_cr + "_in_account_currency": flt(item.discount_amount),
+ "cost_center": item.cost_center,
+ "project": item.project or self.project
+ }, account_currency, item=item)
+ )
+
def allocate_advance_taxes(self, gl_entries):
tax_map = self.get_tax_map()
for pe in self.get("advances"):
From 38e87fce099100d1db3386730140212bc8a42d51 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Tue, 13 Jul 2021 17:41:29 +0530
Subject: [PATCH 122/386] fix: Add tests for discount accounting
---
.../purchase_invoice/test_purchase_invoice.py | 20 ++++++++++++++++++-
.../sales_invoice/test_sales_invoice.py | 15 ++++++++++++++
2 files changed, 34 insertions(+), 1 deletion(-)
diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
index ca4d009956..bd7ded269c 100644
--- a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
@@ -230,6 +230,16 @@ class TestPurchaseInvoice(unittest.TestCase):
self.assertEqual(expected_values[gle.account][1], gle.debit)
self.assertEqual(expected_values[gle.account][2], gle.credit)
+ def test_purchase_invoice_with_discount_accounting_enabled(self):
+ enable_discount_accounting()
+
+ discount_account = create_account(account_name="Discount Account",
+ parent_account="Indirect Expenses - _TC", company="_Test Company")
+ pi = make_purchase_invoice(discount_account=discount_account, discount_amount=100)
+
+ discount_amount = frappe.db.get_value('GL Entry', {'account': discount_account, 'voucher_no': pi.name}, 'credit')
+ self.assertEqual(discount_amount, 100)
+
def test_purchase_invoice_change_naming_series(self):
pi = frappe.copy_doc(test_records[1])
pi.insert()
@@ -1170,6 +1180,11 @@ def unlink_payment_on_cancel_of_invoice(enable=1):
accounts_settings.unlink_payment_on_cancellation_of_invoice = enable
accounts_settings.save()
+def enable_discount_accounting(enable=1):
+ accounts_settings = frappe.get_doc("Accounts Settings")
+ accounts_settings.enable_discount_accounting = enable
+ accounts_settings.save()
+
def make_purchase_invoice(**args):
pi = frappe.new_doc("Purchase Invoice")
args = frappe._dict(args)
@@ -1192,6 +1207,7 @@ def make_purchase_invoice(**args):
pi.return_against = args.return_against
pi.is_subcontracted = args.is_subcontracted or "No"
pi.supplier_warehouse = args.supplier_warehouse or "_Test Warehouse 1 - _TC"
+ pi.cost_center = args.cost_center or "_Test Cost Center - _TC"
pi.append("items", {
"item_code": args.item or args.item_code or "_Test Item",
@@ -1200,7 +1216,9 @@ def make_purchase_invoice(**args):
"received_qty": args.received_qty or 0,
"rejected_qty": args.rejected_qty or 0,
"rate": args.rate or 50,
- 'expense_account': args.expense_account or '_Test Account Cost for Goods Sold - _TC',
+ "expense_account": args.expense_account or '_Test Account Cost for Goods Sold - _TC',
+ "discount_account": args.discount_account or None,
+ "discount_amount": args.discount_amount or 0,
"conversion_factor": 1.0,
"serial_no": args.serial_no,
"stock_uom": args.uom or "_Test UOM",
diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
index dbc7f8632f..d03a874c28 100644
--- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
@@ -1984,6 +1984,18 @@ class TestSalesInvoice(unittest.TestCase):
sales_invoice.save()
self.assertEqual(sales_invoice.items[0].item_tax_template, "_Test Account Excise Duty @ 10 - _TC")
+ def test_sales_invoice_with_discount_accounting_enabled(self):
+ from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import enable_discount_accounting
+
+ enable_discount_accounting()
+
+ discount_account = create_account(account_name="Discount Account",
+ parent_account="Indirect Expenses - _TC", company="_Test Company")
+ si = create_sales_invoice(discount_account=discount_account, discount_amount=100)
+
+ discount_amount = frappe.db.get_value('GL Entry', {'account': discount_account, 'voucher_no': si.name}, 'debit')
+ self.assertEqual(discount_amount, 100)
+
def get_sales_invoice_for_e_invoice():
si = make_sales_invoice_for_ewaybill()
si.naming_series = 'INV-2020-.#####'
@@ -2152,6 +2164,7 @@ def create_sales_invoice(**args):
si.currency=args.currency or "INR"
si.conversion_rate = args.conversion_rate or 1
si.naming_series = args.naming_series or "T-SINV-"
+ si.cost_center = args.cost_center or "_Test Cost Center - _TC"
si.append("items", {
"item_code": args.item or args.item_code or "_Test Item",
@@ -2165,6 +2178,8 @@ def create_sales_invoice(**args):
"rate": args.rate if args.get("rate") is not None else 100,
"income_account": args.income_account or "Sales - _TC",
"expense_account": args.expense_account or "Cost of Goods Sold - _TC",
+ "discount_account": args.discount_account or None,
+ "discount_amount": args.discount_amount or 0,
"cost_center": args.cost_center or "_Test Cost Center - _TC",
"serial_no": args.serial_no,
"conversion_factor": 1
From 9e788cfdcd866780b16195fff411a4dc4bfd822d Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Thu, 15 Jul 2021 22:01:02 +0530
Subject: [PATCH 123/386] fix: Add Additional Discount Account field
---
.../accounts/doctype/sales_invoice/sales_invoice.json | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
index e7dd6b8a60..5c09b71cf3 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
@@ -104,6 +104,7 @@
"section_break_49",
"apply_discount_on",
"base_discount_amount",
+ "additional_discount_account",
"column_break_51",
"additional_discount_percentage",
"discount_amount",
@@ -1966,6 +1967,12 @@
"fieldname": "disable_rounded_total",
"fieldtype": "Check",
"label": "Disable Rounded Total"
+ },
+ {
+ "fieldname": "additional_discount_account",
+ "fieldtype": "Link",
+ "label": "Additional Discount Account",
+ "options": "Account"
}
],
"icon": "fa fa-file-text",
@@ -1978,7 +1985,7 @@
"link_fieldname": "consolidated_invoice"
}
],
- "modified": "2021-05-20 22:48:33.988881",
+ "modified": "2021-07-15 21:57:17.544279",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice",
From c1d65cfa8d987c734b412026a7fbc5aec427359a Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Thu, 15 Jul 2021 22:01:38 +0530
Subject: [PATCH 124/386] fix: Filter options for Additional Discount Account
---
.../accounts/doctype/sales_invoice/sales_invoice.js | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
index 2b48d66dca..fab0e11324 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
@@ -591,6 +591,16 @@ frappe.ui.form.on('Sales Invoice', {
};
});
+ frm.set_query("additional_discount_account", function() {
+ return {
+ filters: {
+ company: frm.doc.company,
+ is_group: 0,
+ root_type: "Profit and Loss",
+ }
+ };
+ });
+
frm.custom_make_buttons = {
'Delivery Note': 'Delivery',
'Sales Invoice': 'Return / Credit Note',
From b64787ee9ca81aa18904419e072296c1932ed15a Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Thu, 15 Jul 2021 22:02:43 +0530
Subject: [PATCH 125/386] fix: Only display Additional Discount Account if
Enable Discount Accounting is checked
---
.../accounts/doctype/accounts_settings/accounts_settings.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/erpnext/accounts/doctype/accounts_settings/accounts_settings.py b/erpnext/accounts/doctype/accounts_settings/accounts_settings.py
index d1abdba379..053f061acc 100644
--- a/erpnext/accounts/doctype/accounts_settings/accounts_settings.py
+++ b/erpnext/accounts/doctype/accounts_settings/accounts_settings.py
@@ -41,4 +41,5 @@ class AccountsSettings(Document):
for doctype in ["Sales Invoice Item", "Purchase Invoice Item"]:
make_property_setter(doctype, "discount_account", "hidden", not(enable_discount_accounting), "Check", validate_fields_for_doctype=False)
- make_property_setter("Item", "default_discount_account", "hidden", not(enable_discount_accounting), "Check", validate_fields_for_doctype=False)
\ No newline at end of file
+ make_property_setter("Item", "default_discount_account", "hidden", not(enable_discount_accounting), "Check", validate_fields_for_doctype=False)
+ make_property_setter("Sales Invoice", "additional_discount_account", "hidden", not(enable_discount_accounting), "Check", validate_fields_for_doctype=False)
\ No newline at end of file
From 38327fc17764516a5844af6ee4fcf36986e715b6 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Thu, 15 Jul 2021 22:03:46 +0530
Subject: [PATCH 126/386] fix: Make additional GL Entries for discount applied
on taxes
---
erpnext/controllers/accounts_controller.py | 36 ++++++++++++++++++++++
1 file changed, 36 insertions(+)
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index 0a11582508..8fc4023f2e 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -852,6 +852,42 @@ class AccountsController(TransactionBase):
"project": item.project or self.project
}, account_currency, item=item)
)
+
+ if self.get('discount_amount') and self.get('additional_discount_account'):
+ self.make_gle_for_additional_discount_applied_on_taxes(gl_entries)
+
+ def make_gle_for_additional_discount_applied_on_taxes(self, gl_entries):
+ for tax in self.get("taxes"):
+ if flt(tax.base_tax_amount_after_discount_amount) and flt(tax.base_tax_amount):
+ account_currency = get_account_currency(tax.account_head)
+ additional_discount_applied_on_taxes = flt(tax.base_tax_amount) - flt(tax.base_tax_amount_after_discount_amount)
+
+ gl_entries.append(
+ self.get_gl_dict({
+ "account": tax.account_head,
+ "against": self.customer,
+ "credit": flt(additional_discount_applied_on_taxes,
+ tax.precision("tax_amount_after_discount_amount")),
+ "credit_in_account_currency": (flt(additional_discount_applied_on_taxes,
+ tax.precision("base_tax_amount_after_discount_amount")) if account_currency==self.company_currency else
+ flt(additional_discount_applied_on_taxes, tax.precision("tax_amount_after_discount_amount"))),
+ "cost_center": tax.cost_center
+ }, account_currency, item=tax)
+ )
+
+ gl_entries.append(
+ self.get_gl_dict({
+ "account": self.additional_discount_account,
+ "against": self.customer,
+ "debit": flt(additional_discount_applied_on_taxes,
+ tax.precision("tax_amount_after_discount_amount")),
+ "debit_in_account_currency": (flt(additional_discount_applied_on_taxes,
+ tax.precision("base_tax_amount_after_discount_amount")) if account_currency==self.company_currency else
+ flt(additional_discount_applied_on_taxes, tax.precision("tax_amount_after_discount_amount"))),
+ "cost_center": tax.cost_center
+ }, account_currency, item=tax)
+ )
+
def allocate_advance_taxes(self, gl_entries):
tax_map = self.get_tax_map()
From d6f409addcedaff16339000374b74a5d93be31db Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Fri, 16 Jul 2021 02:18:45 +0530
Subject: [PATCH 127/386] fix: Sider issues
---
erpnext/stock/doctype/item/item.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/erpnext/stock/doctype/item/item.js b/erpnext/stock/doctype/item/item.js
index 2fee57f2d1..4566618385 100644
--- a/erpnext/stock/doctype/item/item.js
+++ b/erpnext/stock/doctype/item/item.js
@@ -282,8 +282,8 @@ $.extend(erpnext.item, {
'company': row.company,
"is_group": 0
}
- }
- }
+ };
+ };
frm.fields_dict["item_defaults"].grid.get_field("buying_cost_center").get_query = function(doc, cdt, cdn) {
const row = locals[cdt][cdn];
From d0d9e83ad202f22d1cc3c6c21f20f9b934ad3700 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Sat, 17 Jul 2021 17:34:50 +0530
Subject: [PATCH 128/386] fix: Check all expected GL Entries
---
.../doctype/purchase_invoice/test_purchase_invoice.py | 11 +++++++++--
.../doctype/sales_invoice/test_sales_invoice.py | 9 +++++++--
2 files changed, 16 insertions(+), 4 deletions(-)
diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
index bd7ded269c..36fbc7e351 100644
--- a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
@@ -231,14 +231,21 @@ class TestPurchaseInvoice(unittest.TestCase):
self.assertEqual(expected_values[gle.account][2], gle.credit)
def test_purchase_invoice_with_discount_accounting_enabled(self):
+ from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import check_gl_entries
+
enable_discount_accounting()
discount_account = create_account(account_name="Discount Account",
parent_account="Indirect Expenses - _TC", company="_Test Company")
pi = make_purchase_invoice(discount_account=discount_account, discount_amount=100)
- discount_amount = frappe.db.get_value('GL Entry', {'account': discount_account, 'voucher_no': pi.name}, 'credit')
- self.assertEqual(discount_amount, 100)
+ expected_gle = [
+ ["Discount Account - _TC", 0.0, 100.0, nowdate()],
+ ["_Test Account Cost for Goods Sold - _TC", 350.0, 0.0, nowdate()],
+ ["Creditors - _TC", 0.0, 250.0, nowdate()]
+ ]
+
+ check_gl_entries(self, pi.name, expected_gle, nowdate())
def test_purchase_invoice_change_naming_series(self):
pi = frappe.copy_doc(test_records[1])
diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
index d03a874c28..2ddfad9c31 100644
--- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
@@ -1992,9 +1992,14 @@ class TestSalesInvoice(unittest.TestCase):
discount_account = create_account(account_name="Discount Account",
parent_account="Indirect Expenses - _TC", company="_Test Company")
si = create_sales_invoice(discount_account=discount_account, discount_amount=100)
+
+ expected_gle = [
+ ["Discount Account - _TC", 100.0, 0.0, nowdate()],
+ ["Sales - _TC", 0.0, 200.0, nowdate()],
+ ["Debtors - _TC", 100.0, 0.0, nowdate()]
+ ]
- discount_amount = frappe.db.get_value('GL Entry', {'account': discount_account, 'voucher_no': si.name}, 'debit')
- self.assertEqual(discount_amount, 100)
+ check_gl_entries(self, si.name, expected_gle, nowdate())
def get_sales_invoice_for_e_invoice():
si = make_sales_invoice_for_ewaybill()
From 03f270697194c81f50a66d3318cbf2928ddfb9e8 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Sat, 17 Jul 2021 17:40:43 +0530
Subject: [PATCH 129/386] fix: Add Additional Discount Account field
---
.../doctype/purchase_invoice/purchase_invoice.json | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
index 00ef7d5c18..96ae828f46 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
@@ -96,6 +96,7 @@
"section_break_44",
"apply_discount_on",
"base_discount_amount",
+ "additional_discount_account",
"column_break_46",
"additional_discount_percentage",
"discount_amount",
@@ -1377,13 +1378,19 @@
"no_copy": 1,
"print_hide": 1,
"read_only": 1
+ },
+ {
+ "fieldname": "additional_discount_account",
+ "fieldtype": "Link",
+ "label": "Additional Discount Account",
+ "options": "Account"
}
],
"icon": "fa fa-file-text",
"idx": 204,
"is_submittable": 1,
"links": [],
- "modified": "2021-06-15 18:20:56.806195",
+ "modified": "2021-07-17 17:37:50.570595",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Invoice",
From ff25683378769b5869f19dc49f8165d18938a8fd Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Sat, 17 Jul 2021 17:41:06 +0530
Subject: [PATCH 130/386] fix: Filter options for Additional Discount Account
---
.../doctype/purchase_invoice/purchase_invoice.js | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
index a1ee5d0076..4ed31cc227 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
@@ -499,6 +499,16 @@ frappe.ui.form.on("Purchase Invoice", {
'Payment Entry': 'Payment'
}
+ frm.set_query("additional_discount_account", function() {
+ return {
+ filters: {
+ company: frm.doc.company,
+ is_group: 0,
+ root_type: "Profit and Loss",
+ }
+ };
+ });
+
frm.fields_dict['items'].grid.get_field('deferred_expense_account').get_query = function(doc) {
return {
filters: {
From 9dd2a9e8973fe4e5c70dc4aa65683870281e4091 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Sat, 17 Jul 2021 17:42:36 +0530
Subject: [PATCH 131/386] fix: Create ledger entries for discount applied on
taxes in make_tax_gl_entries
---
.../accounts/doctype/purchase_invoice/purchase_invoice.py | 5 +++++
erpnext/accounts/doctype/sales_invoice/sales_invoice.py | 5 +++++
erpnext/controllers/accounts_controller.py | 3 ---
3 files changed, 10 insertions(+), 3 deletions(-)
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
index 78d1ee972f..006f5bb0e8 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
@@ -888,6 +888,11 @@ class PurchaseInvoice(BuyingController):
"remarks": self.remarks or "Accounting Entry for Stock"
}, item=tax))
+ enable_discount_accounting = cint(frappe.db.get_single_value('Accounts Settings', 'enable_discount_accounting'))
+
+ if enable_discount_accounting and self.get('discount_amount') and self.get('additional_discount_account'):
+ self.make_gle_for_additional_discount_applied_on_taxes(gl_entries)
+
def make_internal_transfer_gl_entries(self, gl_entries):
if self.is_internal_transfer() and flt(self.base_total_taxes_and_charges):
account_currency = get_account_currency(self.unrealized_profit_loss_account)
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index 15fae84b79..ee9b59e769 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -902,6 +902,11 @@ class SalesInvoice(SellingController):
}, account_currency, item=tax)
)
+ enable_discount_accounting = cint(frappe.db.get_single_value('Accounts Settings', 'enable_discount_accounting'))
+
+ if enable_discount_accounting and self.get('discount_amount') and self.get('additional_discount_account'):
+ self.make_gle_for_additional_discount_applied_on_taxes(gl_entries)
+
def make_internal_transfer_gl_entries(self, gl_entries):
if self.is_internal_transfer() and flt(self.base_total_taxes_and_charges):
account_currency = get_account_currency(self.unrealized_profit_loss_account)
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index 8fc4023f2e..f4593c2a76 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -852,9 +852,6 @@ class AccountsController(TransactionBase):
"project": item.project or self.project
}, account_currency, item=item)
)
-
- if self.get('discount_amount') and self.get('additional_discount_account'):
- self.make_gle_for_additional_discount_applied_on_taxes(gl_entries)
def make_gle_for_additional_discount_applied_on_taxes(self, gl_entries):
for tax in self.get("taxes"):
From 4da7c5882ba8a05c42a013c3b0690b1701da14f9 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Sat, 17 Jul 2021 17:45:35 +0530
Subject: [PATCH 132/386] fix: Only display Additional Discount Account if
Enable Discount Accounting is checked
---
.../accounts/doctype/accounts_settings/accounts_settings.py | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/erpnext/accounts/doctype/accounts_settings/accounts_settings.py b/erpnext/accounts/doctype/accounts_settings/accounts_settings.py
index 053f061acc..24b0ec4d4a 100644
--- a/erpnext/accounts/doctype/accounts_settings/accounts_settings.py
+++ b/erpnext/accounts/doctype/accounts_settings/accounts_settings.py
@@ -41,5 +41,7 @@ class AccountsSettings(Document):
for doctype in ["Sales Invoice Item", "Purchase Invoice Item"]:
make_property_setter(doctype, "discount_account", "hidden", not(enable_discount_accounting), "Check", validate_fields_for_doctype=False)
- make_property_setter("Item", "default_discount_account", "hidden", not(enable_discount_accounting), "Check", validate_fields_for_doctype=False)
- make_property_setter("Sales Invoice", "additional_discount_account", "hidden", not(enable_discount_accounting), "Check", validate_fields_for_doctype=False)
\ No newline at end of file
+ for doctype in ["Sales Invoice", "Purchase Invoice"]:
+ make_property_setter(doctype, "additional_discount_account", "hidden", not(enable_discount_accounting), "Check", validate_fields_for_doctype=False)
+
+ make_property_setter("Item", "default_discount_account", "hidden", not(enable_discount_accounting), "Check", validate_fields_for_doctype=False)
\ No newline at end of file
From d62af77ca8e88b83a921e892fffd583ffd21f6c6 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Sat, 17 Jul 2021 17:47:20 +0530
Subject: [PATCH 133/386] fix: Remove unnecessary condition
---
.../accounts/doctype/sales_invoice/sales_invoice.js | 12 +++++-------
1 file changed, 5 insertions(+), 7 deletions(-)
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
index fab0e11324..a5341df2e3 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
@@ -629,13 +629,11 @@ frappe.ui.form.on('Sales Invoice', {
// discount account
frm.fields_dict['items'].grid.get_field('discount_account').get_query = function(doc) {
- if (erpnext.is_perpetual_inventory_enabled(doc.company)) {
- return {
- filters: {
- 'report_type': 'Profit and Loss',
- 'company': doc.company,
- "is_group": 0
- }
+ return {
+ filters: {
+ 'report_type': 'Profit and Loss',
+ 'company': doc.company,
+ "is_group": 0
}
}
}
From 99652876d090781916ce8af600e619ea63be0d86 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Sat, 17 Jul 2021 18:45:21 +0530
Subject: [PATCH 134/386] fix: Add test for additional discount applied on
taxes
---
.../sales_invoice/test_sales_invoice.py | 29 +++++++++++++++++++
1 file changed, 29 insertions(+)
diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
index 2ddfad9c31..1e2e92f609 100644
--- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
@@ -2001,6 +2001,35 @@ class TestSalesInvoice(unittest.TestCase):
check_gl_entries(self, si.name, expected_gle, nowdate())
+ def test_additional_discount_for_sales_invoice_with_discount_accounting_enabled(self):
+ from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import enable_discount_accounting
+
+ enable_discount_accounting()
+ additional_discount_account = create_account(account_name="Discount Account",
+ parent_account="Indirect Expenses - _TC", company="_Test Company")
+
+ si = create_sales_invoice(rate=75000, do_not_save=1)
+ si.apply_discount_on = "Grand Total"
+ si.additional_discount_account = additional_discount_account
+ si.additional_discount_percentage = 10
+ si.append("taxes", {
+ "charge_type": "On Net Total",
+ "account_head": "CGST - _TC",
+ "cost_center": "Main - _TC",
+ "description": "CGST @ 9.0",
+ "rate": 9
+ })
+ si.submit()
+
+ expected_gle = [
+ ["Sales - _TC", 0.0, 67500.0, nowdate()],
+ ["Discount Account - _TC", 675.0, 0.0, nowdate()],
+ ["CGST - _TC", 0.0, 6750.0, nowdate()],
+ ["Debtors - _TC", 73575.0, 0.0, nowdate()]
+ ]
+
+ check_gl_entries(self, si.name, expected_gle, nowdate())
+
def get_sales_invoice_for_e_invoice():
si = make_sales_invoice_for_ewaybill()
si.naming_series = 'INV-2020-.#####'
From 99cb89f449b6013457f538cd027b72556e18ebf8 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Sat, 17 Jul 2021 19:49:16 +0530
Subject: [PATCH 135/386] fix: Switch debit and credit for ledger entries for
discount applied on taxes for Purchase Invoice
---
erpnext/controllers/accounts_controller.py | 21 ++++++++++++++-------
1 file changed, 14 insertions(+), 7 deletions(-)
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index f4593c2a76..aa2fe29bc6 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -858,14 +858,22 @@ class AccountsController(TransactionBase):
if flt(tax.base_tax_amount_after_discount_amount) and flt(tax.base_tax_amount):
account_currency = get_account_currency(tax.account_head)
additional_discount_applied_on_taxes = flt(tax.base_tax_amount) - flt(tax.base_tax_amount_after_discount_amount)
+ if self.doctype == 'Purchase Invoice':
+ against = self.supplier
+ dr_or_cr = "debit"
+ rev_dr_cr = "credit"
+ else:
+ against = self.customer
+ dr_or_cr = "credit"
+ rev_dr_cr = "debit"
gl_entries.append(
self.get_gl_dict({
"account": tax.account_head,
- "against": self.customer,
- "credit": flt(additional_discount_applied_on_taxes,
+ "against": against,
+ dr_or_cr: flt(additional_discount_applied_on_taxes,
tax.precision("tax_amount_after_discount_amount")),
- "credit_in_account_currency": (flt(additional_discount_applied_on_taxes,
+ dr_or_cr + "_in_account_currency": (flt(additional_discount_applied_on_taxes,
tax.precision("base_tax_amount_after_discount_amount")) if account_currency==self.company_currency else
flt(additional_discount_applied_on_taxes, tax.precision("tax_amount_after_discount_amount"))),
"cost_center": tax.cost_center
@@ -875,17 +883,16 @@ class AccountsController(TransactionBase):
gl_entries.append(
self.get_gl_dict({
"account": self.additional_discount_account,
- "against": self.customer,
- "debit": flt(additional_discount_applied_on_taxes,
+ "against": against,
+ rev_dr_cr: flt(additional_discount_applied_on_taxes,
tax.precision("tax_amount_after_discount_amount")),
- "debit_in_account_currency": (flt(additional_discount_applied_on_taxes,
+ rev_dr_cr + "_in_account_currency": (flt(additional_discount_applied_on_taxes,
tax.precision("base_tax_amount_after_discount_amount")) if account_currency==self.company_currency else
flt(additional_discount_applied_on_taxes, tax.precision("tax_amount_after_discount_amount"))),
"cost_center": tax.cost_center
}, account_currency, item=tax)
)
-
def allocate_advance_taxes(self, gl_entries):
tax_map = self.get_tax_map()
for pe in self.get("advances"):
From 251f2296018a996737da6eadddcb650994b3f728 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Sat, 17 Jul 2021 19:49:42 +0530
Subject: [PATCH 136/386] fix: Add test for additional discount applied on
taxes
---
.../purchase_invoice/test_purchase_invoice.py | 29 +++++++++++++++++++
1 file changed, 29 insertions(+)
diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
index 36fbc7e351..4eb71f8e70 100644
--- a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
@@ -247,6 +247,35 @@ class TestPurchaseInvoice(unittest.TestCase):
check_gl_entries(self, pi.name, expected_gle, nowdate())
+ def test_additional_discount_for_purchase_invoice_with_discount_accounting_enabled(self):
+ from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import check_gl_entries
+
+ enable_discount_accounting()
+ additional_discount_account = create_account(account_name="Discount Account",
+ parent_account="Indirect Expenses - _TC", company="_Test Company")
+
+ pi = make_purchase_invoice(qty=1, rate=75000, do_not_save=1)
+ pi.apply_discount_on = "Grand Total"
+ pi.additional_discount_account = additional_discount_account
+ pi.additional_discount_percentage = 10
+ pi.append("taxes", {
+ "charge_type": "On Net Total",
+ "account_head": "CGST - _TC",
+ "cost_center": "Main - _TC",
+ "description": "CGST @ 9.0",
+ "rate": 9
+ })
+ pi.submit()
+
+ expected_gle = [
+ ["Discount Account - _TC", 0.0, 675.0, nowdate()],
+ ["CGST - _TC", 6750.0, 0.0, nowdate()],
+ ["_Test Account Cost for Goods Sold - _TC", 67500.0, 0.0, nowdate()],
+ ["Creditors - _TC", 0.0, 73575.0, nowdate()]
+ ]
+
+ check_gl_entries(self, pi.name, expected_gle, nowdate())
+
def test_purchase_invoice_change_naming_series(self):
pi = frappe.copy_doc(test_records[1])
pi.insert()
From b4a8bc8e4cbacb80e077b450195c1be346524387 Mon Sep 17 00:00:00 2001
From: Ganga Manoj
Date: Mon, 19 Jul 2021 23:43:36 +0530
Subject: [PATCH 137/386] fix: Use the item's cost centre instead of the
Invoice's
Co-authored-by: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com>
---
erpnext/controllers/accounts_controller.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index aa2fe29bc6..65dbe17ec1 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -836,7 +836,7 @@ class AccountsController(TransactionBase):
"against": supplier_or_customer,
dr_or_cr: flt(item.discount_amount),
dr_or_cr + "_in_account_currency": flt(item.discount_amount),
- "cost_center": self.cost_center,
+ "cost_center": item.cost_center,
"project": self.project
}, account_currency, item=self)
)
From e7e9bda1235f2b9d35b1f8a9d3b525a026bf4dd5 Mon Sep 17 00:00:00 2001
From: Ganga Manoj
Date: Mon, 19 Jul 2021 23:44:21 +0530
Subject: [PATCH 138/386] fix: Use the item's project instead of the invoice's
Co-authored-by: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com>
---
erpnext/controllers/accounts_controller.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index 65dbe17ec1..2aac4968a2 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -837,7 +837,7 @@ class AccountsController(TransactionBase):
dr_or_cr: flt(item.discount_amount),
dr_or_cr + "_in_account_currency": flt(item.discount_amount),
"cost_center": item.cost_center,
- "project": self.project
+ "project": item.project
}, account_currency, item=self)
)
From f421dc7ca74f97794c8eca5bf52fcfabef178cfe Mon Sep 17 00:00:00 2001
From: Ganga Manoj
Date: Mon, 19 Jul 2021 23:44:55 +0530
Subject: [PATCH 139/386] fix: GL Entry creation
Co-authored-by: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com>
---
erpnext/controllers/accounts_controller.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index 2aac4968a2..9b3336cde5 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -838,7 +838,7 @@ class AccountsController(TransactionBase):
dr_or_cr + "_in_account_currency": flt(item.discount_amount),
"cost_center": item.cost_center,
"project": item.project
- }, account_currency, item=self)
+ }, account_currency, item=item)
)
account_currency = get_account_currency(income_or_expense_account)
From 821b75f1b119b5ef9be2278889882db3b73af33c Mon Sep 17 00:00:00 2001
From: Ganga Manoj
Date: Mon, 19 Jul 2021 23:46:38 +0530
Subject: [PATCH 140/386] fix: Filter for additional_discount_account
Co-authored-by: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com>
---
erpnext/accounts/doctype/sales_invoice/sales_invoice.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
index a5341df2e3..0256227886 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
@@ -596,7 +596,7 @@ frappe.ui.form.on('Sales Invoice', {
filters: {
company: frm.doc.company,
is_group: 0,
- root_type: "Profit and Loss",
+ report_type: "Profit and Loss",
}
};
});
From ed6ebdf5ed297352ac7120bb910662d8c4a41183 Mon Sep 17 00:00:00 2001
From: Ganga Manoj
Date: Mon, 19 Jul 2021 23:47:58 +0530
Subject: [PATCH 141/386] fix: Filter for additional_discount_account
Co-authored-by: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com>
---
erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
index 4ed31cc227..bf78c028c8 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
@@ -504,7 +504,7 @@ frappe.ui.form.on("Purchase Invoice", {
filters: {
company: frm.doc.company,
is_group: 0,
- root_type: "Profit and Loss",
+ report_type: "Profit and Loss",
}
};
});
From 566e8f849903644cad157fb8ae9a790d304e84e4 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Tue, 20 Jul 2021 03:46:02 +0530
Subject: [PATCH 142/386] fix: Create GL Entries for Additional Discount
Account
---
.../purchase_invoice/purchase_invoice.py | 11 ++--
.../doctype/sales_invoice/sales_invoice.py | 31 +++++++---
erpnext/controllers/accounts_controller.py | 60 ++++++-------------
3 files changed, 45 insertions(+), 57 deletions(-)
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
index 006f5bb0e8..feae213d92 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
@@ -609,7 +609,11 @@ class PurchaseInvoice(BuyingController):
if (not item.enable_deferred_expense or self.is_return) else item.deferred_expense_account)
if not item.is_fixed_asset:
- amount = flt(item.base_net_amount, item.precision("base_net_amount"))
+ if frappe.db.get_single_value('Accounts Settings', 'enable_discount_accounting'):
+ amount = flt(item.base_amount, item.precision("base_amount"))
+ else:
+ amount = flt(item.base_net_amount, item.precision("base_net_amount"))
+
else:
amount = flt(item.base_net_amount + item.item_tax_amount, item.precision("base_net_amount"))
@@ -888,11 +892,6 @@ class PurchaseInvoice(BuyingController):
"remarks": self.remarks or "Accounting Entry for Stock"
}, item=tax))
- enable_discount_accounting = cint(frappe.db.get_single_value('Accounts Settings', 'enable_discount_accounting'))
-
- if enable_discount_accounting and self.get('discount_amount') and self.get('additional_discount_account'):
- self.make_gle_for_additional_discount_applied_on_taxes(gl_entries)
-
def make_internal_transfer_gl_entries(self, gl_entries):
if self.is_internal_transfer() and flt(self.base_total_taxes_and_charges):
account_currency = get_account_currency(self.unrealized_profit_loss_account)
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index ee9b59e769..52c2a9c42c 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -902,11 +902,6 @@ class SalesInvoice(SellingController):
}, account_currency, item=tax)
)
- enable_discount_accounting = cint(frappe.db.get_single_value('Accounts Settings', 'enable_discount_accounting'))
-
- if enable_discount_accounting and self.get('discount_amount') and self.get('additional_discount_account'):
- self.make_gle_for_additional_discount_applied_on_taxes(gl_entries)
-
def make_internal_transfer_gl_entries(self, gl_entries):
if self.is_internal_transfer() and flt(self.base_total_taxes_and_charges):
account_currency = get_account_currency(self.unrealized_profit_loss_account)
@@ -946,15 +941,17 @@ class SalesInvoice(SellingController):
income_account = (item.income_account
if (not item.enable_deferred_revenue or self.is_return) else item.deferred_revenue_account)
+ amount, base_amount = self.get_amount_and_base_amount(item)
+
account_currency = get_account_currency(income_account)
gl_entries.append(
self.get_gl_dict({
"account": income_account,
"against": self.customer,
- "credit": flt(item.base_net_amount, item.precision("base_net_amount")),
- "credit_in_account_currency": (flt(item.base_net_amount, item.precision("base_net_amount"))
+ "credit": flt(base_amount, item.precision("base_net_amount")),
+ "credit_in_account_currency": (flt(base_amount, item.precision("base_net_amount"))
if account_currency==self.company_currency
- else flt(item.net_amount, item.precision("net_amount"))),
+ else flt(amount, item.precision("net_amount"))),
"cost_center": item.cost_center,
"project": item.project or self.project
}, account_currency, item=item)
@@ -965,6 +962,24 @@ class SalesInvoice(SellingController):
erpnext.is_perpetual_inventory_enabled(self.company):
gl_entries += super(SalesInvoice, self).get_gl_entries()
+ def get_amount_and_base_amount(self, item):
+ amount = item.net_amount
+ base_amount = item.base_net_amount
+
+ enable_discount_accounting = cint(frappe.db.get_single_value('Accounts Settings', 'enable_discount_accounting'))
+
+ if enable_discount_accounting and self.get('discount_amount') and self.get('additional_discount_account'):
+ amount = item.amount
+ base_amount = item.base_amount
+
+ return amount, base_amount
+
+ def set_asset_status(self, asset):
+ if self.is_return:
+ asset.set_status()
+ else:
+ asset.set_status("Sold" if self.docstatus==1 else None)
+
def make_loyalty_point_redemption_gle(self, gl_entries):
if cint(self.redeem_loyalty_points):
gl_entries.append(
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index 9b3336cde5..59879e0df5 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -812,19 +812,23 @@ class AccountsController(TransactionBase):
enable_discount_accounting = cint(frappe.db.get_single_value('Accounts Settings', 'enable_discount_accounting'))
if enable_discount_accounting:
+ if self.doctype == "Purchase Invoice":
+ dr_or_cr = "credit"
+ rev_dr_cr = "debit"
+ supplier_or_customer = self.supplier
+
+ else:
+ dr_or_cr = "debit"
+ rev_dr_cr = "credit"
+ supplier_or_customer = self.customer
+
for item in self.get("items"):
if item.get('discount_amount') and item.get('discount_account'):
if self.doctype == "Purchase Invoice":
- dr_or_cr = "credit"
- rev_dr_cr = "debit"
- supplier_or_customer = self.supplier
income_or_expense_account = (item.expense_account
if (not item.enable_deferred_expense or self.is_return)
else item.deferred_expense_account)
else:
- dr_or_cr = "debit"
- rev_dr_cr = "credit"
- supplier_or_customer = self.customer
income_or_expense_account = (item.income_account
if (not item.enable_deferred_revenue or self.is_return)
else item.deferred_revenue_account)
@@ -853,46 +857,16 @@ class AccountsController(TransactionBase):
}, account_currency, item=item)
)
- def make_gle_for_additional_discount_applied_on_taxes(self, gl_entries):
- for tax in self.get("taxes"):
- if flt(tax.base_tax_amount_after_discount_amount) and flt(tax.base_tax_amount):
- account_currency = get_account_currency(tax.account_head)
- additional_discount_applied_on_taxes = flt(tax.base_tax_amount) - flt(tax.base_tax_amount_after_discount_amount)
- if self.doctype == 'Purchase Invoice':
- against = self.supplier
- dr_or_cr = "debit"
- rev_dr_cr = "credit"
- else:
- against = self.customer
- dr_or_cr = "credit"
- rev_dr_cr = "debit"
-
- gl_entries.append(
- self.get_gl_dict({
- "account": tax.account_head,
- "against": against,
- dr_or_cr: flt(additional_discount_applied_on_taxes,
- tax.precision("tax_amount_after_discount_amount")),
- dr_or_cr + "_in_account_currency": (flt(additional_discount_applied_on_taxes,
- tax.precision("base_tax_amount_after_discount_amount")) if account_currency==self.company_currency else
- flt(additional_discount_applied_on_taxes, tax.precision("tax_amount_after_discount_amount"))),
- "cost_center": tax.cost_center
- }, account_currency, item=tax)
- )
-
+ if self.get('discount_amount') and self.get('additional_discount_account'):
gl_entries.append(
self.get_gl_dict({
"account": self.additional_discount_account,
- "against": against,
- rev_dr_cr: flt(additional_discount_applied_on_taxes,
- tax.precision("tax_amount_after_discount_amount")),
- rev_dr_cr + "_in_account_currency": (flt(additional_discount_applied_on_taxes,
- tax.precision("base_tax_amount_after_discount_amount")) if account_currency==self.company_currency else
- flt(additional_discount_applied_on_taxes, tax.precision("tax_amount_after_discount_amount"))),
- "cost_center": tax.cost_center
- }, account_currency, item=tax)
- )
-
+ "against": supplier_or_customer,
+ dr_or_cr: self.discount_amount,
+ "cost_center": self.cost_center
+ }, item=self)
+ )
+
def allocate_advance_taxes(self, gl_entries):
tax_map = self.get_tax_map()
for pe in self.get("advances"):
From 1f6c05f0139a8ad9f1d22c4c35552e51e767180f Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Tue, 20 Jul 2021 03:52:39 +0530
Subject: [PATCH 143/386] fix: Make discount_account mandatory if discount
accounting is enabled
---
erpnext/accounts/doctype/accounts_settings/accounts_settings.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/erpnext/accounts/doctype/accounts_settings/accounts_settings.py b/erpnext/accounts/doctype/accounts_settings/accounts_settings.py
index 24b0ec4d4a..a3a32d5e97 100644
--- a/erpnext/accounts/doctype/accounts_settings/accounts_settings.py
+++ b/erpnext/accounts/doctype/accounts_settings/accounts_settings.py
@@ -40,6 +40,7 @@ class AccountsSettings(Document):
for doctype in ["Sales Invoice Item", "Purchase Invoice Item"]:
make_property_setter(doctype, "discount_account", "hidden", not(enable_discount_accounting), "Check", validate_fields_for_doctype=False)
+ make_property_setter(doctype, "discount_account", "mandatory", enable_discount_accounting, "Check", validate_fields_for_doctype=False)
for doctype in ["Sales Invoice", "Purchase Invoice"]:
make_property_setter(doctype, "additional_discount_account", "hidden", not(enable_discount_accounting), "Check", validate_fields_for_doctype=False)
From 45327e04db1a35f439e874e2e5175c87683af959 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Tue, 20 Jul 2021 05:16:33 +0530
Subject: [PATCH 144/386] fix: Tests
---
.../purchase_invoice/test_purchase_invoice.py | 43 +++++++++++++------
.../sales_invoice/test_sales_invoice.py | 25 +++++------
2 files changed, 43 insertions(+), 25 deletions(-)
diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
index 4eb71f8e70..0487ef6444 100644
--- a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
@@ -231,8 +231,6 @@ class TestPurchaseInvoice(unittest.TestCase):
self.assertEqual(expected_values[gle.account][2], gle.credit)
def test_purchase_invoice_with_discount_accounting_enabled(self):
- from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import check_gl_entries
-
enable_discount_accounting()
discount_account = create_account(account_name="Discount Account",
@@ -240,38 +238,45 @@ class TestPurchaseInvoice(unittest.TestCase):
pi = make_purchase_invoice(discount_account=discount_account, discount_amount=100)
expected_gle = [
- ["Discount Account - _TC", 0.0, 100.0, nowdate()],
["_Test Account Cost for Goods Sold - _TC", 350.0, 0.0, nowdate()],
- ["Creditors - _TC", 0.0, 250.0, nowdate()]
+ ["Creditors - _TC", 0.0, 250.0, nowdate()],
+ ["Discount Account - _TC", 0.0, 100.0, nowdate()]
]
check_gl_entries(self, pi.name, expected_gle, nowdate())
def test_additional_discount_for_purchase_invoice_with_discount_accounting_enabled(self):
- from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import check_gl_entries
-
enable_discount_accounting()
additional_discount_account = create_account(account_name="Discount Account",
parent_account="Indirect Expenses - _TC", company="_Test Company")
- pi = make_purchase_invoice(qty=1, rate=75000, do_not_save=1)
+ pi = make_purchase_invoice(qty=1, rate=100, do_not_save=1)
pi.apply_discount_on = "Grand Total"
pi.additional_discount_account = additional_discount_account
- pi.additional_discount_percentage = 10
+ pi.additional_discount_percentage = 20
pi.append("taxes", {
"charge_type": "On Net Total",
"account_head": "CGST - _TC",
"cost_center": "Main - _TC",
"description": "CGST @ 9.0",
- "rate": 9
+ "base_tax_amount": 20,
+ "base_tax_amount_after_discount_amount": 20
})
pi.submit()
+ # gle = frappe.get_all(
+ # "GL Entry",
+ # fields = ['account', 'debit', 'credit', 'posting_date'],
+ # filters = {'voucher_no': pi.name}
+ # )
+ # for gl in gle:
+ # print(gl, "\n")
+
expected_gle = [
- ["Discount Account - _TC", 0.0, 675.0, nowdate()],
- ["CGST - _TC", 6750.0, 0.0, nowdate()],
- ["_Test Account Cost for Goods Sold - _TC", 67500.0, 0.0, nowdate()],
- ["Creditors - _TC", 0.0, 73575.0, nowdate()]
+ ["CGST - _TC", 20.0, 0.0, nowdate()],
+ ["Creditors - _TC", 0.0, 96.0, nowdate()],
+ ["Discount Account - _TC", 0.0, 24.0, nowdate()],
+ ["_Test Account Cost for Goods Sold - _TC", 100.0, 0.0, nowdate()]
]
check_gl_entries(self, pi.name, expected_gle, nowdate())
@@ -1186,6 +1191,18 @@ class TestPurchaseInvoice(unittest.TestCase):
self.assertEqual(expected_gle[i][0], gle.account)
self.assertEqual(expected_gle[i][1], gle.amount)
+def check_gl_entries(doc, voucher_no, expected_gle, posting_date):
+ gl_entries = frappe.db.sql("""select account, debit, credit, posting_date
+ from `tabGL Entry`
+ where voucher_type='Purchase Invoice' and voucher_no=%s and posting_date >= %s
+ order by posting_date asc, account asc""", (voucher_no, posting_date), as_dict=1)
+
+ for i, gle in enumerate(gl_entries):
+ doc.assertEqual(expected_gle[i][0], gle.account)
+ doc.assertEqual(expected_gle[i][1], gle.debit)
+ doc.assertEqual(expected_gle[i][2], gle.credit)
+ doc.assertEqual(getdate(expected_gle[i][3]), gle.posting_date)
+
def update_tax_witholding_category(company, account, date):
from erpnext.accounts.utils import get_fiscal_year
diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
index 1e2e92f609..9f7d18bdb4 100644
--- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
@@ -1994,12 +1994,12 @@ class TestSalesInvoice(unittest.TestCase):
si = create_sales_invoice(discount_account=discount_account, discount_amount=100)
expected_gle = [
+ ["Debtors - _TC", 100.0, 0.0, nowdate()],
["Discount Account - _TC", 100.0, 0.0, nowdate()],
- ["Sales - _TC", 0.0, 200.0, nowdate()],
- ["Debtors - _TC", 100.0, 0.0, nowdate()]
+ ["Sales - _TC", 0.0, 200.0, nowdate()]
]
- check_gl_entries(self, si.name, expected_gle, nowdate())
+ check_gl_entries(self, si.name, expected_gle, add_days(nowdate(), -1))
def test_additional_discount_for_sales_invoice_with_discount_accounting_enabled(self):
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import enable_discount_accounting
@@ -2008,27 +2008,28 @@ class TestSalesInvoice(unittest.TestCase):
additional_discount_account = create_account(account_name="Discount Account",
parent_account="Indirect Expenses - _TC", company="_Test Company")
- si = create_sales_invoice(rate=75000, do_not_save=1)
+ si = create_sales_invoice(rate=100, do_not_save=1)
si.apply_discount_on = "Grand Total"
si.additional_discount_account = additional_discount_account
- si.additional_discount_percentage = 10
+ si.additional_discount_percentage = 20
si.append("taxes", {
- "charge_type": "On Net Total",
+ "charge_type": "Actual",
"account_head": "CGST - _TC",
"cost_center": "Main - _TC",
"description": "CGST @ 9.0",
- "rate": 9
+ "rate": 0,
+ "tax_amount": 20
})
si.submit()
expected_gle = [
- ["Sales - _TC", 0.0, 67500.0, nowdate()],
- ["Discount Account - _TC", 675.0, 0.0, nowdate()],
- ["CGST - _TC", 0.0, 6750.0, nowdate()],
- ["Debtors - _TC", 73575.0, 0.0, nowdate()]
+ ["CGST - _TC", 0.0, 20.0, nowdate()],
+ ["Debtors - _TC", 96.0, 0.0, nowdate()],
+ ["Discount Account - _TC", 24.0, 0.0, nowdate()],
+ ["Sales - _TC", 0.0, 100.0, nowdate()]
]
- check_gl_entries(self, si.name, expected_gle, nowdate())
+ check_gl_entries(self, si.name, expected_gle, add_days(nowdate(), -1))
def get_sales_invoice_for_e_invoice():
si = make_sales_invoice_for_ewaybill()
From 4fa409e0194fde280647b31c96a404099cf99eb1 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Tue, 20 Jul 2021 22:03:44 +0530
Subject: [PATCH 145/386] fix: Add mandatory_depends_on property for Discount
Account
---
.../doctype/accounts_settings/accounts_settings.py | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/erpnext/accounts/doctype/accounts_settings/accounts_settings.py b/erpnext/accounts/doctype/accounts_settings/accounts_settings.py
index a3a32d5e97..5544913292 100644
--- a/erpnext/accounts/doctype/accounts_settings/accounts_settings.py
+++ b/erpnext/accounts/doctype/accounts_settings/accounts_settings.py
@@ -40,9 +40,16 @@ class AccountsSettings(Document):
for doctype in ["Sales Invoice Item", "Purchase Invoice Item"]:
make_property_setter(doctype, "discount_account", "hidden", not(enable_discount_accounting), "Check", validate_fields_for_doctype=False)
- make_property_setter(doctype, "discount_account", "mandatory", enable_discount_accounting, "Check", validate_fields_for_doctype=False)
+ if enable_discount_accounting:
+ make_property_setter(doctype, "discount_account", "mandatory_depends_on", "eval: doc.discount_amount", "Code", validate_fields_for_doctype=False)
+ else:
+ make_property_setter(doctype, "discount_account", "mandatory_depends_on", "", "Code", validate_fields_for_doctype=False)
for doctype in ["Sales Invoice", "Purchase Invoice"]:
make_property_setter(doctype, "additional_discount_account", "hidden", not(enable_discount_accounting), "Check", validate_fields_for_doctype=False)
+ if enable_discount_accounting:
+ make_property_setter(doctype, "additional_discount_account", "mandatory_depends_on", "eval: doc.discount_amount", "Code", validate_fields_for_doctype=False)
+ else:
+ make_property_setter(doctype, "additional_discount_account", "mandatory_depends_on", "", "Code", validate_fields_for_doctype=False)
make_property_setter("Item", "default_discount_account", "hidden", not(enable_discount_accounting), "Check", validate_fields_for_doctype=False)
\ No newline at end of file
From fc09d845c5b38dd60783dfd287a71f7ab0dcbad9 Mon Sep 17 00:00:00 2001
From: Deepesh Garg
Date: Wed, 21 Jul 2021 15:25:09 +0530
Subject: [PATCH 146/386] fix: Syntax Error
---
erpnext/accounts/doctype/sales_invoice/sales_invoice.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
index 0256227886..56f11650ff 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
@@ -348,7 +348,7 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
items_add: function(doc, cdt, cdn) {
var row = frappe.get_doc(cdt, cdn);
this.frm.script_manager.copy_from_first_row("items", row, ["income_account", "discount_account", "cost_center"]);
- }
+ },
set_dynamic_labels: function() {
this._super();
From 5a06019440f80b2c3719f195cdf5619d3715b759 Mon Sep 17 00:00:00 2001
From: Deepesh Garg
Date: Wed, 21 Jul 2021 15:25:40 +0530
Subject: [PATCH 147/386] fix: GL For taxes if discount applied on Grand Total
---
.../doctype/sales_invoice/sales_invoice.py | 26 +++++++------------
erpnext/controllers/accounts_controller.py | 21 +++++++++++++++
2 files changed, 31 insertions(+), 16 deletions(-)
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index 52c2a9c42c..2539de7b12 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -886,18 +886,22 @@ class SalesInvoice(SellingController):
)
def make_tax_gl_entries(self, gl_entries):
+ enable_discount_accounting = cint(frappe.db.get_single_value('Accounts Settings', 'enable_discount_accounting'))
+
for tax in self.get("taxes"):
+ amount, base_amount = self.get_tax_amounts(tax, enable_discount_accounting)
+
if flt(tax.base_tax_amount_after_discount_amount):
account_currency = get_account_currency(tax.account_head)
gl_entries.append(
self.get_gl_dict({
"account": tax.account_head,
"against": self.customer,
- "credit": flt(tax.base_tax_amount_after_discount_amount,
+ "credit": flt(base_amount,
tax.precision("tax_amount_after_discount_amount")),
- "credit_in_account_currency": (flt(tax.base_tax_amount_after_discount_amount,
+ "credit_in_account_currency": (flt(base_amount,
tax.precision("base_tax_amount_after_discount_amount")) if account_currency==self.company_currency else
- flt(tax.tax_amount_after_discount_amount, tax.precision("tax_amount_after_discount_amount"))),
+ flt(amount, tax.precision("tax_amount_after_discount_amount"))),
"cost_center": tax.cost_center
}, account_currency, item=tax)
)
@@ -916,6 +920,8 @@ class SalesInvoice(SellingController):
def make_item_gl_entries(self, gl_entries):
# income account gl entries
+ enable_discount_accounting = cint(frappe.db.get_single_value('Accounts Settings', 'enable_discount_accounting'))
+
for item in self.get("items"):
if flt(item.base_net_amount, item.precision("base_net_amount")):
if item.is_fixed_asset:
@@ -941,7 +947,7 @@ class SalesInvoice(SellingController):
income_account = (item.income_account
if (not item.enable_deferred_revenue or self.is_return) else item.deferred_revenue_account)
- amount, base_amount = self.get_amount_and_base_amount(item)
+ amount, base_amount = self.get_amount_and_base_amount(item, enable_discount_accounting)
account_currency = get_account_currency(income_account)
gl_entries.append(
@@ -962,18 +968,6 @@ class SalesInvoice(SellingController):
erpnext.is_perpetual_inventory_enabled(self.company):
gl_entries += super(SalesInvoice, self).get_gl_entries()
- def get_amount_and_base_amount(self, item):
- amount = item.net_amount
- base_amount = item.base_net_amount
-
- enable_discount_accounting = cint(frappe.db.get_single_value('Accounts Settings', 'enable_discount_accounting'))
-
- if enable_discount_accounting and self.get('discount_amount') and self.get('additional_discount_account'):
- amount = item.amount
- base_amount = item.base_amount
-
- return amount, base_amount
-
def set_asset_status(self, asset):
if self.is_return:
asset.set_status()
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index 59879e0df5..3d048c3686 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -808,6 +808,27 @@ class AccountsController(TransactionBase):
tax_map[tax.account_head] -= allocated_amount
allocated_tax_map[tax.account_head] -= allocated_amount
+ def get_amount_and_base_amount(self, item, enable_discount_accounting):
+ amount = item.net_amount
+ base_amount = item.base_net_amount
+
+ if enable_discount_accounting and self.get('discount_amount') and self.get('additional_discount_account'):
+ amount = item.amount
+ base_amount = item.base_amount
+
+ return amount, base_amount
+
+ def get_tax_amounts(self, tax, enable_discount_accounting):
+ amount = tax.tax_amount_after_discount_amount
+ base_amount = tax.base_tax_amount_after_discount_amount
+
+ if enable_discount_accounting and self.get('discount_amount') and self.get('additional_discount_account') \
+ and self.get('apply_discount_on') == 'Grand Total':
+ amount = tax.tax_amount
+ base_amount = tax.base_tax_amount
+
+ return amount, base_amount
+
def make_discount_gl_entries(self, gl_entries):
enable_discount_accounting = cint(frappe.db.get_single_value('Accounts Settings', 'enable_discount_accounting'))
From c765073c2a56688835b04d72fc335f654e2ef86a Mon Sep 17 00:00:00 2001
From: Deepesh Garg
Date: Wed, 21 Jul 2021 22:28:32 +0530
Subject: [PATCH 148/386] fix: Tests
---
.../purchase_invoice/test_purchase_invoice.py | 20 +++++++++----------
.../sales_invoice/test_sales_invoice.py | 9 +++++----
2 files changed, 15 insertions(+), 14 deletions(-)
diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
index 0487ef6444..e20e385f63 100644
--- a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
@@ -250,17 +250,16 @@ class TestPurchaseInvoice(unittest.TestCase):
additional_discount_account = create_account(account_name="Discount Account",
parent_account="Indirect Expenses - _TC", company="_Test Company")
- pi = make_purchase_invoice(qty=1, rate=100, do_not_save=1)
+ pi = make_purchase_invoice(qty=1, rate=100, do_not_save=1, parent_cost_center="Main - _TC")
pi.apply_discount_on = "Grand Total"
pi.additional_discount_account = additional_discount_account
pi.additional_discount_percentage = 20
pi.append("taxes", {
- "charge_type": "On Net Total",
- "account_head": "CGST - _TC",
+ "charge_type": "Actual",
+ "account_head": "_Test Account VAT - _TC",
"cost_center": "Main - _TC",
- "description": "CGST @ 9.0",
- "base_tax_amount": 20,
- "base_tax_amount_after_discount_amount": 20
+ "description": "Test",
+ "tax_amount": 20
})
pi.submit()
@@ -273,10 +272,10 @@ class TestPurchaseInvoice(unittest.TestCase):
# print(gl, "\n")
expected_gle = [
- ["CGST - _TC", 20.0, 0.0, nowdate()],
+ ["_Test Account Cost for Goods Sold - _TC", 100.0, 0.0, nowdate()],
+ ["_Test Account VAT - _TC", 20.0, 0.0, nowdate()],
["Creditors - _TC", 0.0, 96.0, nowdate()],
- ["Discount Account - _TC", 0.0, 24.0, nowdate()],
- ["_Test Account Cost for Goods Sold - _TC", 100.0, 0.0, nowdate()]
+ ["Discount Account - _TC", 0.0, 24.0, nowdate()]
]
check_gl_entries(self, pi.name, expected_gle, nowdate())
@@ -1197,6 +1196,7 @@ def check_gl_entries(doc, voucher_no, expected_gle, posting_date):
where voucher_type='Purchase Invoice' and voucher_no=%s and posting_date >= %s
order by posting_date asc, account asc""", (voucher_no, posting_date), as_dict=1)
+ print(gl_entries)
for i, gle in enumerate(gl_entries):
doc.assertEqual(expected_gle[i][0], gle.account)
doc.assertEqual(expected_gle[i][1], gle.debit)
@@ -1260,7 +1260,7 @@ def make_purchase_invoice(**args):
pi.return_against = args.return_against
pi.is_subcontracted = args.is_subcontracted or "No"
pi.supplier_warehouse = args.supplier_warehouse or "_Test Warehouse 1 - _TC"
- pi.cost_center = args.cost_center or "_Test Cost Center - _TC"
+ pi.cost_center = args.parent_cost_center
pi.append("items", {
"item_code": args.item or args.item_code or "_Test Item",
diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
index 9f7d18bdb4..1c0177d3d0 100644
--- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
@@ -2014,16 +2014,17 @@ class TestSalesInvoice(unittest.TestCase):
si.additional_discount_percentage = 20
si.append("taxes", {
"charge_type": "Actual",
- "account_head": "CGST - _TC",
+ "account_head": "_Test Account VAT - _TC",
"cost_center": "Main - _TC",
- "description": "CGST @ 9.0",
+ "parent_cost_center": "Main - _TC",
+ "description": "Test",
"rate": 0,
"tax_amount": 20
})
si.submit()
expected_gle = [
- ["CGST - _TC", 0.0, 20.0, nowdate()],
+ ["_Test Account VAT - _TC", 0.0, 20.0, nowdate()],
["Debtors - _TC", 96.0, 0.0, nowdate()],
["Discount Account - _TC", 24.0, 0.0, nowdate()],
["Sales - _TC", 0.0, 100.0, nowdate()]
@@ -2199,7 +2200,7 @@ def create_sales_invoice(**args):
si.currency=args.currency or "INR"
si.conversion_rate = args.conversion_rate or 1
si.naming_series = args.naming_series or "T-SINV-"
- si.cost_center = args.cost_center or "_Test Cost Center - _TC"
+ si.cost_center = args.parent_cost_center
si.append("items", {
"item_code": args.item or args.item_code or "_Test Item",
From 117676175728e3f34edbfea9b989da26ba9a6e84 Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Wed, 21 Jul 2021 23:19:47 +0530
Subject: [PATCH 149/386] feat: Expand All nodes option in Desktop view
---
.../hierarchy_chart_desktop.js | 152 +++++++++++++++---
erpnext/public/scss/hierarchy_chart.scss | 1 +
erpnext/utilities/hierarchy_chart.py | 29 ++++
3 files changed, 159 insertions(+), 23 deletions(-)
create mode 100644 erpnext/utilities/hierarchy_chart.py
diff --git a/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js b/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
index fe4d17c210..694c26567a 100644
--- a/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
+++ b/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
@@ -36,7 +36,11 @@ erpnext.HierarchyChart = class {
me.nodes[this.id] = this;
me.make_node_element(this);
- me.setup_node_click_action(this);
+
+ if (!me.all_nodes_expanded) {
+ me.setup_node_click_action(this);
+ }
+
me.setup_edit_node_action(this);
}
};
@@ -60,8 +64,9 @@ erpnext.HierarchyChart = class {
show() {
frappe.breadcrumbs.add('HR');
- let me = this;
+ this.setup_actions();
if ($(`[data-fieldname="company"]`).length) return;
+ let me = this;
let company = this.page.add_field({
fieldtype: 'Link',
@@ -79,20 +84,9 @@ erpnext.HierarchyChart = class {
// svg for connectors
me.make_svg_markers();
-
- if (me.$hierarchy)
- me.$hierarchy.remove();
-
- // setup hierarchy
- me.$hierarchy = $(
- ``);
-
- me.page.main.append(me.$hierarchy);
+ me.setup_hierarchy()
me.render_root_nodes();
+ me.all_nodes_expanded = false;
}
}
});
@@ -101,6 +95,42 @@ erpnext.HierarchyChart = class {
$(`[data-fieldname="company"]`).trigger('change');
}
+ setup_actions() {
+ let me = this;
+ this.page.add_inner_button(__('Expand All'), function() {
+ me.load_children(me.root_node, true);
+ me.all_nodes_expanded = true;
+
+ me.page.remove_inner_button(__('Expand All'));
+ me.page.add_inner_button(__('Collapse All'), function() {
+ me.setup_hierarchy();
+ me.render_root_nodes();
+ me.all_nodes_expanded = false;
+
+ me.page.remove_inner_button(__('Collapse All'));
+ me.setup_actions();
+ });
+ });
+ }
+
+ setup_hierarchy() {
+ if (this.$hierarchy)
+ this.$hierarchy.remove();
+
+ $(`#connectors`).empty();
+
+ // setup hierarchy
+ this.$hierarchy = $(
+ ``);
+
+ this.page.main.append(this.$hierarchy);
+ this.nodes = {};
+ }
+
make_svg_markers() {
$('#arrows').remove();
@@ -126,7 +156,7 @@ erpnext.HierarchyChart = class {
`);
}
- render_root_nodes() {
+ render_root_nodes(expanded_view=false) {
let me = this;
frappe.call({
@@ -156,7 +186,10 @@ erpnext.HierarchyChart = class {
expand_node = node;
});
- me.expand_node(expand_node);
+ if (!expanded_view) {
+ me.root_node = expand_node;
+ me.expand_node(expand_node);
+ }
}
});
}
@@ -196,11 +229,20 @@ erpnext.HierarchyChart = class {
$(`#${node.parent_id}`).addClass('active-path');
}
- load_children(node) {
- frappe.run_serially([
- () => this.get_child_nodes(node.id),
- (child_nodes) => this.render_child_nodes(node, child_nodes)
- ]);
+ load_children(node, deep=false) {
+ if (!deep) {
+ frappe.run_serially([
+ () => this.get_child_nodes(node.id),
+ (child_nodes) => this.render_child_nodes(node, child_nodes)
+ ]);
+ } else {
+ frappe.run_serially([
+ () => this.setup_hierarchy(),
+ () => this.render_root_nodes(true),
+ () => this.get_all_nodes(node.id, node.name),
+ (data_list) => this.render_children_of_all_nodes(data_list)
+ ]);
+ }
}
get_child_nodes(node_id) {
@@ -247,6 +289,70 @@ erpnext.HierarchyChart = class {
node.expanded = true;
}
+ get_all_nodes(node_id, node_name) {
+ return new Promise(resolve => {
+ frappe.call({
+ method: 'erpnext.utilities.hierarchy_chart.get_all_nodes',
+ args: {
+ method: this.method,
+ company: this.company,
+ parent: node_id,
+ parent_name: node_name
+ },
+ callback: (r) => {
+ resolve(r.message);
+ }
+ });
+ });
+ }
+
+ render_children_of_all_nodes(data_list) {
+ let entry = undefined;
+ let node = undefined;
+
+ while(data_list.length) {
+ // to avoid overlapping connectors
+ entry = data_list.shift();
+ node = this.nodes[entry.parent];
+ if (node) {
+ this.render_child_nodes_for_expanded_view(node, entry.data);
+ } else {
+ data_list.push(entry);
+ }
+ }
+ }
+
+ render_child_nodes_for_expanded_view(node, child_nodes) {
+ node.$children = $('')
+
+ const last_level = this.$hierarchy.find('.level:last').index();
+ const node_level = $(`#${node.id}`).parent().parent().parent().index();
+
+ if (last_level === node_level) {
+ this.$hierarchy.append(`
+
+ `);
+ node.$children.appendTo(this.$hierarchy.find('.level:last'));
+ } else {
+ node.$children.appendTo(this.$hierarchy.find('.level:eq(' + (node_level + 1) + ')'));
+ }
+
+ node.$children.hide().empty();
+
+ if (child_nodes) {
+ $.each(child_nodes, (_i, data) => {
+ this.add_node(node, data);
+ setTimeout(() => {
+ this.add_connector(node.id, data.id);
+ }, 250);
+ });
+ }
+
+ node.$children.show();
+ $(`path[data-parent="${node.id}"]`).show();
+ node.expanded = true;
+ }
+
add_node(node, data) {
return new this.Node({
id: data.id,
@@ -333,7 +439,7 @@ erpnext.HierarchyChart = class {
path.setAttribute("class", "active-connector");
path.setAttribute("marker-start", "url(#arrowstart-active)");
path.setAttribute("marker-end", "url(#arrowhead-active)");
- } else if (parent.hasClass('active-path')) {
+ } else {
path.setAttribute("class", "collapsed-connector");
path.setAttribute("marker-start", "url(#arrowstart-collapsed)");
path.setAttribute("marker-end", "url(#arrowhead-collapsed)");
diff --git a/erpnext/public/scss/hierarchy_chart.scss b/erpnext/public/scss/hierarchy_chart.scss
index dd523c3443..1c2f9421fa 100644
--- a/erpnext/public/scss/hierarchy_chart.scss
+++ b/erpnext/public/scss/hierarchy_chart.scss
@@ -194,6 +194,7 @@
.level {
margin-right: 8px;
align-items: flex-start;
+ flex-direction: column;
}
#arrows {
diff --git a/erpnext/utilities/hierarchy_chart.py b/erpnext/utilities/hierarchy_chart.py
new file mode 100644
index 0000000000..9b0279351f
--- /dev/null
+++ b/erpnext/utilities/hierarchy_chart.py
@@ -0,0 +1,29 @@
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
+# MIT License. See license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe import _
+
+@frappe.whitelist()
+def get_all_nodes(parent, parent_name, method, company):
+ '''Recursively gets all data from nodes'''
+ method = frappe.get_attr(method)
+
+ if not method in frappe.whitelisted:
+ frappe.throw(_('Not Permitted'), frappe.PermissionError)
+
+ data = method(parent, company)
+ result = [dict(parent=parent, parent_name=parent_name, data=data)]
+
+ nodes_to_expand = [{'id': d.get('id'), 'name': d.get('name')} for d in data if d.get('expandable')]
+
+ while nodes_to_expand:
+ parent = nodes_to_expand.pop(0)
+ data = method(parent.get('id'), company)
+ result.append(dict(parent=parent.get('id'), parent_name=parent.get('name'), data=data))
+ for d in data:
+ if d.get('expandable'):
+ nodes_to_expand.append({'id': d.get('id'), 'name': d.get('name')})
+
+ return result
\ No newline at end of file
From 2ff0d3e0ebf5424ad8a50f65ad64b531a13f4b40 Mon Sep 17 00:00:00 2001
From: Deepesh Garg
Date: Thu, 22 Jul 2021 10:43:16 +0530
Subject: [PATCH 150/386] fix: Test Cases
---
.../doctype/purchase_invoice/test_purchase_invoice.py | 9 ---------
.../accounts/doctype/sales_invoice/test_sales_invoice.py | 3 +--
2 files changed, 1 insertion(+), 11 deletions(-)
diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
index e20e385f63..9d2acdc977 100644
--- a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
@@ -263,14 +263,6 @@ class TestPurchaseInvoice(unittest.TestCase):
})
pi.submit()
- # gle = frappe.get_all(
- # "GL Entry",
- # fields = ['account', 'debit', 'credit', 'posting_date'],
- # filters = {'voucher_no': pi.name}
- # )
- # for gl in gle:
- # print(gl, "\n")
-
expected_gle = [
["_Test Account Cost for Goods Sold - _TC", 100.0, 0.0, nowdate()],
["_Test Account VAT - _TC", 20.0, 0.0, nowdate()],
@@ -1196,7 +1188,6 @@ def check_gl_entries(doc, voucher_no, expected_gle, posting_date):
where voucher_type='Purchase Invoice' and voucher_no=%s and posting_date >= %s
order by posting_date asc, account asc""", (voucher_no, posting_date), as_dict=1)
- print(gl_entries)
for i, gle in enumerate(gl_entries):
doc.assertEqual(expected_gle[i][0], gle.account)
doc.assertEqual(expected_gle[i][1], gle.debit)
diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
index 1c0177d3d0..a7fbbdd5ca 100644
--- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
@@ -2008,7 +2008,7 @@ class TestSalesInvoice(unittest.TestCase):
additional_discount_account = create_account(account_name="Discount Account",
parent_account="Indirect Expenses - _TC", company="_Test Company")
- si = create_sales_invoice(rate=100, do_not_save=1)
+ si = create_sales_invoice(rate=100, parent_cost_center='Main - _TC', do_not_save=1)
si.apply_discount_on = "Grand Total"
si.additional_discount_account = additional_discount_account
si.additional_discount_percentage = 20
@@ -2016,7 +2016,6 @@ class TestSalesInvoice(unittest.TestCase):
"charge_type": "Actual",
"account_head": "_Test Account VAT - _TC",
"cost_center": "Main - _TC",
- "parent_cost_center": "Main - _TC",
"description": "Test",
"rate": 0,
"tax_amount": 20
From 328444b530afea225103660a0c5fea9124e0f014 Mon Sep 17 00:00:00 2001
From: Deepesh Garg
Date: Fri, 23 Jul 2021 20:28:02 +0530
Subject: [PATCH 151/386] fix(India): Default value for export type
---
erpnext/patches.txt | 1 +
.../v13_0/update_export_type_for_gst.py | 24 +++++++++++++++++++
erpnext/regional/india/setup.py | 2 --
3 files changed, 25 insertions(+), 2 deletions(-)
create mode 100644 erpnext/patches/v13_0/update_export_type_for_gst.py
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 2a83635117..b891719b02 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -293,3 +293,4 @@ erpnext.patches.v13_0.update_job_card_details
erpnext.patches.v13_0.update_level_in_bom #1234sswef
erpnext.patches.v13_0.add_missing_fg_item_for_stock_entry
erpnext.patches.v13_0.update_subscription_status_in_memberships
+erpnext.patches.v13_0.update_export_type_for_gst
diff --git a/erpnext/patches/v13_0/update_export_type_for_gst.py b/erpnext/patches/v13_0/update_export_type_for_gst.py
new file mode 100644
index 0000000000..478a2a6c80
--- /dev/null
+++ b/erpnext/patches/v13_0/update_export_type_for_gst.py
@@ -0,0 +1,24 @@
+import frappe
+
+def execute():
+ company = frappe.get_all('Company', filters = {'country': 'India'})
+ if not company:
+ return
+
+ # Update custom fields
+ fieldname = frappe.db.get_value('Custom Field', {'dt': 'Customer', 'fieldname': 'export_type'})
+ if fieldname:
+ frappe.db.set_value('Custom Field', fieldname, 'default', '')
+
+ fieldname = frappe.db.get_value('Custom Field', {'dt': 'Supplier', 'fieldname': 'export_type'})
+ if fieldname:
+ frappe.db.set_value('Custom Field', fieldname, 'default', '')
+
+ # Update Customer/Supplier Masters
+ frappe.db.sql("""
+ UPDATE `tabCustomer` set export_type = '' WHERE gst_category NOT IN ('SEZ', 'Overseas', 'Deemed Export')
+ """)
+
+ frappe.db.sql("""
+ UPDATE `tabSupplier` set export_type = '' WHERE gst_category NOT IN ('SEZ', 'Overseas')
+ """)
\ No newline at end of file
diff --git a/erpnext/regional/india/setup.py b/erpnext/regional/india/setup.py
index 92654608da..e9372f9b8f 100644
--- a/erpnext/regional/india/setup.py
+++ b/erpnext/regional/india/setup.py
@@ -641,7 +641,6 @@ def make_custom_fields(update=True):
'label': 'Export Type',
'fieldtype': 'Select',
'insert_after': 'gst_category',
- 'default': 'Without Payment of Tax',
'depends_on':'eval:in_list(["SEZ", "Overseas"], doc.gst_category)',
'options': '\nWith Payment of Tax\nWithout Payment of Tax'
}
@@ -660,7 +659,6 @@ def make_custom_fields(update=True):
'label': 'Export Type',
'fieldtype': 'Select',
'insert_after': 'gst_category',
- 'default': 'Without Payment of Tax',
'depends_on':'eval:in_list(["SEZ", "Overseas", "Deemed Export"], doc.gst_category)',
'options': '\nWith Payment of Tax\nWithout Payment of Tax'
}
From 57cb3ac023544c618b2c7c9fa5927a81cd31a848 Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Sun, 25 Jul 2021 20:23:20 +0530
Subject: [PATCH 152/386] feat: add html2canvas for easily exporting html to
images using canvas
---
.eslintrc | 1 +
package.json | 3 ++-
yarn.lock | 19 +++++++++++++++++++
3 files changed, 22 insertions(+), 1 deletion(-)
diff --git a/.eslintrc b/.eslintrc
index ecfaab23ee..46fb354c11 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -154,6 +154,7 @@
"before": true,
"beforeEach": true,
"onScan": true,
+ "html2canvas": true,
"extend_cscript": true,
"localforage": true
}
diff --git a/package.json b/package.json
index c9ee7a622c..5bc1e56a21 100644
--- a/package.json
+++ b/package.json
@@ -15,7 +15,8 @@
"snyk": "^1.518.0"
},
"dependencies": {
- "onscan.js": "^1.5.2"
+ "onscan.js": "^1.5.2",
+ "html2canvas": "^1.1.4"
},
"scripts": {
"snyk-protect": "snyk protect",
diff --git a/yarn.lock b/yarn.lock
index 0a2ac1affc..cc01d89344 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -688,6 +688,11 @@ balanced-match@^1.0.0:
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
+base64-arraybuffer@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.2.0.tgz#4b944fac0191aa5907afe2d8c999ccc57ce80f45"
+ integrity sha512-7emyCsu1/xiBXgQZrscw/8KPRT44I4Yq9Pe6EGs3aPRTsWuggML1/1DTuZUuIaJPIm1FTDUVXl4x/yW8s0kQDQ==
+
base64-js@^1.3.1:
version "1.5.1"
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
@@ -997,6 +1002,13 @@ crypto-random-string@^2.0.0:
resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5"
integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==
+css-line-break@1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/css-line-break/-/css-line-break-1.1.1.tgz#d5e9bdd297840099eb0503c7310fd34927a026ef"
+ integrity sha512-1feNVaM4Fyzdj4mKPIQNL2n70MmuYzAXZ1aytlROFX1JsOo070OsugwGjj7nl6jnDJWHDM8zRZswkmeYVWZJQA==
+ dependencies:
+ base64-arraybuffer "^0.2.0"
+
debug@^3.1.0, debug@^3.2.6:
version "3.2.6"
resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b"
@@ -1472,6 +1484,13 @@ hosted-git-info@^3.0.4, hosted-git-info@^3.0.7:
dependencies:
lru-cache "^6.0.0"
+html2canvas@^1.1.4:
+ version "1.1.4"
+ resolved "https://registry.yarnpkg.com/html2canvas/-/html2canvas-1.1.4.tgz#53ae91cd26e9e9e623c56533cccb2e3f57c8124c"
+ integrity sha512-uHgQDwrXsRmFdnlOVFvHin9R7mdjjZvoBoXxicPR+NnucngkaLa5zIDW9fzMkiip0jSffyTyWedE8iVogYOeWg==
+ dependencies:
+ css-line-break "1.1.1"
+
http-cache-semantics@^4.0.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz#49e91c5cbf36c9b94bcfcd71c23d5249ec74e390"
From 37198159aaaecb86b5bbcb4528b935922eb11f3c Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Sun, 25 Jul 2021 20:28:01 +0530
Subject: [PATCH 153/386] feat: Export chart option in desktop view
---
.../hierarchy_chart_desktop.js | 97 +++++++++++++------
erpnext/public/scss/hierarchy_chart.scss | 10 +-
erpnext/utilities/hierarchy_chart.py | 4 +-
3 files changed, 82 insertions(+), 29 deletions(-)
diff --git a/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js b/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
index 694c26567a..57d34d8225 100644
--- a/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
+++ b/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
@@ -1,3 +1,4 @@
+import html2canvas from 'html2canvas';
erpnext.HierarchyChart = class {
/* Options:
- doctype
@@ -11,16 +12,20 @@ erpnext.HierarchyChart = class {
this.method = method;
this.doctype = doctype;
+ this.setup_page_style();
+ this.page.main.addClass('frappe-card');
+
+ this.nodes = {};
+ this.setup_node_class();
+ }
+
+ setup_page_style() {
this.page.main.css({
'min-height': '300px',
'max-height': '600px',
'overflow': 'auto',
'position': 'relative'
});
- this.page.main.addClass('frappe-card');
-
- this.nodes = {};
- this.setup_node_class();
}
setup_node_class() {
@@ -84,7 +89,7 @@ erpnext.HierarchyChart = class {
// svg for connectors
me.make_svg_markers();
- me.setup_hierarchy()
+ me.setup_hierarchy();
me.render_root_nodes();
me.all_nodes_expanded = false;
}
@@ -97,6 +102,10 @@ erpnext.HierarchyChart = class {
setup_actions() {
let me = this;
+ this.page.add_inner_button(__('Export'), function() {
+ me.export_chart();
+ });
+
this.page.add_inner_button(__('Expand All'), function() {
me.load_children(me.root_node, true);
me.all_nodes_expanded = true;
@@ -113,6 +122,36 @@ erpnext.HierarchyChart = class {
});
}
+ export_chart() {
+ this.page.main.css({
+ 'min-height': '',
+ 'max-height': '',
+ 'overflow': 'visible',
+ 'position': 'fixed',
+ 'left': '0',
+ 'top': '0'
+ });
+
+ $('.node-card').addClass('exported');
+
+ html2canvas(document.querySelector('#hierarchy-chart-wrapper'), {
+ scrollY: -window.scrollY,
+ scrollX: 0
+ }).then(function(canvas) {
+ // Export the canvas to its data URI representation
+ let dataURL = canvas.toDataURL('image/png');
+
+ // download the image
+ let a = document.createElement('a');
+ a.href = dataURL;
+ a.download = 'hierarchy_chart';
+ a.click();
+ });
+
+ this.setup_page_style();
+ $('.node-card').removeClass('exported');
+ }
+
setup_hierarchy() {
if (this.$hierarchy)
this.$hierarchy.remove();
@@ -127,33 +166,37 @@ erpnext.HierarchyChart = class {
`);
- this.page.main.append(this.$hierarchy);
+ this.page.main
+ .find('#hierarchy-chart-wrapper')
+ .append(this.$hierarchy);
this.nodes = {};
}
make_svg_markers() {
$('#arrows').remove();
- this.page.main.prepend(`
-
-
-
-
-
-
-
-
+ this.page.main.append(`
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
- `);
+
+
+
+
+
+
+
+
+
+
+
`);
}
render_root_nodes(expanded_view=false) {
@@ -310,7 +353,7 @@ erpnext.HierarchyChart = class {
let entry = undefined;
let node = undefined;
- while(data_list.length) {
+ while (data_list.length) {
// to avoid overlapping connectors
entry = data_list.shift();
node = this.nodes[entry.parent];
@@ -323,7 +366,7 @@ erpnext.HierarchyChart = class {
}
render_child_nodes_for_expanded_view(node, child_nodes) {
- node.$children = $('')
+ node.$children = $('');
const last_level = this.$hierarchy.find('.level:last').index();
const node_level = $(`#${node.id}`).parent().parent().parent().index();
diff --git a/erpnext/public/scss/hierarchy_chart.scss b/erpnext/public/scss/hierarchy_chart.scss
index 1c2f9421fa..44288fe155 100644
--- a/erpnext/public/scss/hierarchy_chart.scss
+++ b/erpnext/public/scss/hierarchy_chart.scss
@@ -21,6 +21,10 @@
}
}
+.node-card.exported {
+ box-shadow: none
+}
+
.node-image {
width: 3.0rem;
height: 3.0rem;
@@ -178,9 +182,12 @@
}
// horizontal hierarchy tree view
+#hierarchy-chart-wrapper {
+ padding-top: 30px;
+}
+
.hierarchy {
display: flex;
- padding-top: 30px;
}
.hierarchy li {
@@ -200,6 +207,7 @@
#arrows {
position: absolute;
overflow: visible;
+ margin-top: -80px;
}
.active-connector {
diff --git a/erpnext/utilities/hierarchy_chart.py b/erpnext/utilities/hierarchy_chart.py
index 9b0279351f..22d3f28faa 100644
--- a/erpnext/utilities/hierarchy_chart.py
+++ b/erpnext/utilities/hierarchy_chart.py
@@ -3,14 +3,16 @@
from __future__ import unicode_literals
import frappe
+import os
from frappe import _
+from frappe.utils.pdf import get_pdf
@frappe.whitelist()
def get_all_nodes(parent, parent_name, method, company):
'''Recursively gets all data from nodes'''
method = frappe.get_attr(method)
- if not method in frappe.whitelisted:
+ if method not in frappe.whitelisted:
frappe.throw(_('Not Permitted'), frappe.PermissionError)
data = method(parent, company)
From 475d856d6681bebd2586754b0c081735952e841e Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Sun, 25 Jul 2021 20:39:51 +0530
Subject: [PATCH 154/386] fix(style): longer titles overflowing
---
erpnext/public/scss/hierarchy_chart.scss | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/erpnext/public/scss/hierarchy_chart.scss b/erpnext/public/scss/hierarchy_chart.scss
index 44288fe155..7f1077dbbd 100644
--- a/erpnext/public/scss/hierarchy_chart.scss
+++ b/erpnext/public/scss/hierarchy_chart.scss
@@ -40,6 +40,10 @@
line-height: 1.35;
}
+.node-info {
+ width: 12.7rem;
+}
+
.node-connections {
font-size: 0.75rem;
line-height: 1.35;
From 6bca87ddb9c39cd18abb30bc1b9f4cb5f07b451c Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Sun, 25 Jul 2021 21:34:51 +0530
Subject: [PATCH 155/386] fix: remove unnecessary imports
---
erpnext/utilities/hierarchy_chart.py | 2 --
1 file changed, 2 deletions(-)
diff --git a/erpnext/utilities/hierarchy_chart.py b/erpnext/utilities/hierarchy_chart.py
index 22d3f28faa..fb58a5d586 100644
--- a/erpnext/utilities/hierarchy_chart.py
+++ b/erpnext/utilities/hierarchy_chart.py
@@ -3,9 +3,7 @@
from __future__ import unicode_literals
import frappe
-import os
from frappe import _
-from frappe.utils.pdf import get_pdf
@frappe.whitelist()
def get_all_nodes(parent, parent_name, method, company):
From c676eaae57d353ff9ecd34fe28158e8216e94c9f Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Sun, 25 Jul 2021 23:11:18 +0530
Subject: [PATCH 156/386] fix: test
---
erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js b/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
index 57d34d8225..89fb8d5792 100644
--- a/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
+++ b/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
@@ -173,7 +173,7 @@ erpnext.HierarchyChart = class {
}
make_svg_markers() {
- $('#arrows').remove();
+ $('#hierarchy-chart-wrapper').remove();
this.page.main.append(`
From 4209b3bda9dce91efa816d7dd43a655210ef02a5 Mon Sep 17 00:00:00 2001
From: Frappe PR Bot
Date: Mon, 26 Jul 2021 13:00:32 +0530
Subject: [PATCH 157/386] fix: included company in Link Document Type filters
for contact (#26576) (#26634)
(cherry picked from commit cbddedab7bf2fc7637b861214c3373a742da830b)
Co-authored-by: Noah Jacob
---
erpnext/hooks.py | 3 ++-
erpnext/public/js/contact.js | 16 ++++++++++++++++
2 files changed, 18 insertions(+), 1 deletion(-)
create mode 100644 erpnext/public/js/contact.js
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index 52daec9180..1ba752a146 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -24,7 +24,8 @@ doctype_js = {
"Address": "public/js/address.js",
"Communication": "public/js/communication.js",
"Event": "public/js/event.js",
- "Newsletter": "public/js/newsletter.js"
+ "Newsletter": "public/js/newsletter.js",
+ "Contact": "public/js/contact.js"
}
override_doctype_class = {
diff --git a/erpnext/public/js/contact.js b/erpnext/public/js/contact.js
new file mode 100644
index 0000000000..41a0e8a9f9
--- /dev/null
+++ b/erpnext/public/js/contact.js
@@ -0,0 +1,16 @@
+
+
+frappe.ui.form.on("Contact", {
+ refresh(frm) {
+ frm.set_query('link_doctype', "links", function() {
+ return {
+ query: "frappe.contacts.address_and_contact.filter_dynamic_link_doctypes",
+ filters: {
+ fieldtype: ["in", ["HTML", "Text Editor"]],
+ fieldname: ["in", ["contact_html", "company_description"]],
+ }
+ };
+ });
+ frm.refresh_field("links");
+ }
+});
From 06fb0b93b5905ab0ba7acd6939a817ecebe717e9 Mon Sep 17 00:00:00 2001
From: Subin Tom <36098155+nemesis189@users.noreply.github.com>
Date: Mon, 26 Jul 2021 16:46:47 +0530
Subject: [PATCH 158/386] fix: Supplier invoice importer fix v13 (#26633)
* fix: Supplier Invoice Importer fix
Co-authored-by: Subin Tom
---
erpnext/controllers/accounts_controller.py | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index 4c313c43a7..cdd865ac4a 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -1112,8 +1112,11 @@ class AccountsController(TransactionBase):
for d in self.get("payment_schedule"):
if d.invoice_portion:
d.payment_amount = flt(grand_total * flt(d.invoice_portion / 100), d.precision('payment_amount'))
- d.base_payment_amount = flt(base_grand_total * flt(d.invoice_portion / 100), d.precision('payment_amount'))
+ d.base_payment_amount = flt(base_grand_total * flt(d.invoice_portion / 100), d.precision('base_payment_amount'))
d.outstanding = d.payment_amount
+ elif not d.invoice_portion:
+ d.base_payment_amount = flt(base_grand_total * self.get("conversion_rate"), d.precision('base_payment_amount'))
+
def set_due_date(self):
due_dates = [d.due_date for d in self.get("payment_schedule") if d.due_date]
From d066eab6cd15ded671cbb5c34d8f4a8847a7ba64 Mon Sep 17 00:00:00 2001
From: Deepesh Garg
Date: Mon, 26 Jul 2021 18:38:50 +0530
Subject: [PATCH 159/386] fix: Test case for GSTR-3b report
---
.../regional/doctype/gstr_3b_report/gstr_3b_report.py | 10 ++++++++--
erpnext/regional/report/gstr_1/gstr_1.py | 3 ++-
2 files changed, 10 insertions(+), 3 deletions(-)
diff --git a/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.py b/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.py
index 641520437f..6fd135d560 100644
--- a/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.py
+++ b/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.py
@@ -281,9 +281,15 @@ class GSTR3BReport(Document):
if self.get('invoice_items'):
# Build itemised tax for export invoices, nil and exempted where tax table is blank
for invoice, items in iteritems(self.invoice_items):
- if invoice not in self.items_based_on_tax_rate and (self.invoice_detail_map.get(invoice, {}).get('export_type')
- == "Without Payment of Tax"):
+ if invoice not in self.items_based_on_tax_rate and self.invoice_detail_map.get(invoice, {}).get('export_type') \
+ == "Without Payment of Tax" and self.invoice_detail_map.get(invoice, {}).get('gst_category') == "Overseas":
self.items_based_on_tax_rate.setdefault(invoice, {}).setdefault(0, items.keys())
+ else:
+ for item in items.keys():
+ if item in self.is_nil_exempt + self.is_non_gst and \
+ item not in self.items_based_on_tax_rate.get(invoice, {}).get(0, []):
+ self.items_based_on_tax_rate.setdefault(invoice, {}).setdefault(0, [])
+ self.items_based_on_tax_rate[invoice][0].append(item)
def set_outward_taxable_supplies(self):
inter_state_supply_details = {}
diff --git a/erpnext/regional/report/gstr_1/gstr_1.py b/erpnext/regional/report/gstr_1/gstr_1.py
index cfcb8c3444..f9de2d527b 100644
--- a/erpnext/regional/report/gstr_1/gstr_1.py
+++ b/erpnext/regional/report/gstr_1/gstr_1.py
@@ -287,7 +287,8 @@ class Gstr1Report(object):
# Build itemised tax for export invoices where tax table is blank
for invoice, items in iteritems(self.invoice_items):
if invoice not in self.items_based_on_tax_rate and invoice not in unidentified_gst_accounts_invoice \
- and frappe.db.get_value(self.doctype, invoice, "export_type") == "Without Payment of Tax":
+ and self.invoices.get(invoice, {}).get('export_type') == "Without Payment of Tax" \
+ and self.invoices.get(invoice, {}).get('gst_category') == "Overseas":
self.items_based_on_tax_rate.setdefault(invoice, {}).setdefault(0, items.keys())
def get_columns(self):
From 8d52a2270999f8fa37139aa02ec9bf839f95a343 Mon Sep 17 00:00:00 2001
From: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com>
Date: Mon, 26 Jul 2021 19:00:57 +0530
Subject: [PATCH 160/386] fix: Additional discount calculations in Invoices
(#26553)
* fix: Additional discount calculations in Invoices
* revert: Client side handling for Dynamic GST Rates
* fix: Add update item tax template method back
* fix: Revert refresh field
* fix: add company change trigger
---
.../public/js/controllers/taxes_and_totals.js | 69 +++----------------
erpnext/public/js/controllers/transaction.js | 44 +++++++++++-
2 files changed, 53 insertions(+), 60 deletions(-)
diff --git a/erpnext/public/js/controllers/taxes_and_totals.js b/erpnext/public/js/controllers/taxes_and_totals.js
index 52efbb5f6c..53d5278bbf 100644
--- a/erpnext/public/js/controllers/taxes_and_totals.js
+++ b/erpnext/public/js/controllers/taxes_and_totals.js
@@ -65,28 +65,23 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
this.frm.refresh_fields();
},
- calculate_discount_amount: function(){
+ calculate_discount_amount: function() {
if (frappe.meta.get_docfield(this.frm.doc.doctype, "discount_amount")) {
- this.calculate_item_values();
- this.calculate_net_total();
this.set_discount_amount();
this.apply_discount_amount();
}
},
_calculate_taxes_and_totals: function() {
- frappe.run_serially([
- () => this.validate_conversion_rate(),
- () => this.calculate_item_values(),
- () => this.update_item_tax_map(),
- () => this.initialize_taxes(),
- () => this.determine_exclusive_rate(),
- () => this.calculate_net_total(),
- () => this.calculate_taxes(),
- () => this.manipulate_grand_total_for_inclusive_tax(),
- () => this.calculate_totals(),
- () => this._cleanup()
- ]);
+ this.validate_conversion_rate();
+ this.calculate_item_values();
+ this.initialize_taxes();
+ this.determine_exclusive_rate();
+ this.calculate_net_total();
+ this.calculate_taxes();
+ this.manipulate_grand_total_for_inclusive_tax();
+ this.calculate_totals();
+ this._cleanup();
},
validate_conversion_rate: function() {
@@ -107,7 +102,7 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
},
calculate_item_values: function() {
- var me = this;
+ let me = this;
if (!this.discount_amount_applied) {
$.each(this.frm.doc["items"] || [], function(i, item) {
frappe.model.round_floats_in(item);
@@ -268,46 +263,6 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
frappe.model.round_floats_in(this.frm.doc, ["total", "base_total", "net_total", "base_net_total"]);
},
- update_item_tax_map: function() {
- let me = this;
- let item_codes = [];
- let item_rates = {};
- let item_tax_templates = {};
-
- $.each(this.frm.doc.items || [], function(i, item) {
- if (item.item_code) {
- // Use combination of name and item code in case same item is added multiple times
- item_codes.push([item.item_code, item.name]);
- item_rates[item.name] = item.net_rate;
- item_tax_templates[item.name] = item.item_tax_template;
- }
- });
-
- if (item_codes.length) {
- return this.frm.call({
- method: "erpnext.stock.get_item_details.get_item_tax_info",
- args: {
- company: me.frm.doc.company,
- tax_category: cstr(me.frm.doc.tax_category),
- item_codes: item_codes,
- item_rates: item_rates,
- item_tax_templates: item_tax_templates
- },
- callback: function(r) {
- if (!r.exc) {
- $.each(me.frm.doc.items || [], function(i, item) {
- if (item.name && r.message.hasOwnProperty(item.name) && r.message[item.name].item_tax_template) {
- item.item_tax_template = r.message[item.name].item_tax_template;
- item.item_tax_rate = r.message[item.name].item_tax_rate;
- me.add_taxes_from_item_tax_template(item.item_tax_rate);
- }
- });
- }
- }
- });
- }
- },
-
add_taxes_from_item_tax_template: function(item_tax_map) {
let me = this;
@@ -632,8 +587,6 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
tax.item_wise_tax_detail = JSON.stringify(tax.item_wise_tax_detail);
});
}
-
- this.frm.refresh_fields();
},
set_discount_amount: function() {
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index b3af3d67ea..5475383759 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -826,9 +826,9 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
frappe.run_serially([
() => me.frm.script_manager.trigger("currency"),
+ () => me.update_item_tax_map(),
() => me.apply_default_taxes(),
- () => me.apply_pricing_rule(),
- () => me.calculate_taxes_and_totals()
+ () => me.apply_pricing_rule()
]);
}
}
@@ -1787,6 +1787,46 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
]);
},
+ update_item_tax_map: function() {
+ let me = this;
+ let item_codes = [];
+ let item_rates = {};
+ let item_tax_templates = {};
+
+ $.each(this.frm.doc.items || [], function(i, item) {
+ if (item.item_code) {
+ // Use combination of name and item code in case same item is added multiple times
+ item_codes.push([item.item_code, item.name]);
+ item_rates[item.name] = item.net_rate;
+ item_tax_templates[item.name] = item.item_tax_template;
+ }
+ });
+
+ if (item_codes.length) {
+ return this.frm.call({
+ method: "erpnext.stock.get_item_details.get_item_tax_info",
+ args: {
+ company: me.frm.doc.company,
+ tax_category: cstr(me.frm.doc.tax_category),
+ item_codes: item_codes,
+ item_rates: item_rates,
+ item_tax_templates: item_tax_templates
+ },
+ callback: function(r) {
+ if (!r.exc) {
+ $.each(me.frm.doc.items || [], function(i, item) {
+ if (item.name && r.message.hasOwnProperty(item.name) && r.message[item.name].item_tax_template) {
+ item.item_tax_template = r.message[item.name].item_tax_template;
+ item.item_tax_rate = r.message[item.name].item_tax_rate;
+ me.add_taxes_from_item_tax_template(item.item_tax_rate);
+ }
+ });
+ }
+ }
+ });
+ }
+ },
+
item_tax_template: function(doc, cdt, cdn) {
var me = this;
if(me.frm.updating_party_details) return;
From fb72df7dce3124d36b4e86553fc509928a3585b2 Mon Sep 17 00:00:00 2001
From: Deepesh Garg
Date: Sun, 25 Jul 2021 19:46:20 +0530
Subject: [PATCH 161/386] fix: Exchange rate revaluation posting date and
precision fixes
---
.../exchange_rate_revaluation.py | 20 ++++++++++---------
1 file changed, 11 insertions(+), 9 deletions(-)
diff --git a/erpnext/accounts/doctype/exchange_rate_revaluation/exchange_rate_revaluation.py b/erpnext/accounts/doctype/exchange_rate_revaluation/exchange_rate_revaluation.py
index 56193216a2..e94875f2d7 100644
--- a/erpnext/accounts/doctype/exchange_rate_revaluation/exchange_rate_revaluation.py
+++ b/erpnext/accounts/doctype/exchange_rate_revaluation/exchange_rate_revaluation.py
@@ -99,10 +99,12 @@ class ExchangeRateRevaluation(Document):
sum(debit) - sum(credit) as balance
from `tabGL Entry`
where account in (%s)
+ and posting_date <= %s
+ and is_cancelled = 0
group by account, party_type, party
having sum(debit) != sum(credit)
order by account
- """ % ', '.join(['%s']*len(accounts)), tuple(accounts), as_dict=1)
+ """ % (', '.join(['%s']*len(accounts)), '%s'), tuple(accounts + [self.posting_date]), as_dict=1)
return account_details
@@ -143,9 +145,9 @@ class ExchangeRateRevaluation(Document):
"party_type": d.get("party_type"),
"party": d.get("party"),
"account_currency": d.get("account_currency"),
- "balance": d.get("balance_in_account_currency"),
- dr_or_cr: abs(d.get("balance_in_account_currency")),
- "exchange_rate":d.get("new_exchange_rate"),
+ "balance": flt(d.get("balance_in_account_currency"), d.precision("balance_in_account_currency")),
+ dr_or_cr: flt(abs(d.get("balance_in_account_currency")), d.precision("balance_in_account_currency")),
+ "exchange_rate": flt(d.get("new_exchange_rate"), d.precision("new_exchange_rate")),
"reference_type": "Exchange Rate Revaluation",
"reference_name": self.name,
})
@@ -154,9 +156,9 @@ class ExchangeRateRevaluation(Document):
"party_type": d.get("party_type"),
"party": d.get("party"),
"account_currency": d.get("account_currency"),
- "balance": d.get("balance_in_account_currency"),
- reverse_dr_or_cr: abs(d.get("balance_in_account_currency")),
- "exchange_rate": d.get("current_exchange_rate"),
+ "balance": flt(d.get("balance_in_account_currency"), d.precision("balance_in_account_currency")),
+ reverse_dr_or_cr: flt(abs(d.get("balance_in_account_currency")), d.precision("balance_in_account_currency")),
+ "exchange_rate": flt(d.get("current_exchange_rate"), d.precision("current_exchange_rate")),
"reference_type": "Exchange Rate Revaluation",
"reference_name": self.name
})
@@ -185,9 +187,9 @@ def get_account_details(account, company, posting_date, party_type=None, party=N
account_details = {}
company_currency = erpnext.get_company_currency(company)
- balance = get_balance_on(account, party_type=party_type, party=party, in_account_currency=False)
+ balance = get_balance_on(account, date=posting_date, party_type=party_type, party=party, in_account_currency=False)
if balance:
- balance_in_account_currency = get_balance_on(account, party_type=party_type, party=party)
+ balance_in_account_currency = get_balance_on(account, date=posting_date, party_type=party_type, party=party)
current_exchange_rate = balance / balance_in_account_currency if balance_in_account_currency else 0
new_exchange_rate = get_exchange_rate(account_currency, company_currency, posting_date)
new_balance_in_base_currency = balance_in_account_currency * new_exchange_rate
From 5749e52bf6f4a67d4ee899b07edc2c2ac8434bf6 Mon Sep 17 00:00:00 2001
From: Deepesh Garg
Date: Sun, 25 Jul 2021 19:46:50 +0530
Subject: [PATCH 162/386] fix: Ignore GL Entry on cancel
---
.../exchange_rate_revaluation/exchange_rate_revaluation.py | 3 +++
1 file changed, 3 insertions(+)
diff --git a/erpnext/accounts/doctype/exchange_rate_revaluation/exchange_rate_revaluation.py b/erpnext/accounts/doctype/exchange_rate_revaluation/exchange_rate_revaluation.py
index e94875f2d7..c8d5737d75 100644
--- a/erpnext/accounts/doctype/exchange_rate_revaluation/exchange_rate_revaluation.py
+++ b/erpnext/accounts/doctype/exchange_rate_revaluation/exchange_rate_revaluation.py
@@ -27,6 +27,9 @@ class ExchangeRateRevaluation(Document):
if not (self.company and self.posting_date):
frappe.throw(_("Please select Company and Posting Date to getting entries"))
+ def on_cancel(self):
+ self.ignore_linked_doctypes = ('GL Entry')
+
@frappe.whitelist()
def check_journal_entry_condition(self):
total_debit = frappe.db.get_value("Journal Entry Account", {
From dc2cd35b933ee038940578325efbec7c2f522906 Mon Sep 17 00:00:00 2001
From: Deepesh Garg
Date: Sun, 25 Jul 2021 21:26:22 +0530
Subject: [PATCH 163/386] fix: Convert null values to empty string on grouping
---
.../exchange_rate_revaluation/exchange_rate_revaluation.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/accounts/doctype/exchange_rate_revaluation/exchange_rate_revaluation.py b/erpnext/accounts/doctype/exchange_rate_revaluation/exchange_rate_revaluation.py
index c8d5737d75..f2b0a8c08a 100644
--- a/erpnext/accounts/doctype/exchange_rate_revaluation/exchange_rate_revaluation.py
+++ b/erpnext/accounts/doctype/exchange_rate_revaluation/exchange_rate_revaluation.py
@@ -104,7 +104,7 @@ class ExchangeRateRevaluation(Document):
where account in (%s)
and posting_date <= %s
and is_cancelled = 0
- group by account, party_type, party
+ group by account, NULLIF(party_type,''), NULLIF(party,'')
having sum(debit) != sum(credit)
order by account
""" % (', '.join(['%s']*len(accounts)), '%s'), tuple(accounts + [self.posting_date]), as_dict=1)
From cfd73ed554b21550592dd57abc561bd8eb72f3a9 Mon Sep 17 00:00:00 2001
From: Frappe PR Bot
Date: Mon, 26 Jul 2021 19:42:19 +0530
Subject: [PATCH 164/386] ci: auto backport squashed commits based on labels
(#26622) (#26640)
(cherry picked from commit 057a0a98428b138b20646b820e7ab27c99bc5f22)
Co-authored-by: Ankush
---
.github/workflows/backport.yml | 23 ++++++++++++++++-------
1 file changed, 16 insertions(+), 7 deletions(-)
diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml
index 7c6b8432b8..cc98f4544f 100644
--- a/.github/workflows/backport.yml
+++ b/.github/workflows/backport.yml
@@ -1,16 +1,25 @@
name: Backport
on:
- pull_request:
+ pull_request_target:
types:
- closed
- labeled
jobs:
- backport:
- runs-on: ubuntu-18.04
- name: Backport
+ main:
+ runs-on: ubuntu-latest
steps:
- - name: Backport
- uses: tibdex/backport@v1
+ - name: Checkout Actions
+ uses: actions/checkout@v2
with:
- github_token: ${{ secrets.GITHUB_TOKEN }}
\ No newline at end of file
+ repository: "ankush/backport"
+ path: ./actions
+ ref: develop
+ - name: Install Actions
+ run: npm install --production --prefix ./actions
+ - name: Run backport
+ uses: ./actions/backport
+ with:
+ token: ${{secrets.BACKPORT_BOT_TOKEN}}
+ labelsToAdd: "backport"
+ title: "{{originalTitle}}"
From aaea5edbdb2d14ce3599e9e5d47048cf032e3f6c Mon Sep 17 00:00:00 2001
From: Jannat Patel <31363128+pateljannat@users.noreply.github.com>
Date: Tue, 27 Jul 2021 09:39:33 +0530
Subject: [PATCH 165/386] fix: Salary component account filter (#26605)
* fix: salary component account filter
* fix: cleanup
---
.../doctype/salary_component/salary_component.js | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/erpnext/payroll/doctype/salary_component/salary_component.js b/erpnext/payroll/doctype/salary_component/salary_component.js
index dbf75140ac..e9e6f81862 100644
--- a/erpnext/payroll/doctype/salary_component/salary_component.js
+++ b/erpnext/payroll/doctype/salary_component/salary_component.js
@@ -4,11 +4,18 @@
frappe.ui.form.on('Salary Component', {
setup: function(frm) {
frm.set_query("account", "accounts", function(doc, cdt, cdn) {
- var d = locals[cdt][cdn];
+ let d = frappe.get_doc(cdt, cdn);
+
+ let root_type = "Liability";
+ if (frm.doc.type == "Deduction") {
+ root_type = "Expense";
+ }
+
return {
filters: {
"is_group": 0,
- "company": d.company
+ "company": d.company,
+ "root_type": root_type
}
};
});
From 6c48a2ed7949e33401dc6efe8682540bc3ba9c1c Mon Sep 17 00:00:00 2001
From: Jannat Patel <31363128+pateljannat@users.noreply.github.com>
Date: Tue, 27 Jul 2021 09:41:55 +0530
Subject: [PATCH 166/386] fix: Removed set_status after cancel from Expense
Claim and Employee Advance (#25901)
* fix: removed set_status after cancel from hr doctypes
* fix: semgrep on_submit issue
* fix: sider
* fix: spaces
* fix: update flag for db_set
---
.../employee_advance/employee_advance.py | 3 +--
.../hr/doctype/expense_claim/expense_claim.py | 23 +++++++++++--------
2 files changed, 14 insertions(+), 12 deletions(-)
diff --git a/erpnext/hr/doctype/employee_advance/employee_advance.py b/erpnext/hr/doctype/employee_advance/employee_advance.py
index ece627c50d..cbb3cc813b 100644
--- a/erpnext/hr/doctype/employee_advance/employee_advance.py
+++ b/erpnext/hr/doctype/employee_advance/employee_advance.py
@@ -24,7 +24,6 @@ class EmployeeAdvance(Document):
def on_cancel(self):
self.ignore_linked_doctypes = ('GL Entry')
- self.set_status()
def set_status(self):
if self.docstatus == 0:
@@ -231,4 +230,4 @@ def get_voucher_type(mode_of_payment=None):
if mode_of_payment_type == "Bank":
voucher_type = "Bank Entry"
- return voucher_type
\ No newline at end of file
+ return voucher_type
diff --git a/erpnext/hr/doctype/expense_claim/expense_claim.py b/erpnext/hr/doctype/expense_claim/expense_claim.py
index 8f8dbb2224..95e2806aed 100644
--- a/erpnext/hr/doctype/expense_claim/expense_claim.py
+++ b/erpnext/hr/doctype/expense_claim/expense_claim.py
@@ -36,8 +36,8 @@ class ExpenseClaim(AccountsController):
if self.task and not self.project:
self.project = frappe.db.get_value("Task", self.task, "project")
- def set_status(self):
- self.status = {
+ def set_status(self, update=False):
+ status = {
"0": "Draft",
"1": "Submitted",
"2": "Cancelled"
@@ -45,14 +45,18 @@ class ExpenseClaim(AccountsController):
paid_amount = flt(self.total_amount_reimbursed) + flt(self.total_advance_amount)
precision = self.precision("grand_total")
- if (self.is_paid or (flt(self.total_sanctioned_amount) > 0
- and flt(self.grand_total, precision) == flt(paid_amount, precision))) \
- and self.docstatus == 1 and self.approval_status == 'Approved':
- self.status = "Paid"
+ if (self.is_paid or (flt(self.total_sanctioned_amount) > 0 and self.docstatus == 1
+ and flt(self.grand_total, precision) == flt(paid_amount, precision))) and self.approval_status == 'Approved':
+ status = "Paid"
elif flt(self.total_sanctioned_amount) > 0 and self.docstatus == 1 and self.approval_status == 'Approved':
- self.status = "Unpaid"
+ status = "Unpaid"
elif self.docstatus == 1 and self.approval_status == 'Rejected':
- self.status = 'Rejected'
+ status = 'Rejected'
+
+ if update:
+ self.db_set("status", status)
+ else:
+ self.status = status
def on_update(self):
share_doc_with_approver(self, self.expense_approver)
@@ -75,7 +79,7 @@ class ExpenseClaim(AccountsController):
if self.is_paid:
update_reimbursed_amount(self)
- self.set_status()
+ self.set_status(update=True)
self.update_claimed_amount_in_employee_advance()
def on_cancel(self):
@@ -87,7 +91,6 @@ class ExpenseClaim(AccountsController):
if self.is_paid:
update_reimbursed_amount(self)
- self.set_status()
self.update_claimed_amount_in_employee_advance()
def update_claimed_amount_in_employee_advance(self):
From 5448aa25e71dca107d4868c05297a2030a2d4089 Mon Sep 17 00:00:00 2001
From: Jannat Patel <31363128+pateljannat@users.noreply.github.com>
Date: Tue, 27 Jul 2021 10:18:53 +0530
Subject: [PATCH 167/386] chore: code owners updated (#26659)
---
CODEOWNERS | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/CODEOWNERS b/CODEOWNERS
index 219b6bb782..a4a14de1b8 100644
--- a/CODEOWNERS
+++ b/CODEOWNERS
@@ -21,13 +21,13 @@ erpnext/quality_management/ @marination @rohitwaghchaure
erpnext/shopping_cart/ @marination
erpnext/stock/ @marination @rohitwaghchaure @ankush
-erpnext/crm/ @ruchamahabal
-erpnext/education/ @ruchamahabal
-erpnext/healthcare/ @ruchamahabal
-erpnext/hr/ @ruchamahabal
+erpnext/crm/ @ruchamahabal @pateljannat
+erpnext/education/ @ruchamahabal @pateljannat
+erpnext/healthcare/ @ruchamahabal @pateljannat @chillaranand
+erpnext/hr/ @ruchamahabal @pateljannat
erpnext/non_profit/ @ruchamahabal
-erpnext/payroll @ruchamahabal
-erpnext/projects/ @ruchamahabal
+erpnext/payroll @ruchamahabal @pateljannat
+erpnext/projects/ @ruchamahabal @pateljannat
erpnext/controllers @deepeshgarg007 @nextchamp-saqib @rohitwaghchaure @marination
From 6e6823c3aa5555d9fa3f4a3061031c2e6ec59da4 Mon Sep 17 00:00:00 2001
From: Deepesh Garg
Date: Tue, 27 Jul 2021 10:59:25 +0530
Subject: [PATCH 168/386] feat: Enhancements in TDS
---
.../tax_withholding_category.json | 350 ++++++------------
.../tax_withholding_category.py | 24 +-
.../test_tax_withholding_category.py | 47 ++-
3 files changed, 184 insertions(+), 237 deletions(-)
diff --git a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.json b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.json
index f9160e281d..331770fbe8 100644
--- a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.json
+++ b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.json
@@ -1,263 +1,151 @@
{
- "allow_copy": 0,
- "allow_guest_to_view": 0,
- "allow_import": 1,
- "allow_rename": 1,
- "autoname": "Prompt",
- "beta": 0,
- "creation": "2018-04-13 18:42:06.431683",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "",
- "editable_grid": 1,
- "engine": "InnoDB",
+ "actions": [],
+ "allow_import": 1,
+ "allow_rename": 1,
+ "autoname": "Prompt",
+ "creation": "2018-04-13 18:42:06.431683",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "category_details_section",
+ "category_name",
+ "round_off_tax_amount",
+ "column_break_2",
+ "consider_party_ledger_amount",
+ "tax_on_excess_amount",
+ "section_break_8",
+ "rates",
+ "section_break_7",
+ "accounts"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "category_name",
"fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
"in_list_view": 1,
- "in_standard_filter": 0,
"label": "Category Name",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "show_days": 1,
+ "show_seconds": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "section_break_8",
"fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Tax Withholding Rates",
- "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
+ "show_days": 1,
+ "show_seconds": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "rates",
"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": "Rates",
- "length": 0,
- "no_copy": 0,
"options": "Tax Withholding Rate",
- "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
+ "show_days": 1,
+ "show_seconds": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "section_break_7",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
+ "fieldname": "section_break_7",
+ "fieldtype": "Section Break",
"label": "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
- },
+ "show_days": 1,
+ "show_seconds": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "accounts",
- "fieldtype": "Table",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Accounts",
- "length": 0,
- "no_copy": 0,
- "options": "Tax Withholding 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": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "fieldname": "accounts",
+ "fieldtype": "Table",
+ "label": "Accounts",
+ "options": "Tax Withholding Account",
+ "reqd": 1,
+ "show_days": 1,
+ "show_seconds": 1
+ },
+ {
+ "fieldname": "category_details_section",
+ "fieldtype": "Section Break",
+ "label": "Category Details",
+ "show_days": 1,
+ "show_seconds": 1
+ },
+ {
+ "fieldname": "column_break_2",
+ "fieldtype": "Column Break",
+ "show_days": 1,
+ "show_seconds": 1
+ },
+ {
+ "default": "0",
+ "description": "Even invoices with apply tax withholding unchecked will be considered for checking cumulative threshold breach",
+ "fieldname": "consider_party_ledger_amount",
+ "fieldtype": "Check",
+ "label": "Consider Entire Party Ledger Amount",
+ "show_days": 1,
+ "show_seconds": 1
+ },
+ {
+ "default": "0",
+ "description": "Tax will be withheld only for amount exceeding the cumulative threshold",
+ "fieldname": "tax_on_excess_amount",
+ "fieldtype": "Check",
+ "label": "Only Deduct Tax On Excess Amount ",
+ "show_days": 1,
+ "show_seconds": 1
+ },
+ {
+ "description": "Checking this will round off the tax amount to the nearest integer",
+ "fieldname": "round_off_tax_amount",
+ "fieldtype": "Data",
+ "label": "Round Off Tax Amount",
+ "show_days": 1,
+ "show_seconds": 1
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2018-07-17 22:53:26.193179",
- "modified_by": "Administrator",
- "module": "Accounts",
- "name": "Tax Withholding Category",
- "name_case": "",
- "owner": "Administrator",
+ ],
+ "index_web_pages_for_search": 1,
+ "links": [],
+ "modified": "2021-07-26 21:47:34.396071",
+ "modified_by": "Administrator",
+ "module": "Accounts",
+ "name": "Tax Withholding Category",
+ "owner": "Administrator",
"permissions": [
{
- "amend": 0,
- "cancel": 0,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "System Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "System Manager",
+ "share": 1,
"write": 1
- },
+ },
{
- "amend": 0,
- "cancel": 0,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Accounts Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Accounts Manager",
+ "share": 1,
"write": 1
- },
+ },
{
- "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
}
- ],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1,
- "track_seen": 0,
- "track_views": 0
+ ],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
index b9ee4a0963..45c8e1b49f 100644
--- a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
+++ b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
@@ -6,7 +6,7 @@ from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.model.document import Document
-from frappe.utils import flt, getdate
+from frappe.utils import flt, getdate, cint
from erpnext.accounts.utils import get_fiscal_year
class TaxWithholdingCategory(Document):
@@ -86,7 +86,10 @@ def get_tax_withholding_details(tax_withholding_category, fiscal_year, company):
"rate": tax_rate_detail.tax_withholding_rate,
"threshold": tax_rate_detail.single_threshold,
"cumulative_threshold": tax_rate_detail.cumulative_threshold,
- "description": tax_withholding.category_name if tax_withholding.category_name else tax_withholding_category
+ "description": tax_withholding.category_name if tax_withholding.category_name else tax_withholding_category,
+ "consider_party_ledger_amount": tax_withholding.consider_party_ledger_amount,
+ "tax_on_excess_amount": tax_withholding.tax_on_excess_amount,
+ "round_off_tax_amount": tax_withholding.round_off_tax_amount
})
def get_tax_withholding_rates(tax_withholding, fiscal_year):
@@ -235,10 +238,15 @@ def get_deducted_tax(taxable_vouchers, fiscal_year, tax_details):
def get_tds_amount(ldc, parties, inv, tax_details, fiscal_year_details, tax_deducted, vouchers):
tds_amount = 0
+ invoice_filters = {
+ 'name': ('in', vouchers),
+ 'docstatus': 1
+ }
- supp_credit_amt = frappe.db.get_value('Purchase Invoice', {
- 'name': ('in', vouchers), 'docstatus': 1, 'apply_tds': 1
- }, 'sum(net_total)') or 0.0
+ if not cint(tax_details.consider_party_ledger_amount):
+ invoice_filters.update({'apply_tds': 1})
+
+ supp_credit_amt = frappe.db.get_value('Purchase Invoice', invoice_filters, 'sum(net_total)') or 0.0
supp_jv_credit_amt = frappe.db.get_value('Journal Entry Account', {
'parent': ('in', vouchers), 'docstatus': 1,
@@ -255,6 +263,9 @@ def get_tds_amount(ldc, parties, inv, tax_details, fiscal_year_details, tax_dedu
cumulative_threshold = tax_details.get('cumulative_threshold', 0)
if ((threshold and inv.net_total >= threshold) or (cumulative_threshold and supp_credit_amt >= cumulative_threshold)):
+ if (cumulative_threshold and supp_credit_amt >= cumulative_threshold) and cint(tax_details.tax_on_excess_amount):
+ supp_credit_amt -= cumulative_threshold
+
if ldc and is_valid_certificate(
ldc.valid_from, ldc.valid_upto,
inv.get('posting_date') or inv.get('transaction_date'), tax_deducted,
@@ -263,6 +274,9 @@ def get_tds_amount(ldc, parties, inv, tax_details, fiscal_year_details, tax_dedu
tds_amount = get_ltds_amount(supp_credit_amt, 0, ldc.certificate_limit, ldc.rate, tax_details)
else:
tds_amount = supp_credit_amt * tax_details.rate / 100 if supp_credit_amt > 0 else 0
+
+ if cint(tax_details.round_off_tax_amount):
+ tds_amount = round(tds_amount)
return tds_amount
diff --git a/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py b/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py
index dd26be7c99..2ba22ca435 100644
--- a/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py
+++ b/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py
@@ -87,6 +87,31 @@ class TestTaxWithholdingCategory(unittest.TestCase):
for d in invoices:
d.cancel()
+ def test_tax_withholding_category_checks(self):
+ invoices = []
+ frappe.db.set_value("Supplier", "Test TDS Supplier3", "tax_withholding_category", "New TDS Category")
+
+ # First Invoice with no tds check
+ pi = create_purchase_invoice(supplier = "Test TDS Supplier3", rate = 20000, do_not_save=True)
+ pi.apply_tds = 0
+ pi.save()
+ pi.submit()
+ invoices.append(pi)
+
+ # Second Invoice will apply TDS checked
+ pi1 = create_purchase_invoice(supplier = "Test TDS Supplier3", rate = 20000)
+ pi1.submit()
+ invoices.append(pi1)
+
+ # Cumulative threshold is 30000
+ # Threshold calculation should be on both the invoices
+ # TDS should be applied only on 1000
+ self.assertEqual(pi1.taxes[0].tax_amount, 1000)
+
+ for d in invoices:
+ d.cancel()
+
+
def test_cumulative_threshold_tcs(self):
frappe.db.set_value("Customer", "Test TCS Customer", "tax_withholding_category", "Cumulative Threshold TCS")
invoices = []
@@ -195,7 +220,7 @@ def create_sales_invoice(**args):
def create_records():
# create a new suppliers
- for name in ['Test TDS Supplier', 'Test TDS Supplier1', 'Test TDS Supplier2']:
+ for name in ['Test TDS Supplier', 'Test TDS Supplier1', 'Test TDS Supplier2', 'Test TDS Supplier3']:
if frappe.db.exists('Supplier', name):
continue
@@ -311,3 +336,23 @@ def create_tax_with_holding_category():
'account': 'TDS - _TC'
}]
}).insert()
+
+ if not frappe.db.exists("Tax Withholding Category", "New TDS Category"):
+ frappe.get_doc({
+ "doctype": "Tax Withholding Category",
+ "name": "New TDS Category",
+ "category_name": "New TDS Category",
+ "round_off_tax_amount": 1,
+ "consider_party_ledger_amount": 1,
+ "tax_on_excess_amount": 1,
+ "rates": [{
+ 'fiscal_year': fiscal_year,
+ 'tax_withholding_rate': 10,
+ 'single_threshold': 0,
+ 'cumulative_threshold': 30000
+ }],
+ "accounts": [{
+ 'company': '_Test Company',
+ 'account': 'TDS - _TC'
+ }]
+ }).insert()
From b122a1eaa094c6e320dddd6c5b5f6716932f8028 Mon Sep 17 00:00:00 2001
From: Frappe PR Bot
Date: Tue, 27 Jul 2021 16:59:06 +0530
Subject: [PATCH 169/386] fix: reload manufacturing setting before patch
(#26641) (#26670)
(cherry picked from commit c8d7a8c781f6c448fd872427d611ffab70c136db)
Co-authored-by: Ankush
---
erpnext/patches/v13_0/add_missing_fg_item_for_stock_entry.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/erpnext/patches/v13_0/add_missing_fg_item_for_stock_entry.py b/erpnext/patches/v13_0/add_missing_fg_item_for_stock_entry.py
index 48999e6f99..d7ad1fc696 100644
--- a/erpnext/patches/v13_0/add_missing_fg_item_for_stock_entry.py
+++ b/erpnext/patches/v13_0/add_missing_fg_item_for_stock_entry.py
@@ -10,6 +10,7 @@ def execute():
if not frappe.db.has_column('Work Order', 'has_batch_no'):
return
+ frappe.reload_doc('manufacturing', 'doctype', 'manufacturing_settings')
if cint(frappe.db.get_single_value('Manufacturing Settings', 'make_serial_no_batch_from_work_order')):
return
@@ -107,4 +108,4 @@ def repost_future_sle_and_gle(doc):
"company": doc.company
})
- create_repost_item_valuation_entry(args)
\ No newline at end of file
+ create_repost_item_valuation_entry(args)
From af58ac9e104b0a278835880bcdebc47a4eaa38c7 Mon Sep 17 00:00:00 2001
From: Rohit Waghchaure
Date: Tue, 27 Jul 2021 18:43:20 +0530
Subject: [PATCH 170/386] fix: not able to add employee in the job card
---
erpnext/manufacturing/doctype/job_card/job_card.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/erpnext/manufacturing/doctype/job_card/job_card.py b/erpnext/manufacturing/doctype/job_card/job_card.py
index 420bb00803..69c7f5c614 100644
--- a/erpnext/manufacturing/doctype/job_card/job_card.py
+++ b/erpnext/manufacturing/doctype/job_card/job_card.py
@@ -192,11 +192,11 @@ class JobCard(Document):
"completed_qty": args.get("completed_qty") or 0.0
})
elif args.get("start_time"):
- new_args = {
+ new_args = frappe._dict({
"from_time": get_datetime(args.get("start_time")),
"operation": args.get("sub_operation"),
"completed_qty": 0.0
- }
+ })
if employees:
for name in employees:
From 56b81565fa3f2b1503c98678846372275635ce90 Mon Sep 17 00:00:00 2001
From: Rohit Waghchaure
Date: Fri, 23 Jul 2021 15:19:53 +0530
Subject: [PATCH 171/386] fix: added progress bar in repost item valuation
---
.../repost_item_valuation.js | 37 ++++++++++
.../repost_item_valuation.json | 34 ++++++++-
.../repost_item_valuation.py | 2 +-
erpnext/stock/stock_ledger.py | 71 ++++++++++++++-----
4 files changed, 124 insertions(+), 20 deletions(-)
diff --git a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.js b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.js
index b3e4286bcc..4cd40bf38e 100644
--- a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.js
+++ b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.js
@@ -29,13 +29,50 @@ frappe.ui.form.on('Repost Item Valuation', {
};
});
}
+
+ frm.trigger('setup_realtime_progress');
},
+
+ setup_realtime_progress: function(frm) {
+ frappe.realtime.on('item_reposting_progress', data => {
+ if (frm.doc.name !== data.name) {
+ return;
+ }
+
+ if (frm.doc.status == 'In Progress') {
+ frm.doc.current_index = data.current_index;
+ frm.doc.items_to_be_repost = data.items_to_be_repost;
+
+ frm.dashboard.reset();
+ frm.trigger('show_reposting_progress');
+ }
+ });
+ },
+
refresh: function(frm) {
if (frm.doc.status == "Failed" && frm.doc.docstatus==1) {
frm.add_custom_button(__('Restart'), function () {
frm.trigger("restart_reposting");
}).addClass("btn-primary");
}
+
+ frm.trigger('show_reposting_progress');
+ },
+
+ show_reposting_progress: function(frm) {
+ var bars = [];
+
+ let total_count = frm.doc.items_to_be_repost ? JSON.parse(frm.doc.items_to_be_repost).length : 0;
+ let progress = flt(cint(frm.doc.current_index) / total_count * 100, 2) || 0.5;
+ var title = __('Reposting Completed {0}%', [progress]);
+
+ bars.push({
+ 'title': title,
+ 'width': progress + '%',
+ 'progress_class': 'progress-bar-success'
+ });
+
+ frm.dashboard.add_progress(__('Reposting Progress'), bars);
},
restart_reposting: function(frm) {
diff --git a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.json b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.json
index 071fc86d9b..a800bf8701 100644
--- a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.json
+++ b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.json
@@ -21,7 +21,10 @@
"allow_zero_rate",
"amended_from",
"error_section",
- "error_log"
+ "error_log",
+ "items_to_be_repost",
+ "distinct_item_and_warehouse",
+ "current_index"
],
"fields": [
{
@@ -142,12 +145,39 @@
"fieldname": "allow_zero_rate",
"fieldtype": "Check",
"label": "Allow Zero Rate"
+ },
+ {
+ "fieldname": "items_to_be_repost",
+ "fieldtype": "Code",
+ "hidden": 1,
+ "label": "Items to Be Repost",
+ "no_copy": 1,
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "fieldname": "distinct_item_and_warehouse",
+ "fieldtype": "Code",
+ "hidden": 1,
+ "label": "Distinct Item and Warehouse",
+ "no_copy": 1,
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "fieldname": "current_index",
+ "fieldtype": "Int",
+ "hidden": 1,
+ "label": "Current Index",
+ "no_copy": 1,
+ "print_hide": 1,
+ "read_only": 1
}
],
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
- "modified": "2020-12-10 07:52:12.476589",
+ "modified": "2021-07-22 18:59:43.057878",
"modified_by": "Administrator",
"module": "Stock",
"name": "Repost Item Valuation",
diff --git a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py
index 5f31d9caf0..2e454a5159 100644
--- a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py
+++ b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py
@@ -80,7 +80,7 @@ def repost(doc):
def repost_sl_entries(doc):
if doc.based_on == 'Transaction':
- repost_future_sle(voucher_type=doc.voucher_type, voucher_no=doc.voucher_no,
+ repost_future_sle(doc=doc, voucher_type=doc.voucher_type, voucher_no=doc.voucher_no,
allow_negative_stock=doc.allow_negative_stock, via_landed_cost_voucher=doc.via_landed_cost_voucher)
else:
repost_future_sle(args=[frappe._dict({
diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py
index c15d1eda7d..8f9ec465e5 100644
--- a/erpnext/stock/stock_ledger.py
+++ b/erpnext/stock/stock_ledger.py
@@ -127,30 +127,24 @@ def make_entry(args, allow_negative_stock=False, via_landed_cost_voucher=False):
sle.submit()
return sle
-def repost_future_sle(args=None, voucher_type=None, voucher_no=None, allow_negative_stock=None, via_landed_cost_voucher=False):
+def repost_future_sle(args=None, doc=None, voucher_type=None, voucher_no=None, allow_negative_stock=None, via_landed_cost_voucher=False):
if not args and voucher_type and voucher_no:
- args = get_args_for_voucher(voucher_type, voucher_no)
+ args = get_items_to_be_repost(voucher_type, voucher_no, doc)
- distinct_item_warehouses = {}
- for i, d in enumerate(args):
- distinct_item_warehouses.setdefault((d.item_code, d.warehouse), frappe._dict({
- "reposting_status": False,
- "sle": d,
- "args_idx": i
- }))
+ distinct_item_warehouses = get_distinct_item_warehouse(args, doc)
- i = 0
+ i = get_current_index(doc) or 0
while i < len(args):
obj = update_entries_after({
- "item_code": args[i].item_code,
- "warehouse": args[i].warehouse,
- "posting_date": args[i].posting_date,
- "posting_time": args[i].posting_time,
+ "item_code": args[i].get('item_code'),
+ "warehouse": args[i].get('warehouse'),
+ "posting_date": args[i].get('posting_date'),
+ "posting_time": args[i].get('posting_time'),
"creation": args[i].get("creation"),
"distinct_item_warehouses": distinct_item_warehouses
}, allow_negative_stock=allow_negative_stock, via_landed_cost_voucher=via_landed_cost_voucher)
- distinct_item_warehouses[(args[i].item_code, args[i].warehouse)].reposting_status = True
+ distinct_item_warehouses[(args[i].get('item_code'), args[i].get('warehouse'))].reposting_status = True
if obj.new_items_found:
for item_wh, data in iteritems(distinct_item_warehouses):
@@ -159,11 +153,35 @@ def repost_future_sle(args=None, voucher_type=None, voucher_no=None, allow_negat
args.append(data.sle)
elif data.sle_changed and not data.reposting_status:
args[data.args_idx] = data.sle
-
+
data.sle_changed = False
i += 1
-def get_args_for_voucher(voucher_type, voucher_no):
+ if doc and i % 2 == 0:
+ update_args_in_repost_item_valuation(doc, i, args, distinct_item_warehouses)
+
+ if doc and args:
+ update_args_in_repost_item_valuation(doc, i, args, distinct_item_warehouses)
+
+def update_args_in_repost_item_valuation(doc, index, args, distinct_item_warehouses):
+ frappe.db.set_value(doc.doctype, doc.name, {
+ 'items_to_be_repost': json.dumps(args, default=str),
+ 'distinct_item_and_warehouse': json.dumps({str(k): v for k,v in distinct_item_warehouses.items()}, default=str),
+ 'current_index': index
+ })
+
+ frappe.db.commit()
+
+ frappe.publish_realtime('item_reposting_progress', {
+ 'name': doc.name,
+ 'items_to_be_repost': json.dumps(args, default=str),
+ 'current_index': index
+ })
+
+def get_items_to_be_repost(voucher_type, voucher_no, doc=None):
+ if doc and doc.items_to_be_repost:
+ return json.loads(doc.items_to_be_repost) or []
+
return frappe.db.get_all("Stock Ledger Entry",
filters={"voucher_type": voucher_type, "voucher_no": voucher_no},
fields=["item_code", "warehouse", "posting_date", "posting_time", "creation"],
@@ -171,6 +189,25 @@ def get_args_for_voucher(voucher_type, voucher_no):
group_by="item_code, warehouse"
)
+def get_distinct_item_warehouse(args=None, doc=None):
+ distinct_item_warehouses = {}
+ if doc and doc.distinct_item_and_warehouse:
+ distinct_item_warehouses = json.loads(doc.distinct_item_and_warehouse)
+ distinct_item_warehouses = {frappe.safe_eval(k): frappe._dict(v) for k, v in distinct_item_warehouses.items()}
+ else:
+ for i, d in enumerate(args):
+ distinct_item_warehouses.setdefault((d.item_code, d.warehouse), frappe._dict({
+ "reposting_status": False,
+ "sle": d,
+ "args_idx": i
+ }))
+
+ return distinct_item_warehouses
+
+def get_current_index(doc=None):
+ if doc and doc.current_index:
+ return doc.current_index
+
class update_entries_after(object):
"""
update valution rate and qty after transaction
From ac2e139d5bdfe58fb03ee73ef88cf70d855b8caf Mon Sep 17 00:00:00 2001
From: Raffael Meyer <14891507+barredterra@users.noreply.github.com>
Date: Tue, 27 Jul 2021 20:44:59 +0200
Subject: [PATCH 172/386] fix: force reload of Opportunity in patch (#26668)
---
erpnext/patches/v13_0/rename_issue_doctype_fields.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/patches/v13_0/rename_issue_doctype_fields.py b/erpnext/patches/v13_0/rename_issue_doctype_fields.py
index fa1dfed643..41c51c36dc 100644
--- a/erpnext/patches/v13_0/rename_issue_doctype_fields.py
+++ b/erpnext/patches/v13_0/rename_issue_doctype_fields.py
@@ -37,7 +37,7 @@ def execute():
if frappe.db.exists('DocType', 'Opportunity'):
opportunities = frappe.db.get_all('Opportunity', fields=['name', 'mins_to_first_response'], order_by='creation desc')
- frappe.reload_doc('crm', 'doctype', 'opportunity')
+ frappe.reload_doctype('Opportunity', force=True)
rename_field('Opportunity', 'mins_to_first_response', 'first_response_time')
# change fieldtype to duration
From 64af124f88f2133790cd4d7f160f1fac9afbc409 Mon Sep 17 00:00:00 2001
From: Deepesh Garg
Date: Wed, 28 Jul 2021 10:43:02 +0530
Subject: [PATCH 173/386] fix(minor): Consider grand total for threshold check
---
.../tax_withholding_category/tax_withholding_category.py | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
index 45c8e1b49f..020de3c3f3 100644
--- a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
+++ b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
@@ -243,10 +243,13 @@ def get_tds_amount(ldc, parties, inv, tax_details, fiscal_year_details, tax_dedu
'docstatus': 1
}
+ field = 'sum(net_total)'
+
if not cint(tax_details.consider_party_ledger_amount):
invoice_filters.update({'apply_tds': 1})
+ field = 'sum(grand_total)'
- supp_credit_amt = frappe.db.get_value('Purchase Invoice', invoice_filters, 'sum(net_total)') or 0.0
+ supp_credit_amt = frappe.db.get_value('Purchase Invoice', invoice_filters, field) or 0.0
supp_jv_credit_amt = frappe.db.get_value('Journal Entry Account', {
'parent': ('in', vouchers), 'docstatus': 1,
From 1c9e516092e415ae27441b26e0a632427cd81f31 Mon Sep 17 00:00:00 2001
From: Deepesh Garg
Date: Wed, 28 Jul 2021 11:38:44 +0530
Subject: [PATCH 174/386] fix: GL Entries for discount amount with item qty
greater than 1
---
erpnext/controllers/accounts_controller.py | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index 3d048c3686..8199b1040f 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -845,6 +845,7 @@ class AccountsController(TransactionBase):
for item in self.get("items"):
if item.get('discount_amount') and item.get('discount_account'):
+ discount_amount = item.discount_amount * item.qty
if self.doctype == "Purchase Invoice":
income_or_expense_account = (item.expense_account
if (not item.enable_deferred_expense or self.is_return)
@@ -859,8 +860,9 @@ class AccountsController(TransactionBase):
self.get_gl_dict({
"account": item.discount_account,
"against": supplier_or_customer,
- dr_or_cr: flt(item.discount_amount),
- dr_or_cr + "_in_account_currency": flt(item.discount_amount),
+ dr_or_cr: flt(discount_amount, item.precision('discount_amount')),
+ dr_or_cr + "_in_account_currency": flt(discount_amount * self.get('conversion_rate'),
+ item.precision('discount_amount')),
"cost_center": item.cost_center,
"project": item.project
}, account_currency, item=item)
@@ -871,8 +873,9 @@ class AccountsController(TransactionBase):
self.get_gl_dict({
"account": income_or_expense_account,
"against": supplier_or_customer,
- rev_dr_cr: flt(item.discount_amount),
- rev_dr_cr + "_in_account_currency": flt(item.discount_amount),
+ rev_dr_cr: flt(discount_amount, item.precision('discount_amount')),
+ rev_dr_cr + "_in_account_currency": flt(discount_amount * self.get('conversion_rate'),
+ item.precision('discount_amount')),
"cost_center": item.cost_center,
"project": item.project or self.project
}, account_currency, item=item)
From 93502499412e6a268f5d570b33b131af74b328f1 Mon Sep 17 00:00:00 2001
From: Deepesh Garg
Date: Wed, 28 Jul 2021 12:57:59 +0530
Subject: [PATCH 175/386] fix: Chnage fieldtype from data to check
---
.../tax_withholding_category.json | 4 ++--
erpnext/patches.txt | 1 +
erpnext/patches/v13_0/update_tds_check_field.py | 8 ++++++++
3 files changed, 11 insertions(+), 2 deletions(-)
create mode 100644 erpnext/patches/v13_0/update_tds_check_field.py
diff --git a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.json b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.json
index 331770fbe8..153906ffe9 100644
--- a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.json
+++ b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.json
@@ -94,7 +94,7 @@
{
"description": "Checking this will round off the tax amount to the nearest integer",
"fieldname": "round_off_tax_amount",
- "fieldtype": "Data",
+ "fieldtype": "Check",
"label": "Round Off Tax Amount",
"show_days": 1,
"show_seconds": 1
@@ -102,7 +102,7 @@
],
"index_web_pages_for_search": 1,
"links": [],
- "modified": "2021-07-26 21:47:34.396071",
+ "modified": "2021-07-27 21:47:34.396071",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Tax Withholding Category",
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index b891719b02..32763754d2 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -294,3 +294,4 @@ erpnext.patches.v13_0.update_level_in_bom #1234sswef
erpnext.patches.v13_0.add_missing_fg_item_for_stock_entry
erpnext.patches.v13_0.update_subscription_status_in_memberships
erpnext.patches.v13_0.update_export_type_for_gst
+erpnext.patches.v13_0.update_tds_check_field #3
diff --git a/erpnext/patches/v13_0/update_tds_check_field.py b/erpnext/patches/v13_0/update_tds_check_field.py
new file mode 100644
index 0000000000..16bf76d530
--- /dev/null
+++ b/erpnext/patches/v13_0/update_tds_check_field.py
@@ -0,0 +1,8 @@
+import frappe
+
+def execute():
+ if frappe.db.has_column("Tax Withholding Category", "round_off_tax_amount"):
+ frappe.db.sql("""
+ UPDATE `tabTax Withholding Category` set round_off_tax_amount = 0
+ WHERE round_off_tax_amount IS NULL
+ """)
\ No newline at end of file
From 90c5cb0a3106c173c0607b9193d31d7cd4749e9f Mon Sep 17 00:00:00 2001
From: Afshan <33727827+AfshanKhan@users.noreply.github.com>
Date: Wed, 28 Jul 2021 13:42:33 +0530
Subject: [PATCH 176/386] fix: documentation link for E Invoicing (#26685)
---
.../regional/doctype/e_invoice_settings/e_invoice_settings.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/regional/doctype/e_invoice_settings/e_invoice_settings.js b/erpnext/regional/doctype/e_invoice_settings/e_invoice_settings.js
index cc2d9f06d2..54e488610d 100644
--- a/erpnext/regional/doctype/e_invoice_settings/e_invoice_settings.js
+++ b/erpnext/regional/doctype/e_invoice_settings/e_invoice_settings.js
@@ -3,7 +3,7 @@
frappe.ui.form.on('E Invoice Settings', {
refresh(frm) {
- const docs_link = 'https://docs.erpnext.com/docs/user/manual/en/regional/india/setup-e-invoicing';
+ const docs_link = 'https://docs.erpnext.com/docs/v13/user/manual/en/regional/india/setup-e-invoicing';
frm.dashboard.set_headline(
__("Read {0} for more information on E Invoicing features.", [`documentation `])
);
From fa8e6ac7cd604fffaeecb4a4e73f4b08a20ad2b2 Mon Sep 17 00:00:00 2001
From: Deepesh Garg
Date: Wed, 28 Jul 2021 15:30:05 +0530
Subject: [PATCH 177/386] fix: Patch
---
erpnext/patches/v13_0/update_tds_check_field.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/erpnext/patches/v13_0/update_tds_check_field.py b/erpnext/patches/v13_0/update_tds_check_field.py
index 16bf76d530..3d149586a0 100644
--- a/erpnext/patches/v13_0/update_tds_check_field.py
+++ b/erpnext/patches/v13_0/update_tds_check_field.py
@@ -1,7 +1,8 @@
import frappe
def execute():
- if frappe.db.has_column("Tax Withholding Category", "round_off_tax_amount"):
+ if frappe.db.has_table("Tax Withholding Category") \
+ and frappe.db.has_column("Tax Withholding Category", "round_off_tax_amount"):
frappe.db.sql("""
UPDATE `tabTax Withholding Category` set round_off_tax_amount = 0
WHERE round_off_tax_amount IS NULL
From 1b6dd84c0a25e143ec3ac92b3f439d6d90ca6573 Mon Sep 17 00:00:00 2001
From: Frappe PR Bot
Date: Wed, 28 Jul 2021 18:11:11 +0530
Subject: [PATCH 178/386] fix(bom): remove manual permission checking (#26689)
(#26690)
get_list does the permission checking.
(cherry picked from commit d95f16ac8fb084e33ab936545fc60acd6a4ff618)
Co-authored-by: Ankush
---
erpnext/manufacturing/doctype/bom/bom.py | 9 +--------
1 file changed, 1 insertion(+), 8 deletions(-)
diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py
index af081c449c..ebd9ae2dc5 100644
--- a/erpnext/manufacturing/doctype/bom/bom.py
+++ b/erpnext/manufacturing/doctype/bom/bom.py
@@ -1069,13 +1069,6 @@ def item_query(doctype, txt, searchfield, start, page_len, filters):
if barcodes:
or_cond_filters["name"] = ("in", barcodes)
- for cond in get_match_cond(doctype, as_condition=False):
- for key, value in cond.items():
- if key == doctype:
- key = "name"
-
- query_filters[key] = ("in", value)
-
if filters and filters.get("item_code"):
has_variants = frappe.get_cached_value("Item", filters.get("item_code"), "has_variants")
if not has_variants:
@@ -1084,7 +1077,7 @@ def item_query(doctype, txt, searchfield, start, page_len, filters):
if filters and filters.get("is_stock_item"):
query_filters["is_stock_item"] = 1
- return frappe.get_all("Item",
+ return frappe.get_list("Item",
fields = fields, filters=query_filters,
or_filters = or_cond_filters, order_by=order_by,
limit_start=start, limit_page_length=page_len, as_list=1)
From b1350af1f64868244ec7dc9838fb81fa4bbec1b4 Mon Sep 17 00:00:00 2001
From: Anupam
Date: Wed, 28 Jul 2021 18:51:19 +0530
Subject: [PATCH 179/386] fix: setup wizard
---
.../setup/setup_wizard/operations/company_setup.py | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/erpnext/setup/setup_wizard/operations/company_setup.py b/erpnext/setup/setup_wizard/operations/company_setup.py
index 4edf9485dc..4833d93c4a 100644
--- a/erpnext/setup/setup_wizard/operations/company_setup.py
+++ b/erpnext/setup/setup_wizard/operations/company_setup.py
@@ -45,9 +45,16 @@ def enable_shopping_cart(args):
def create_email_digest():
from frappe.utils.user import get_system_managers
system_managers = get_system_managers(only_name=True)
+
if not system_managers:
return
+ recipients = []
+ for d in system_managers:
+ recipients.append({
+ 'recipient': d
+ })
+
companies = frappe.db.sql_list("select name FROM `tabCompany`")
for company in companies:
if not frappe.db.exists("Email Digest", "Default Weekly Digest - " + company):
@@ -56,7 +63,7 @@ def create_email_digest():
"name": "Default Weekly Digest - " + company,
"company": company,
"frequency": "Weekly",
- "recipient_list": "\n".join(system_managers)
+ "recipients": recipients
})
for df in edigest.meta.get("fields", {"fieldtype": "Check"}):
@@ -72,7 +79,7 @@ def create_email_digest():
"name": "Scheduler Errors",
"company": companies[0],
"frequency": "Daily",
- "recipient_list": "\n".join(system_managers),
+ "recipients": recipients,
"scheduler_errors": 1,
"enabled": 1
})
From e5fea372afb1c1295811ff18a570c9acf1506c50 Mon Sep 17 00:00:00 2001
From: Anupam
Date: Thu, 29 Jul 2021 11:05:38 +0530
Subject: [PATCH 180/386] fix: frappe linter
---
erpnext/setup/doctype/email_digest/email_digest.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/erpnext/setup/doctype/email_digest/email_digest.js b/erpnext/setup/doctype/email_digest/email_digest.js
index 84e2d0d52a..2e415af282 100644
--- a/erpnext/setup/doctype/email_digest/email_digest.js
+++ b/erpnext/setup/doctype/email_digest/email_digest.js
@@ -11,8 +11,8 @@ frappe.ui.form.on("Email Digest", {
name: frm.doc.name
},
callback: function(r) {
- var d = new frappe.ui.Dialog({
- title: __('Email Digest: ') + frm.doc.name,
+ let d = new frappe.ui.Dialog({
+ title: __('Email Digest: {0}', [frm.doc.name]),
width: 800
});
$(d.body).html(r.message);
From 8859574aab0553406964859250e0e4bbe470ee8a Mon Sep 17 00:00:00 2001
From: Ankush
Date: Thu, 29 Jul 2021 11:09:22 +0530
Subject: [PATCH 181/386] feat: don't recompute taxes (#26694)
---
.../sales_taxes_and_charges.json | 14 ++++++++++++--
erpnext/controllers/taxes_and_totals.py | 7 ++++---
2 files changed, 16 insertions(+), 5 deletions(-)
diff --git a/erpnext/accounts/doctype/sales_taxes_and_charges/sales_taxes_and_charges.json b/erpnext/accounts/doctype/sales_taxes_and_charges/sales_taxes_and_charges.json
index 1b7a0fe562..cfdb167bbc 100644
--- a/erpnext/accounts/doctype/sales_taxes_and_charges/sales_taxes_and_charges.json
+++ b/erpnext/accounts/doctype/sales_taxes_and_charges/sales_taxes_and_charges.json
@@ -27,7 +27,8 @@
"base_tax_amount",
"base_total",
"base_tax_amount_after_discount_amount",
- "item_wise_tax_detail"
+ "item_wise_tax_detail",
+ "dont_recompute_tax"
],
"fields": [
{
@@ -200,13 +201,22 @@
"fieldname": "included_in_paid_amount",
"fieldtype": "Check",
"label": "Considered In Paid Amount"
+ },
+ {
+ "default": "0",
+ "fieldname": "dont_recompute_tax",
+ "fieldtype": "Check",
+ "hidden": 1,
+ "label": "Dont Recompute tax",
+ "print_hide": 1,
+ "read_only": 1
}
],
"idx": 1,
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
- "modified": "2021-06-14 01:44:36.899147",
+ "modified": "2021-07-27 12:40:59.051803",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Taxes and Charges",
diff --git a/erpnext/controllers/taxes_and_totals.py b/erpnext/controllers/taxes_and_totals.py
index 56da5b71da..099c7d4346 100644
--- a/erpnext/controllers/taxes_and_totals.py
+++ b/erpnext/controllers/taxes_and_totals.py
@@ -152,7 +152,7 @@ class calculate_taxes_and_totals(object):
validate_taxes_and_charges(tax)
validate_inclusive_tax(tax, self.doc)
- if not self.doc.get('is_consolidated'):
+ if not (self.doc.get('is_consolidated') or tax.get("dont_recompute_tax")):
tax.item_wise_tax_detail = {}
tax_fields = ["total", "tax_amount_after_discount_amount",
@@ -347,7 +347,7 @@ class calculate_taxes_and_totals(object):
elif tax.charge_type == "On Item Quantity":
current_tax_amount = tax_rate * item.qty
- if not self.doc.get("is_consolidated"):
+ if not (self.doc.get("is_consolidated") or tax.get("dont_recompute_tax")):
self.set_item_wise_tax(item, tax, tax_rate, current_tax_amount)
return current_tax_amount
@@ -455,7 +455,8 @@ class calculate_taxes_and_totals(object):
def _cleanup(self):
if not self.doc.get('is_consolidated'):
for tax in self.doc.get("taxes"):
- tax.item_wise_tax_detail = json.dumps(tax.item_wise_tax_detail, separators=(',', ':'))
+ if not tax.get("dont_recompute_tax"):
+ tax.item_wise_tax_detail = json.dumps(tax.item_wise_tax_detail, separators=(',', ':'))
def set_discount_amount(self):
if self.doc.additional_discount_percentage:
From 6a71955b998f30e3477b9847cd8fec4b806b69bf Mon Sep 17 00:00:00 2001
From: Frappe PR Bot
Date: Thu, 29 Jul 2021 14:28:13 +0530
Subject: [PATCH 182/386] chore: change location of backport action (#26705)
(#26707)
(cherry picked from commit e906acdc49a5131680301eb056f16c7821b0b539)
Co-authored-by: Ankush
---
.github/workflows/backport.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml
index cc98f4544f..1d180f251e 100644
--- a/.github/workflows/backport.yml
+++ b/.github/workflows/backport.yml
@@ -12,7 +12,7 @@ jobs:
- name: Checkout Actions
uses: actions/checkout@v2
with:
- repository: "ankush/backport"
+ repository: "frappe/backport"
path: ./actions
ref: develop
- name: Install Actions
From 4c681592bf9d7933f872dbec460cb8942535a934 Mon Sep 17 00:00:00 2001
From: Deepesh Garg
Date: Thu, 29 Jul 2021 15:26:19 +0530
Subject: [PATCH 183/386] fix: TDS calculation for first threshold breach for
TDS category 194Q
---
.../tax_withholding_category/tax_withholding_category.py | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
index 020de3c3f3..481ef285e7 100644
--- a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
+++ b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
@@ -148,6 +148,7 @@ def get_lower_deduction_certificate(fiscal_year, pan_no):
def get_tax_amount(party_type, parties, inv, tax_details, fiscal_year_details, pan_no=None):
fiscal_year = fiscal_year_details[0]
+
vouchers = get_invoice_vouchers(parties, fiscal_year, inv.company, party_type=party_type)
advance_vouchers = get_advance_vouchers(parties, fiscal_year, inv.company, party_type=party_type)
taxable_vouchers = vouchers + advance_vouchers
@@ -267,7 +268,11 @@ def get_tds_amount(ldc, parties, inv, tax_details, fiscal_year_details, tax_dedu
if ((threshold and inv.net_total >= threshold) or (cumulative_threshold and supp_credit_amt >= cumulative_threshold)):
if (cumulative_threshold and supp_credit_amt >= cumulative_threshold) and cint(tax_details.tax_on_excess_amount):
- supp_credit_amt -= cumulative_threshold
+ # Get net total again as TDS is calculated on net total
+ # Grand is used to just check for threshold breach
+ net_total = frappe.db.get_value('Purchase Invoice', invoice_filters, 'sum(net_total)') or 0.0
+ net_total += inv.net_total
+ supp_credit_amt = net_total - cumulative_threshold
if ldc and is_valid_certificate(
ldc.valid_from, ldc.valid_upto,
From e39bbc85e11d848a2dd248c546b723f914d3bede Mon Sep 17 00:00:00 2001
From: Saqib
Date: Thu, 29 Jul 2021 15:46:25 +0530
Subject: [PATCH 184/386] fix: cannot cancel payment entry if linked with
invoices (#26703)
---
erpnext/accounts/doctype/payment_entry/payment_entry.js | 2 ++
1 file changed, 2 insertions(+)
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.js b/erpnext/accounts/doctype/payment_entry/payment_entry.js
index d3ac3a6676..439b1edbce 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.js
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.js
@@ -7,6 +7,8 @@ cur_frm.cscript.tax_table = "Advance Taxes and Charges";
frappe.ui.form.on('Payment Entry', {
onload: function(frm) {
+ frm.ignore_doctypes_on_cancel_all = ['Sales Invoice', 'Purchase Invoice'];
+
if(frm.doc.__islocal) {
if (!frm.doc.paid_from) frm.set_value("paid_from_account_currency", null);
if (!frm.doc.paid_to) frm.set_value("paid_to_account_currency", null);
From 379ce70126205d3e489680549aec51cc6722aa6a Mon Sep 17 00:00:00 2001
From: Rohit Waghchaure
Date: Thu, 29 Jul 2021 17:02:06 +0530
Subject: [PATCH 185/386] fix: remove cancelled entries from Stock and Account
Value comparison report
---
.../stock_and_account_value_comparison.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/erpnext/stock/report/stock_and_account_value_comparison/stock_and_account_value_comparison.py b/erpnext/stock/report/stock_and_account_value_comparison/stock_and_account_value_comparison.py
index 14d543b174..bfc4471b9a 100644
--- a/erpnext/stock/report/stock_and_account_value_comparison/stock_and_account_value_comparison.py
+++ b/erpnext/stock/report/stock_and_account_value_comparison/stock_and_account_value_comparison.py
@@ -22,6 +22,7 @@ def get_data(report_filters):
data = []
filters = {
+ "is_cancelled": 0,
"company": report_filters.company,
"posting_date": ("<=", report_filters.as_on_date)
}
@@ -34,7 +35,7 @@ def get_data(report_filters):
key = (d.voucher_type, d.voucher_no)
gl_data = voucher_wise_gl_data.get(key) or {}
d.account_value = gl_data.get("account_value", 0)
- d.difference_value = (d.stock_value - d.account_value)
+ d.difference_value = abs(d.stock_value - d.account_value)
if abs(d.difference_value) > 0.1:
data.append(d)
From 19a6d809272ab4efeb6ef57d45d47b71f6d8fec6 Mon Sep 17 00:00:00 2001
From: Deepesh Garg
Date: Thu, 29 Jul 2021 18:47:16 +0530
Subject: [PATCH 186/386] fix: Parent condition in pricing rules
---
erpnext/accounts/doctype/pricing_rule/utils.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/accounts/doctype/pricing_rule/utils.py b/erpnext/accounts/doctype/pricing_rule/utils.py
index b54d0e73a8..94abf3b3c0 100644
--- a/erpnext/accounts/doctype/pricing_rule/utils.py
+++ b/erpnext/accounts/doctype/pricing_rule/utils.py
@@ -168,7 +168,7 @@ def _get_tree_conditions(args, parenttype, table, allow_blank=True):
frappe.throw(_("Invalid {0}").format(args.get(field)))
parent_groups = frappe.db.sql_list("""select name from `tab%s`
- where lft>=%s and rgt<=%s""" % (parenttype, '%s', '%s'), (lft, rgt))
+ where lft<=%s and rgt>=%s""" % (parenttype, '%s', '%s'), (lft, rgt))
if parenttype in ["Customer Group", "Item Group", "Territory"]:
parent_field = "parent_{0}".format(frappe.scrub(parenttype))
From 1011c1b01acf5f606de2f9936bf9ea7411f1f53e Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Fri, 9 Jul 2021 01:44:34 +0530
Subject: [PATCH 187/386] fix: Clear Payment Schedule if PI has default Payment
Schedule, but linked PO doensn't
---
.../purchase_invoice/purchase_invoice.py | 73 +++++++++++++++++++
1 file changed, 73 insertions(+)
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
index f7992797ed..147785a080 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
@@ -1142,6 +1142,79 @@ class PurchaseInvoice(BuyingController):
if update:
self.db_set('status', self.status, update_modified = update_modified)
+@frappe.whitelist()
+def set_payment_terms_from_po(doc):
+ if isinstance(doc, six.string_types):
+ doc = json.loads(doc)
+
+ purchase_order = doc.get('items')[0].get('purchase_order')
+
+ if purchase_order and all_items_have_same_po(doc, purchase_order):
+ purchase_order = frappe.get_cached_doc('Purchase Order', purchase_order)
+ else:
+ return
+
+ if has_default_payment_terms(doc) and not has_default_payment_terms(purchase_order):
+ doc['payment_schedule'] = []
+ doc['payment_terms_template'] = purchase_order.payment_terms_template
+
+ for schedule in purchase_order.payment_schedule:
+ payment_schedule = {
+ 'payment_term': schedule.payment_term,
+ 'due_date': schedule.due_date,
+ 'invoice_portion': schedule.invoice_portion,
+ 'discount_type': schedule.discount_type,
+ 'discount': schedule.discount,
+ 'base_payment_amount': schedule.base_payment_amount,
+ 'payment_amount': schedule.payment_amount,
+ 'outstanding': schedule.outstanding
+ }
+ doc['payment_schedule'].append(payment_schedule)
+
+ return doc
+
+def all_items_have_same_po(doc, purchase_order):
+ for item in doc.get('items'):
+ if item.get('purchase_order') != purchase_order:
+ return False
+
+ return True
+
+def has_default_payment_terms(doc):
+ if doc.get('payment_schedule')[0].get('invoice_portion') == 100:
+ return True
+ return False
+
+# to get details of purchase invoice/receipt from which this doc was created for exchange rate difference handling
+def get_purchase_document_details(doc):
+ if doc.doctype == 'Purchase Invoice':
+ doc_reference = 'purchase_receipt'
+ items_reference = 'pr_detail'
+ parent_doctype = 'Purchase Receipt'
+ child_doctype = 'Purchase Receipt Item'
+ else:
+ doc_reference = 'purchase_invoice'
+ items_reference = 'purchase_invoice_item'
+ parent_doctype = 'Purchase Invoice'
+ child_doctype = 'Purchase Invoice Item'
+
+ purchase_receipts_or_invoices = []
+ items = []
+
+ for item in doc.get('items'):
+ if item.get(doc_reference):
+ purchase_receipts_or_invoices.append(item.get(doc_reference))
+ if item.get(items_reference):
+ items.append(item.get(items_reference))
+
+ exchange_rate_map = frappe._dict(frappe.get_all(parent_doctype, filters={'name': ('in',
+ purchase_receipts_or_invoices)}, fields=['name', 'conversion_rate'], as_list=1))
+
+ net_rate_map = frappe._dict(frappe.get_all(child_doctype, filters={'name': ('in',
+ items)}, fields=['name', 'net_rate'], as_list=1))
+
+ return exchange_rate_map, net_rate_map
+
def get_list_context(context=None):
from erpnext.controllers.website_list_for_contact import get_list_context
list_context = get_list_context(context)
From b389c9e3759d8e62b2c7a7721c4d6d8a24c8fb77 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Sat, 17 Jul 2021 22:53:21 +0530
Subject: [PATCH 188/386] fix: Fetch Payment Terms from Sales/Purchase Orders
---
.../purchase_invoice/purchase_invoice.py | 43 -------------------
.../doctype/purchase_order/purchase_order.py | 12 +++---
erpnext/controllers/accounts_controller.py | 43 +++++++++++++++++++
.../doctype/sales_order/sales_order.py | 6 +++
.../doctype/delivery_note/delivery_note.py | 6 +++
.../purchase_receipt/purchase_receipt.py | 5 +++
6 files changed, 66 insertions(+), 49 deletions(-)
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
index 147785a080..28a9bddc42 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
@@ -1142,49 +1142,6 @@ class PurchaseInvoice(BuyingController):
if update:
self.db_set('status', self.status, update_modified = update_modified)
-@frappe.whitelist()
-def set_payment_terms_from_po(doc):
- if isinstance(doc, six.string_types):
- doc = json.loads(doc)
-
- purchase_order = doc.get('items')[0].get('purchase_order')
-
- if purchase_order and all_items_have_same_po(doc, purchase_order):
- purchase_order = frappe.get_cached_doc('Purchase Order', purchase_order)
- else:
- return
-
- if has_default_payment_terms(doc) and not has_default_payment_terms(purchase_order):
- doc['payment_schedule'] = []
- doc['payment_terms_template'] = purchase_order.payment_terms_template
-
- for schedule in purchase_order.payment_schedule:
- payment_schedule = {
- 'payment_term': schedule.payment_term,
- 'due_date': schedule.due_date,
- 'invoice_portion': schedule.invoice_portion,
- 'discount_type': schedule.discount_type,
- 'discount': schedule.discount,
- 'base_payment_amount': schedule.base_payment_amount,
- 'payment_amount': schedule.payment_amount,
- 'outstanding': schedule.outstanding
- }
- doc['payment_schedule'].append(payment_schedule)
-
- return doc
-
-def all_items_have_same_po(doc, purchase_order):
- for item in doc.get('items'):
- if item.get('purchase_order') != purchase_order:
- return False
-
- return True
-
-def has_default_payment_terms(doc):
- if doc.get('payment_schedule')[0].get('invoice_portion') == 100:
- return True
- return False
-
# to get details of purchase invoice/receipt from which this doc was created for exchange rate difference handling
def get_purchase_document_details(doc):
if doc.doctype == 'Purchase Invoice':
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py
index eaa502ff7f..a0bac51046 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.py
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.py
@@ -443,6 +443,8 @@ def make_purchase_invoice_from_portal(purchase_order_name):
frappe.response.location = '/purchase-invoices/' + doc.name
def get_mapped_purchase_invoice(source_name, target_doc=None, ignore_permissions=False):
+ from erpnext.controllers.accounts_controller import fetch_payment_terms_from_order
+
def postprocess(source, target):
target.flags.ignore_permissions = ignore_permissions
set_missing_values(source, target)
@@ -489,15 +491,13 @@ def get_mapped_purchase_invoice(source_name, target_doc=None, ignore_permissions
},
}
- if frappe.get_single("Accounts Settings").automatically_fetch_payment_terms == 1:
- fields["Payment Schedule"] = {
- "doctype": "Payment Schedule",
- "add_if_empty": True
- }
-
doc = get_mapped_doc("Purchase Order", source_name, fields,
target_doc, postprocess, ignore_permissions=ignore_permissions)
+ automatically_fetch_payment_terms = cint(frappe.db.get_single_value('Accounts Settings', 'automatically_fetch_payment_terms'))
+ if automatically_fetch_payment_terms:
+ fetch_payment_terms_from_order(doc)
+
return doc
@frappe.whitelist()
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index cdd865ac4a..f7ea77bae4 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -1803,3 +1803,46 @@ def validate_regional(doc):
@erpnext.allow_regional
def validate_einvoice_fields(doc):
pass
+
+def fetch_payment_terms_from_order(doc):
+ """
+ Fetch Payment Terms from Purchase/Sales Order on creating a new Purchase/Sales Invoice.
+ """
+
+ if doc.doctype == "Sales Invoice":
+ po_or_so = doc.get('items')[0].get('sales_order')
+ po_or_so_doctype = "Sales Order"
+ po_or_so_doctype_name = "sales_order"
+ else:
+ po_or_so = doc.get('items')[0].get('purchase_order')
+ po_or_so_doctype = "Purchase Order"
+ po_or_so_doctype_name = "purchase_order"
+
+ if po_or_so and all_items_have_same_po_or_so(doc, po_or_so, po_or_so_doctype_name):
+ po_or_so = frappe.get_cached_doc(po_or_so_doctype, po_or_so)
+ else:
+ doc.set_payment_schedule()
+ return
+
+ doc.payment_schedule = []
+ doc.payment_terms_template = po_or_so.payment_terms_template
+
+ for schedule in po_or_so.payment_schedule:
+ payment_schedule = {
+ 'payment_term': schedule.payment_term,
+ 'due_date': schedule.due_date,
+ 'invoice_portion': schedule.invoice_portion,
+ 'discount_type': schedule.discount_type,
+ 'discount': schedule.discount,
+ 'base_payment_amount': schedule.base_payment_amount,
+ 'payment_amount': schedule.payment_amount,
+ 'outstanding': schedule.outstanding
+ }
+ doc.append("payment_schedule", payment_schedule)
+
+def all_items_have_same_po_or_so(doc, po_or_so, po_or_so_fieldname):
+ for item in doc.get('items'):
+ if item.get(po_or_so_fieldname) != po_or_so:
+ return False
+
+ return True
\ No newline at end of file
diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py
index 41f57a34d3..a58c381df3 100755
--- a/erpnext/selling/doctype/sales_order/sales_order.py
+++ b/erpnext/selling/doctype/sales_order/sales_order.py
@@ -621,6 +621,8 @@ def make_delivery_note(source_name, target_doc=None, skip_item_mapping=False):
@frappe.whitelist()
def make_sales_invoice(source_name, target_doc=None, ignore_permissions=False):
+ from erpnext.controllers.accounts_controller import fetch_payment_terms_from_order
+
def postprocess(source, target):
set_missing_values(source, target)
#Get the advance paid Journal Entries in Sales Invoice Advance
@@ -693,6 +695,10 @@ def make_sales_invoice(source_name, target_doc=None, ignore_permissions=False):
}
}, target_doc, postprocess, ignore_permissions=ignore_permissions)
+ automatically_fetch_payment_terms = cint(frappe.db.get_single_value('Accounts Settings', 'automatically_fetch_payment_terms'))
+ if automatically_fetch_payment_terms:
+ fetch_payment_terms_from_order(doclist)
+
return doclist
@frappe.whitelist()
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.py b/erpnext/stock/doctype/delivery_note/delivery_note.py
index 4808e948fc..1628f93019 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.py
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.py
@@ -414,6 +414,8 @@ def get_returned_qty_map(delivery_note):
@frappe.whitelist()
def make_sales_invoice(source_name, target_doc=None):
+ from erpnext.controllers.accounts_controller import fetch_payment_terms_from_order
+
doc = frappe.get_doc('Delivery Note', source_name)
to_make_invoice_qty_map = {}
@@ -503,6 +505,10 @@ def make_sales_invoice(source_name, target_doc=None):
}
}, target_doc, set_missing_values)
+ automatically_fetch_payment_terms = cint(frappe.db.get_single_value('Accounts Settings', 'automatically_fetch_payment_terms'))
+ if automatically_fetch_payment_terms:
+ fetch_payment_terms_from_order(doc)
+
return doc
@frappe.whitelist()
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
index 82c87a83a5..cf6cac273f 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
@@ -583,6 +583,7 @@ def update_billing_percentage(pr_doc, update_modified=True):
@frappe.whitelist()
def make_purchase_invoice(source_name, target_doc=None):
from erpnext.accounts.party import get_payment_terms_template
+ from erpnext.controllers.accounts_controller import fetch_payment_terms_from_order
doc = frappe.get_doc('Purchase Receipt', source_name)
returned_qty_map = get_returned_qty_map(source_name)
@@ -654,6 +655,10 @@ def make_purchase_invoice(source_name, target_doc=None):
}
}, target_doc, set_missing_values)
+ automatically_fetch_payment_terms = cint(frappe.db.get_single_value('Accounts Settings', 'automatically_fetch_payment_terms'))
+ if automatically_fetch_payment_terms:
+ fetch_payment_terms_from_order(doclist)
+
return doclist
def get_invoiced_qty_map(purchase_receipt):
From 6333c3bee5b4aaa95bc289519e8341361af19ff6 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Sat, 17 Jul 2021 22:55:24 +0530
Subject: [PATCH 189/386] fix: Remove unused imports
From def7cc6cb3584ce32e8351e8b7faeb49a955a052 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Thu, 22 Jul 2021 05:57:42 +0530
Subject: [PATCH 190/386] fix: Modify set_payment_schedule() to include
fetch_payment_terms_from_order()
---
.../doctype/purchase_order/purchase_order.py | 4 +-
erpnext/controllers/accounts_controller.py | 111 +++++++++++-------
.../doctype/sales_order/sales_order.py | 4 +-
.../doctype/delivery_note/delivery_note.py | 4 +-
.../purchase_receipt/purchase_receipt.py | 3 +-
5 files changed, 70 insertions(+), 56 deletions(-)
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py
index a0bac51046..f68d81909a 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.py
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.py
@@ -443,8 +443,6 @@ def make_purchase_invoice_from_portal(purchase_order_name):
frappe.response.location = '/purchase-invoices/' + doc.name
def get_mapped_purchase_invoice(source_name, target_doc=None, ignore_permissions=False):
- from erpnext.controllers.accounts_controller import fetch_payment_terms_from_order
-
def postprocess(source, target):
target.flags.ignore_permissions = ignore_permissions
set_missing_values(source, target)
@@ -496,7 +494,7 @@ def get_mapped_purchase_invoice(source_name, target_doc=None, ignore_permissions
automatically_fetch_payment_terms = cint(frappe.db.get_single_value('Accounts Settings', 'automatically_fetch_payment_terms'))
if automatically_fetch_payment_terms:
- fetch_payment_terms_from_order(doc)
+ doc.set_payment_schedule()
return doc
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index f7ea77bae4..2bf5c77e61 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -1105,7 +1105,14 @@ class AccountsController(TransactionBase):
data = get_payment_terms(self.payment_terms_template, posting_date, grand_total, base_grand_total)
for item in data:
self.append("payment_schedule", item)
- else:
+
+ elif self.doctype in ["Sales Invoice", "Purchase Invoice"]:
+ po_or_so, doctype, fieldname = self.get_order_details()
+
+ if self.linked_order_has_payment_terms(po_or_so, fieldname):
+ self.fetch_payment_terms_from_order(po_or_so, doctype)
+
+ elif self.doctype not in ["Purchase Receipt"]:
data = dict(due_date=due_date, invoice_portion=100, payment_amount=grand_total, base_payment_amount=base_grand_total)
self.append("payment_schedule", data)
else:
@@ -1118,6 +1125,63 @@ class AccountsController(TransactionBase):
d.base_payment_amount = flt(base_grand_total * self.get("conversion_rate"), d.precision('base_payment_amount'))
+ def get_order_details(self):
+ if self.doctype == "Sales Invoice":
+ po_or_so = self.get('items')[0].get('sales_order')
+ po_or_so_doctype = "Sales Order"
+ po_or_so_doctype_name = "sales_order"
+
+ else:
+ po_or_so = self.get('items')[0].get('purchase_order')
+ po_or_so_doctype = "Purchase Order"
+ po_or_so_doctype_name = "purchase_order"
+
+ return po_or_so, po_or_so_doctype, po_or_so_doctype_name
+
+ def linked_order_has_payment_terms(self, po_or_so, fieldname):
+ if po_or_so and self.all_items_have_same_po_or_so(po_or_so, fieldname):
+ if self.linked_order_has_payment_terms_template(po_or_so):
+ return True
+ elif self.linked_order_has_payment_schedule(po_or_so):
+ return True
+
+ return False
+
+ def all_items_have_same_po_or_so(self, po_or_so, fieldname):
+ for item in self.get('items'):
+ if item.get(fieldname) != po_or_so:
+ return False
+
+ return True
+
+ def linked_order_has_payment_terms_template(self, po_or_so):
+ return frappe.get_value('Sales Order', po_or_so, 'payment_terms_template')
+
+ def linked_order_has_payment_schedule(self, po_or_so):
+ return frappe.get_all('Payment Schedule', filters={'parent': po_or_so})
+
+ def fetch_payment_terms_from_order(self, po_or_so, po_or_so_doctype):
+ """
+ Fetch Payment Terms from Purchase/Sales Order on creating a new Purchase/Sales Invoice.
+ """
+ po_or_so = frappe.get_cached_doc(po_or_so_doctype, po_or_so)
+
+ self.payment_schedule = []
+ self.payment_terms_template = po_or_so.payment_terms_template
+
+ for schedule in po_or_so.payment_schedule:
+ payment_schedule = {
+ 'payment_term': schedule.payment_term,
+ 'due_date': schedule.due_date,
+ 'invoice_portion': schedule.invoice_portion,
+ 'discount_type': schedule.discount_type,
+ 'discount': schedule.discount,
+ 'base_payment_amount': schedule.base_payment_amount,
+ 'payment_amount': schedule.payment_amount,
+ 'outstanding': schedule.outstanding
+ }
+ self.append("payment_schedule", payment_schedule)
+
def set_due_date(self):
due_dates = [d.due_date for d in self.get("payment_schedule") if d.due_date]
if due_dates:
@@ -1802,47 +1866,4 @@ def validate_regional(doc):
@erpnext.allow_regional
def validate_einvoice_fields(doc):
- pass
-
-def fetch_payment_terms_from_order(doc):
- """
- Fetch Payment Terms from Purchase/Sales Order on creating a new Purchase/Sales Invoice.
- """
-
- if doc.doctype == "Sales Invoice":
- po_or_so = doc.get('items')[0].get('sales_order')
- po_or_so_doctype = "Sales Order"
- po_or_so_doctype_name = "sales_order"
- else:
- po_or_so = doc.get('items')[0].get('purchase_order')
- po_or_so_doctype = "Purchase Order"
- po_or_so_doctype_name = "purchase_order"
-
- if po_or_so and all_items_have_same_po_or_so(doc, po_or_so, po_or_so_doctype_name):
- po_or_so = frappe.get_cached_doc(po_or_so_doctype, po_or_so)
- else:
- doc.set_payment_schedule()
- return
-
- doc.payment_schedule = []
- doc.payment_terms_template = po_or_so.payment_terms_template
-
- for schedule in po_or_so.payment_schedule:
- payment_schedule = {
- 'payment_term': schedule.payment_term,
- 'due_date': schedule.due_date,
- 'invoice_portion': schedule.invoice_portion,
- 'discount_type': schedule.discount_type,
- 'discount': schedule.discount,
- 'base_payment_amount': schedule.base_payment_amount,
- 'payment_amount': schedule.payment_amount,
- 'outstanding': schedule.outstanding
- }
- doc.append("payment_schedule", payment_schedule)
-
-def all_items_have_same_po_or_so(doc, po_or_so, po_or_so_fieldname):
- for item in doc.get('items'):
- if item.get(po_or_so_fieldname) != po_or_so:
- return False
-
- return True
\ No newline at end of file
+ pass
\ No newline at end of file
diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py
index a58c381df3..2b9d516e21 100755
--- a/erpnext/selling/doctype/sales_order/sales_order.py
+++ b/erpnext/selling/doctype/sales_order/sales_order.py
@@ -621,8 +621,6 @@ def make_delivery_note(source_name, target_doc=None, skip_item_mapping=False):
@frappe.whitelist()
def make_sales_invoice(source_name, target_doc=None, ignore_permissions=False):
- from erpnext.controllers.accounts_controller import fetch_payment_terms_from_order
-
def postprocess(source, target):
set_missing_values(source, target)
#Get the advance paid Journal Entries in Sales Invoice Advance
@@ -697,7 +695,7 @@ def make_sales_invoice(source_name, target_doc=None, ignore_permissions=False):
automatically_fetch_payment_terms = cint(frappe.db.get_single_value('Accounts Settings', 'automatically_fetch_payment_terms'))
if automatically_fetch_payment_terms:
- fetch_payment_terms_from_order(doclist)
+ doclist.set_payment_schedule()
return doclist
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.py b/erpnext/stock/doctype/delivery_note/delivery_note.py
index 1628f93019..f99a01b820 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.py
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.py
@@ -414,8 +414,6 @@ def get_returned_qty_map(delivery_note):
@frappe.whitelist()
def make_sales_invoice(source_name, target_doc=None):
- from erpnext.controllers.accounts_controller import fetch_payment_terms_from_order
-
doc = frappe.get_doc('Delivery Note', source_name)
to_make_invoice_qty_map = {}
@@ -507,7 +505,7 @@ def make_sales_invoice(source_name, target_doc=None):
automatically_fetch_payment_terms = cint(frappe.db.get_single_value('Accounts Settings', 'automatically_fetch_payment_terms'))
if automatically_fetch_payment_terms:
- fetch_payment_terms_from_order(doc)
+ doc.set_payment_schedule()
return doc
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
index cf6cac273f..b05cc7875c 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
@@ -583,7 +583,6 @@ def update_billing_percentage(pr_doc, update_modified=True):
@frappe.whitelist()
def make_purchase_invoice(source_name, target_doc=None):
from erpnext.accounts.party import get_payment_terms_template
- from erpnext.controllers.accounts_controller import fetch_payment_terms_from_order
doc = frappe.get_doc('Purchase Receipt', source_name)
returned_qty_map = get_returned_qty_map(source_name)
@@ -657,7 +656,7 @@ def make_purchase_invoice(source_name, target_doc=None):
automatically_fetch_payment_terms = cint(frappe.db.get_single_value('Accounts Settings', 'automatically_fetch_payment_terms'))
if automatically_fetch_payment_terms:
- fetch_payment_terms_from_order(doclist)
+ doc.set_payment_schedule()
return doclist
From 59d1cc02c525cb6710d2a38a5b9c40031f8bf9a8 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Thu, 22 Jul 2021 22:58:45 +0530
Subject: [PATCH 191/386] fix: Add test to check if payment terms are fetched
when creating a Sales Invoice
---
.../doctype/sales_order/test_sales_order.py | 35 +++++++++++++++++++
1 file changed, 35 insertions(+)
diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py
index 974648d6d4..bf6925473a 100644
--- a/erpnext/selling/doctype/sales_order/test_sales_order.py
+++ b/erpnext/selling/doctype/sales_order/test_sales_order.py
@@ -1229,7 +1229,42 @@ class TestSalesOrder(unittest.TestCase):
self.assertRaises(frappe.ValidationError, so.cancel)
+ def test_payment_terms_are_fetched_when_creating_invoice(self):
+ from erpnext.accounts.doctype.payment_entry.test_payment_entry import create_payment_terms_template
+ from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
+ automatically_fetch_payment_terms()
+
+ so = make_sales_order(uom="Nos", do_not_save=1)
+ create_payment_terms_template()
+ so.payment_terms_template = 'Test Receivable Template'
+ so.submit()
+
+ si = create_sales_invoice(qty=10, do_not_save=1)
+ si.items[0].sales_order = so.name
+ si.items[0].so_detail = so.items[0].name
+ si.insert()
+
+ self.assertEqual(so.payment_terms_template, si.payment_terms_template)
+ compare_payment_schedules(self, so, si)
+
+def automatically_fetch_payment_terms(enable=1):
+ accounts_settings = frappe.get_doc("Accounts Settings")
+ accounts_settings.automatically_fetch_payment_terms = enable
+ accounts_settings.save()
+
+def compare_payment_schedules(doc, doc1, doc2):
+ payment_schedule1 = frappe.db.sql("""select payment_term, description, due_date, mode_of_payment, invoice_portion, payment_amount
+ from `tabPayment Schedule`
+ where parenttype=%s and parent=%s
+ order by payment_term asc""", (doc1.doctype, doc1.name), as_dict=1)
+
+ payment_schedule2 = frappe.db.sql("""select payment_term, description, due_date, mode_of_payment, invoice_portion, payment_amount
+ from `tabPayment Schedule`
+ where parenttype=%s and parent=%s
+ order by payment_term asc""", (doc2.doctype, doc2.name), as_dict=1)
+
+ doc.assertEqual(payment_schedule1, payment_schedule2)
def make_sales_order(**args):
so = frappe.new_doc("Sales Order")
From 293c5e10c3fa122715ca5f3ca67f9051a87bf01f Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Fri, 23 Jul 2021 03:23:29 +0530
Subject: [PATCH 192/386] fix: Add test to check if payment terms are fetched
when creating a Sales Invoice
---
.../delivery_note/test_delivery_note.py | 27 ++++++++++++++++++-
1 file changed, 26 insertions(+), 1 deletion(-)
diff --git a/erpnext/stock/doctype/delivery_note/test_delivery_note.py b/erpnext/stock/doctype/delivery_note/test_delivery_note.py
index f981aeb13b..8b1245eb40 100644
--- a/erpnext/stock/doctype/delivery_note/test_delivery_note.py
+++ b/erpnext/stock/doctype/delivery_note/test_delivery_note.py
@@ -17,7 +17,8 @@ from erpnext.stock.doctype.stock_entry.test_stock_entry \
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos, SerialNoWarehouseError
from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation \
import create_stock_reconciliation, set_valuation_method
-from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order, create_dn_against_so
+from erpnext.selling.doctype.sales_order.test_sales_order \
+ import make_sales_order, create_dn_against_so, automatically_fetch_payment_terms, compare_payment_schedules
from erpnext.accounts.doctype.account.test_account import get_inventory_account
from erpnext.stock.doctype.warehouse.test_warehouse import get_warehouse
from erpnext.stock.doctype.item.test_item import make_item
@@ -759,6 +760,30 @@ class TestDeliveryNote(unittest.TestCase):
self.assertTrue("TESTBATCH" in dn.packed_items[0].batch_no, "Batch number not added in packed item")
+ def test_payment_terms_are_fetched_when_creating_invoice(self):
+ from erpnext.accounts.doctype.payment_entry.test_payment_entry import create_payment_terms_template
+ from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
+
+ automatically_fetch_payment_terms()
+
+ so = make_sales_order(uom="Nos", do_not_save=1)
+ create_payment_terms_template()
+ so.payment_terms_template = 'Test Receivable Template'
+ so.submit()
+
+ dn = create_dn_against_so(so.name, delivered_qty=10)
+
+ si = create_sales_invoice(qty=10, do_not_save=1)
+ si.items[0].delivery_note= dn.name
+ si.items[0].dn_detail = dn.items[0].name
+ si.items[0].sales_order = so.name
+ si.items[0].so_detail = so.items[0].name
+
+ si.insert()
+ si.submit()
+
+ self.assertEqual(so.payment_terms_template, si.payment_terms_template)
+ compare_payment_schedules(self, so, si)
def create_delivery_note(**args):
dn = frappe.new_doc("Delivery Note")
From e94604f517ea77f6e82fe8e8c14cdb569742eee2 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Fri, 23 Jul 2021 03:36:37 +0530
Subject: [PATCH 193/386] fix: Add test to check if payment terms are fetched
when creating a Purchase Invoice
---
.../purchase_order/test_purchase_order.py | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/erpnext/buying/doctype/purchase_order/test_purchase_order.py b/erpnext/buying/doctype/purchase_order/test_purchase_order.py
index 8563b97ab7..11cf39e5e2 100644
--- a/erpnext/buying/doctype/purchase_order/test_purchase_order.py
+++ b/erpnext/buying/doctype/purchase_order/test_purchase_order.py
@@ -968,8 +968,25 @@ class TestPurchaseOrder(unittest.TestCase):
# To test if the PO does NOT have a Blanket Order
self.assertEqual(po_doc.items[0].blanket_order, None)
+ def test_payment_terms_are_fetched_when_creating_invoice(self):
+ from erpnext.accounts.doctype.payment_entry.test_payment_entry import create_payment_terms_template
+ from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
+ from erpnext.selling.doctype.sales_order.test_sales_order import automatically_fetch_payment_terms, compare_payment_schedules
+ automatically_fetch_payment_terms()
+ po = create_purchase_order(qty=10, rate=100, do_not_save=1)
+ create_payment_terms_template()
+ po.payment_terms_template = 'Test Receivable Template'
+ po.submit()
+
+ pi = make_purchase_invoice(qty=10, rate=100, do_not_save=1)
+ pi.items[0].purchase_order = po.name
+ pi.items[0].po_detail = po.items[0].name
+ pi.insert()
+
+ # self.assertEqual(po.payment_terms_template, pi.payment_terms_template)
+ compare_payment_schedules(self, po, pi)
def make_pr_against_po(po, received_qty=0):
pr = make_purchase_receipt(po)
From 0413a5aafdc2ef05ce6aabfc275081aac8a737af Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Fri, 23 Jul 2021 03:44:56 +0530
Subject: [PATCH 194/386] fix: Add test to check if payment terms are fetched
when creating a Purchase Invoice
---
.../purchase_receipt/test_purchase_receipt.py | 52 +++++++++++++++++++
1 file changed, 52 insertions(+)
diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
index 2eb8bfd5d2..44e3e1e70e 100644
--- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
@@ -1052,6 +1052,58 @@ class TestPurchaseReceipt(unittest.TestCase):
frappe.db.set_value('Company', company, 'enable_perpetual_inventory_for_non_stock_items', before_test_value)
+ def test_purchase_receipt_with_exchange_rate_difference(self):
+ from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice as create_purchase_invoice
+ from erpnext.accounts.doctype.purchase_invoice.purchase_invoice import make_purchase_receipt as create_purchase_receipt
+
+ pi = create_purchase_invoice(company="_Test Company with perpetual inventory",
+ cost_center = "Main - TCP1",
+ warehouse = "Stores - TCP1",
+ expense_account ="_Test Account Cost for Goods Sold - TCP1",
+ currency = "USD", conversion_rate = 70)
+
+ pr = create_purchase_receipt(pi.name)
+ pr.conversion_rate = 80
+ pr.items[0].purchase_invoice = pi.name
+ pr.items[0].purchase_invoice_item = pi.items[0].name
+
+ pr.save()
+ pr.submit()
+
+ # Get exchnage gain and loss account
+ exchange_gain_loss_account = frappe.db.get_value('Company', pr.company, 'exchange_gain_loss_account')
+
+ # fetching the latest GL Entry with exchange gain and loss account account
+ amount = frappe.db.get_value('GL Entry', {'account': exchange_gain_loss_account, 'voucher_no': pr.name}, 'credit')
+ discrepancy_caused_by_exchange_rate_diff = abs(pi.items[0].base_net_amount - pr.items[0].base_net_amount)
+
+ self.assertEqual(discrepancy_caused_by_exchange_rate_diff, amount)
+
+ def test_payment_terms_are_fetched_when_creating_invoice(self):
+ from erpnext.accounts.doctype.payment_entry.test_payment_entry import create_payment_terms_template
+ from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
+ from erpnext.buying.doctype.purchase_order.test_purchase_order import create_purchase_order, make_pr_against_po
+ from erpnext.selling.doctype.sales_order.test_sales_order import automatically_fetch_payment_terms, compare_payment_schedules
+
+ automatically_fetch_payment_terms()
+
+ po = create_purchase_order(qty=10, rate=100, do_not_save=1)
+ create_payment_terms_template()
+ po.payment_terms_template = 'Test Receivable Template'
+ po.submit()
+
+ pr = make_pr_against_po(po.name, received_qty=10)
+
+ pi = make_purchase_invoice(qty=10, rate=100, do_not_save=1)
+ pi.items[0].purchase_receipt = pr.name
+ pi.items[0].pr_detail = pr.items[0].name
+ pi.items[0].purchase_order = po.name
+ pi.items[0].po_detail = po.items[0].name
+ pi.insert()
+
+ # self.assertEqual(po.payment_terms_template, pi.payment_terms_template)
+ compare_payment_schedules(self, po, pi)
+
def get_sl_entries(voucher_type, voucher_no):
return frappe.db.sql(""" select actual_qty, warehouse, stock_value_difference
from `tabStock Ledger Entry` where voucher_type=%s and voucher_no=%s
From 57df4a3aa1c5432eb889c7045de3d570fe35e90c Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Fri, 23 Jul 2021 03:45:59 +0530
Subject: [PATCH 195/386] fix: Rename tests
---
erpnext/buying/doctype/purchase_order/test_purchase_order.py | 2 +-
erpnext/selling/doctype/sales_order/test_sales_order.py | 2 +-
erpnext/stock/doctype/delivery_note/test_delivery_note.py | 2 +-
erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py | 2 +-
4 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/erpnext/buying/doctype/purchase_order/test_purchase_order.py b/erpnext/buying/doctype/purchase_order/test_purchase_order.py
index 11cf39e5e2..474c9cf3df 100644
--- a/erpnext/buying/doctype/purchase_order/test_purchase_order.py
+++ b/erpnext/buying/doctype/purchase_order/test_purchase_order.py
@@ -968,7 +968,7 @@ class TestPurchaseOrder(unittest.TestCase):
# To test if the PO does NOT have a Blanket Order
self.assertEqual(po_doc.items[0].blanket_order, None)
- def test_payment_terms_are_fetched_when_creating_invoice(self):
+ def test_payment_terms_are_fetched_when_creating_purchase_invoice(self):
from erpnext.accounts.doctype.payment_entry.test_payment_entry import create_payment_terms_template
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
from erpnext.selling.doctype.sales_order.test_sales_order import automatically_fetch_payment_terms, compare_payment_schedules
diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py
index bf6925473a..3fbe0afd10 100644
--- a/erpnext/selling/doctype/sales_order/test_sales_order.py
+++ b/erpnext/selling/doctype/sales_order/test_sales_order.py
@@ -1229,7 +1229,7 @@ class TestSalesOrder(unittest.TestCase):
self.assertRaises(frappe.ValidationError, so.cancel)
- def test_payment_terms_are_fetched_when_creating_invoice(self):
+ def test_payment_terms_are_fetched_when_creating_sales_invoice(self):
from erpnext.accounts.doctype.payment_entry.test_payment_entry import create_payment_terms_template
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
diff --git a/erpnext/stock/doctype/delivery_note/test_delivery_note.py b/erpnext/stock/doctype/delivery_note/test_delivery_note.py
index 8b1245eb40..ca8d8b99d3 100644
--- a/erpnext/stock/doctype/delivery_note/test_delivery_note.py
+++ b/erpnext/stock/doctype/delivery_note/test_delivery_note.py
@@ -760,7 +760,7 @@ class TestDeliveryNote(unittest.TestCase):
self.assertTrue("TESTBATCH" in dn.packed_items[0].batch_no, "Batch number not added in packed item")
- def test_payment_terms_are_fetched_when_creating_invoice(self):
+ def test_payment_terms_are_fetched_when_creating_sales_invoice(self):
from erpnext.accounts.doctype.payment_entry.test_payment_entry import create_payment_terms_template
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
index 44e3e1e70e..9a5064fcc7 100644
--- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
@@ -1079,7 +1079,7 @@ class TestPurchaseReceipt(unittest.TestCase):
self.assertEqual(discrepancy_caused_by_exchange_rate_diff, amount)
- def test_payment_terms_are_fetched_when_creating_invoice(self):
+ def test_payment_terms_are_fetched_when_creating_purchase_invoice(self):
from erpnext.accounts.doctype.payment_entry.test_payment_entry import create_payment_terms_template
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
from erpnext.buying.doctype.purchase_order.test_purchase_order import create_purchase_order, make_pr_against_po
From 6343950d82e77ccffa0d444829bd65a8b23fc441 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Fri, 23 Jul 2021 03:58:27 +0530
Subject: [PATCH 196/386] fix: Sider issues
---
erpnext/selling/doctype/sales_order/test_sales_order.py | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py
index 3fbe0afd10..f4a089bcef 100644
--- a/erpnext/selling/doctype/sales_order/test_sales_order.py
+++ b/erpnext/selling/doctype/sales_order/test_sales_order.py
@@ -1249,9 +1249,9 @@ class TestSalesOrder(unittest.TestCase):
compare_payment_schedules(self, so, si)
def automatically_fetch_payment_terms(enable=1):
- accounts_settings = frappe.get_doc("Accounts Settings")
- accounts_settings.automatically_fetch_payment_terms = enable
- accounts_settings.save()
+ accounts_settings = frappe.get_doc("Accounts Settings")
+ accounts_settings.automatically_fetch_payment_terms = enable
+ accounts_settings.save()
def compare_payment_schedules(doc, doc1, doc2):
payment_schedule1 = frappe.db.sql("""select payment_term, description, due_date, mode_of_payment, invoice_portion, payment_amount
From 01ab63189a70788c7c542bcd6a69b56280a46761 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Thu, 29 Jul 2021 19:18:35 +0530
Subject: [PATCH 197/386] fix: Check if Purchase Order has Payment Terms
Template
---
erpnext/controllers/accounts_controller.py | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index 2bf5c77e61..913e70b30c 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -1109,7 +1109,7 @@ class AccountsController(TransactionBase):
elif self.doctype in ["Sales Invoice", "Purchase Invoice"]:
po_or_so, doctype, fieldname = self.get_order_details()
- if self.linked_order_has_payment_terms(po_or_so, fieldname):
+ if self.linked_order_has_payment_terms(po_or_so, fieldname, doctype):
self.fetch_payment_terms_from_order(po_or_so, doctype)
elif self.doctype not in ["Purchase Receipt"]:
@@ -1138,9 +1138,9 @@ class AccountsController(TransactionBase):
return po_or_so, po_or_so_doctype, po_or_so_doctype_name
- def linked_order_has_payment_terms(self, po_or_so, fieldname):
+ def linked_order_has_payment_terms(self, po_or_so, fieldname, doctype):
if po_or_so and self.all_items_have_same_po_or_so(po_or_so, fieldname):
- if self.linked_order_has_payment_terms_template(po_or_so):
+ if self.linked_order_has_payment_terms_template(po_or_so, doctype):
return True
elif self.linked_order_has_payment_schedule(po_or_so):
return True
@@ -1154,8 +1154,8 @@ class AccountsController(TransactionBase):
return True
- def linked_order_has_payment_terms_template(self, po_or_so):
- return frappe.get_value('Sales Order', po_or_so, 'payment_terms_template')
+ def linked_order_has_payment_terms_template(self, po_or_so, doctype):
+ return frappe.get_value(doctype, po_or_so, 'payment_terms_template')
def linked_order_has_payment_schedule(self, po_or_so):
return frappe.get_all('Payment Schedule', filters={'parent': po_or_so})
From c7df7593248be42c1a0a3bd15a1905d8864cc1b5 Mon Sep 17 00:00:00 2001
From: Ankush
Date: Thu, 29 Jul 2021 19:49:12 +0530
Subject: [PATCH 198/386] fix: empty "against account" in Purchase Receipt GLE
bp #26712 (#26718)
* fix: correct field for GLE against account in PR
* fix: remove incorrect field check from reposting
---
erpnext/accounts/utils.py | 2 +-
erpnext/stock/doctype/purchase_receipt/purchase_receipt.py | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py
index 1cdbd8d38a..9afe365f74 100644
--- a/erpnext/accounts/utils.py
+++ b/erpnext/accounts/utils.py
@@ -966,7 +966,7 @@ def compare_existing_and_expected_gle(existing_gle, expected_gle, precision):
for e in existing_gle:
if entry.account == e.account:
account_existed = True
- if (entry.account == e.account and entry.against_account == e.against_account
+ if (entry.account == e.account
and (not entry.cost_center or not e.cost_center or entry.cost_center == e.cost_center)
and ( flt(entry.debit, precision) != flt(e.debit, precision) or
flt(entry.credit, precision) != flt(e.credit, precision))):
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
index 82c87a83a5..26ea11e01d 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
@@ -415,7 +415,7 @@ class PurchaseReceipt(BuyingController):
"cost_center": cost_center,
"debit": debit,
"credit": credit,
- "against_account": against_account,
+ "against": against_account,
"remarks": remarks,
}
From 2d6f2fea5b42286e4a12d26d219448f9a298c0ed Mon Sep 17 00:00:00 2001
From: Saqib
Date: Fri, 30 Jul 2021 10:55:53 +0530
Subject: [PATCH 199/386] fix: gl entries for exchange gain loss (#26728)
---
.../purchase_invoice/test_purchase_invoice.py | 8 ++++----
erpnext/controllers/accounts_controller.py | 17 +++++++++++------
2 files changed, 15 insertions(+), 10 deletions(-)
diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
index ca4d009956..4bc22a544d 100644
--- a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
@@ -997,8 +997,8 @@ class TestPurchaseInvoice(unittest.TestCase):
expected_gle = [
["_Test Account Cost for Goods Sold - _TC", 37500.0],
- ["_Test Payable USD - _TC", -40000.0],
- ["Exchange Gain/Loss - _TC", 2500.0]
+ ["_Test Payable USD - _TC", -35000.0],
+ ["Exchange Gain/Loss - _TC", -2500.0]
]
gl_entries = frappe.db.sql("""
@@ -1028,8 +1028,8 @@ class TestPurchaseInvoice(unittest.TestCase):
expected_gle = [
["_Test Account Cost for Goods Sold - _TC", 36500.0],
- ["_Test Payable USD - _TC", -38000.0],
- ["Exchange Gain/Loss - _TC", 1500.0]
+ ["_Test Payable USD - _TC", -35000.0],
+ ["Exchange Gain/Loss - _TC", -1500.0]
]
gl_entries = frappe.db.sql("""
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index cdd865ac4a..a9b7efbe98 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -674,19 +674,24 @@ class AccountsController(TransactionBase):
if self.get('doctype') in ['Purchase Invoice', 'Sales Invoice']:
for d in self.get("advances"):
if d.exchange_gain_loss:
- party = self.supplier if self.get('doctype') == 'Purchase Invoice' else self.customer
- party_account = self.credit_to if self.get('doctype') == 'Purchase Invoice' else self.debit_to
- party_type = "Supplier" if self.get('doctype') == 'Purchase Invoice' else "Customer"
+ is_purchase_invoice = self.get('doctype') == 'Purchase Invoice'
+ party = self.supplier if is_purchase_invoice else self.customer
+ party_account = self.credit_to if is_purchase_invoice else self.debit_to
+ party_type = "Supplier" if is_purchase_invoice else "Customer"
gain_loss_account = frappe.db.get_value('Company', self.company, 'exchange_gain_loss_account')
+ if not gain_loss_account:
+ frappe.throw(_("Please set Default Exchange Gain/Loss Account in Company {}")
+ .format(self.get('company')))
account_currency = get_account_currency(gain_loss_account)
if account_currency != self.company_currency:
- frappe.throw(_("Currency for {0} must be {1}").format(d.account, self.company_currency))
+ frappe.throw(_("Currency for {0} must be {1}").format(gain_loss_account, self.company_currency))
# for purchase
dr_or_cr = 'debit' if d.exchange_gain_loss > 0 else 'credit'
- # just reverse for sales?
- dr_or_cr = 'debit' if dr_or_cr == 'credit' else 'credit'
+ if not is_purchase_invoice:
+ # just reverse for sales?
+ dr_or_cr = 'debit' if dr_or_cr == 'credit' else 'credit'
gl_entries.append(
self.get_gl_dict({
From b8845b9ed986a8cd2e2e30360d12336b23b4c5bc Mon Sep 17 00:00:00 2001
From: Subin Tom
Date: Fri, 30 Jul 2021 16:30:18 +0530
Subject: [PATCH 200/386] Fix: Payment Entry party validation issue
---
erpnext/accounts/party.py | 5 +++++
erpnext/accounts/utils.py | 2 ++
2 files changed, 7 insertions(+)
diff --git a/erpnext/accounts/party.py b/erpnext/accounts/party.py
index b97dc401e6..c3b78a4f48 100644
--- a/erpnext/accounts/party.py
+++ b/erpnext/accounts/party.py
@@ -286,6 +286,7 @@ def validate_party_gle_currency(party_type, party, company, party_account_curren
.format(frappe.bold(party_type), frappe.bold(party), frappe.bold(existing_gle_currency), frappe.bold(company)), InvalidAccountCurrency)
def validate_party_accounts(doc):
+
companies = []
for account in doc.get("accounts"):
@@ -446,6 +447,10 @@ def get_payment_terms_template(party_name, party_type, company=None):
return template
def validate_party_frozen_disabled(party_type, party_name):
+
+ if frappe.flags.ignore_party_validation:
+ return
+
if party_type and party_name:
if party_type in ("Customer", "Supplier"):
party = frappe.get_cached_value(party_type, party_name, ["is_frozen", "disabled"], as_dict=True)
diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py
index 1cdbd8d38a..d569e1cbca 100644
--- a/erpnext/accounts/utils.py
+++ b/erpnext/accounts/utils.py
@@ -350,6 +350,7 @@ def reconcile_against_document(args):
# cancel advance entry
doc = frappe.get_doc(d.voucher_type, d.voucher_no)
+ frappe.flags.ignore_party_validation = True
doc.make_gl_entries(cancel=1, adv_adj=1)
# update ref in advance entry
@@ -361,6 +362,7 @@ def reconcile_against_document(args):
# re-submit advance entry
doc = frappe.get_doc(d.voucher_type, d.voucher_no)
doc.make_gl_entries(cancel = 0, adv_adj =1)
+ frappe.flags.ignore_party_validation = False
if d.voucher_type in ('Payment Entry', 'Journal Entry'):
doc.update_expense_claim()
From b5c7fce68922a846be2b644980b9dfad8a596e92 Mon Sep 17 00:00:00 2001
From: Frappe PR Bot
Date: Fri, 30 Jul 2021 18:54:35 +0530
Subject: [PATCH 201/386] fix: student category mapping from the program
enrollment tool (#26716) (#26739)
Co-authored-by: Jannat Patel <31363128+pateljannat@users.noreply.github.com>
(cherry picked from commit 1a2332a81cd7999e1f9266337fb48462ebfcbcc4)
Co-authored-by: Rucha Mahabal
---
erpnext/education/api.py | 7 +-
.../program_enrollment_tool_student.json | 245 +++++-------------
2 files changed, 64 insertions(+), 188 deletions(-)
diff --git a/erpnext/education/api.py b/erpnext/education/api.py
index afa0be9b9f..4493a3fef1 100644
--- a/erpnext/education/api.py
+++ b/erpnext/education/api.py
@@ -34,11 +34,14 @@ def enroll_student(source_name):
}
}}, ignore_permissions=True)
student.save()
+
+ student_applicant = frappe.db.get_value("Student Applicant", source_name,
+ ["student_category", "program"], as_dict=True)
program_enrollment = frappe.new_doc("Program Enrollment")
program_enrollment.student = student.name
- program_enrollment.student_category = student.student_category
+ program_enrollment.student_category = student_applicant.student_category
program_enrollment.student_name = student.title
- program_enrollment.program = frappe.db.get_value("Student Applicant", source_name, "program")
+ program_enrollment.program = student_applicant.program
frappe.publish_realtime('enroll_student_progress', {"progress": [2, 4]}, user=frappe.session.user)
return program_enrollment
diff --git a/erpnext/education/doctype/program_enrollment_tool_student/program_enrollment_tool_student.json b/erpnext/education/doctype/program_enrollment_tool_student/program_enrollment_tool_student.json
index 9be292b65e..1d7497387f 100644
--- a/erpnext/education/doctype/program_enrollment_tool_student/program_enrollment_tool_student.json
+++ b/erpnext/education/doctype/program_enrollment_tool_student/program_enrollment_tool_student.json
@@ -1,195 +1,68 @@
{
- "allow_copy": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "beta": 0,
- "creation": "2016-06-10 03:29:02.539914",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "",
- "editable_grid": 1,
+ "actions": [],
+ "creation": "2016-06-10 03:29:02.539914",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "student_applicant",
+ "student",
+ "student_name",
+ "column_break_3",
+ "student_batch_name",
+ "student_category"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
- "fieldname": "student_applicant",
- "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": "Student Applicant",
- "length": 0,
- "no_copy": 0,
- "options": "Student Applicant",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "fieldname": "student_applicant",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Student Applicant",
+ "options": "Student Applicant"
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
- "fieldname": "student",
- "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": "Student",
- "length": 0,
- "no_copy": 0,
- "options": "Student",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "fieldname": "student",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Student",
+ "options": "Student"
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_3",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "fieldname": "column_break_3",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "student_name",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Student Name",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "fieldname": "student_name",
+ "fieldtype": "Data",
+ "in_list_view": 1,
+ "label": "Student Name",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "student_batch_name",
- "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": "Student Batch Name",
- "length": 0,
- "no_copy": 0,
- "options": "Student Batch Name",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
+ "fieldname": "student_batch_name",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Student Batch Name",
+ "options": "Student Batch Name"
+ },
+ {
+ "fieldname": "student_category",
+ "fieldtype": "Link",
+ "label": "Student Category",
+ "options": "Student Category",
+ "read_only": 1
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 1,
- "max_attachments": 0,
- "modified": "2018-01-02 12:03:53.890741",
- "modified_by": "Administrator",
- "module": "Education",
- "name": "Program Enrollment Tool Student",
- "name_case": "",
- "owner": "Administrator",
- "permissions": [],
- "quick_entry": 1,
- "read_only": 0,
- "read_only_onload": 0,
- "restrict_to_domain": "Education",
- "show_name_in_global_search": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 0,
- "track_seen": 0
+ ],
+ "istable": 1,
+ "links": [],
+ "modified": "2021-07-29 18:19:54.471594",
+ "modified_by": "Administrator",
+ "module": "Education",
+ "name": "Program Enrollment Tool Student",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "restrict_to_domain": "Education",
+ "sort_field": "modified",
+ "sort_order": "DESC"
}
\ No newline at end of file
From 74bb55bfd26583b8e12b5dc2dd89eb8f51dbd45d Mon Sep 17 00:00:00 2001
From: Nabin Hait
Date: Sun, 1 Aug 2021 20:03:38 +0530
Subject: [PATCH 202/386] Revert "fix: Tax calculation for Recurring additional
salary (#24206)"
This reverts commit adfdc71844a94a68884c50f45c5f90f3d1640a95.
---
.../additional_salary/additional_salary.py | 6 +++---
.../doctype/salary_detail/salary_detail.json | 11 +---------
.../doctype/salary_slip/salary_slip.py | 21 +++++--------------
3 files changed, 9 insertions(+), 29 deletions(-)
diff --git a/erpnext/payroll/doctype/additional_salary/additional_salary.py b/erpnext/payroll/doctype/additional_salary/additional_salary.py
index b978cbe2b5..381f399e9f 100644
--- a/erpnext/payroll/doctype/additional_salary/additional_salary.py
+++ b/erpnext/payroll/doctype/additional_salary/additional_salary.py
@@ -112,11 +112,11 @@ class AdditionalSalary(Document):
no_of_days = date_diff(getdate(end_date), getdate(start_date)) + 1
return amount_per_day * no_of_days
-@frappe.whitelist()
def get_additional_salaries(employee, start_date, end_date, component_type):
additional_salary_list = frappe.db.sql("""
- select name, salary_component as component, type, amount, overwrite_salary_structure_amount as overwrite,
- deduct_full_tax_on_selected_payroll_date, is_recurring
+ select name, salary_component as component, type, amount,
+ overwrite_salary_structure_amount as overwrite,
+ deduct_full_tax_on_selected_payroll_date
from `tabAdditional Salary`
where employee=%(employee)s
and docstatus = 1
diff --git a/erpnext/payroll/doctype/salary_detail/salary_detail.json b/erpnext/payroll/doctype/salary_detail/salary_detail.json
index 97608d72f3..393f647cc8 100644
--- a/erpnext/payroll/doctype/salary_detail/salary_detail.json
+++ b/erpnext/payroll/doctype/salary_detail/salary_detail.json
@@ -12,7 +12,6 @@
"year_to_date",
"section_break_5",
"additional_salary",
- "is_recurring_additional_salary",
"statistical_component",
"depends_on_payment_days",
"exempted_from_income_tax",
@@ -236,19 +235,11 @@
"label": "Year To Date",
"options": "currency",
"read_only": 1
- },
- {
- "default": "0",
- "depends_on": "eval:doc.parenttype=='Salary Slip' && doc.parentfield=='earnings' && doc.additional_salary",
- "fieldname": "is_recurring_additional_salary",
- "fieldtype": "Check",
- "label": "Is Recurring Additional Salary",
- "read_only": 1
}
],
"istable": 1,
"links": [],
- "modified": "2021-03-14 13:39:15.847158",
+ "modified": "2021-01-14 13:39:15.847158",
"modified_by": "Administrator",
"module": "Payroll",
"name": "Salary Detail",
diff --git a/erpnext/payroll/doctype/salary_slip/salary_slip.py b/erpnext/payroll/doctype/salary_slip/salary_slip.py
index 3e82c0d428..7e1fb0616d 100644
--- a/erpnext/payroll/doctype/salary_slip/salary_slip.py
+++ b/erpnext/payroll/doctype/salary_slip/salary_slip.py
@@ -7,12 +7,12 @@ import datetime, math
from frappe.utils import add_days, cint, cstr, flt, getdate, rounded, date_diff, money_in_words, formatdate, get_first_day
from frappe.model.naming import make_autoname
-from frappe.utils.background_jobs import enqueue
from frappe import msgprint, _
from erpnext.payroll.doctype.payroll_entry.payroll_entry import get_start_end_dates
from erpnext.hr.doctype.employee.employee import get_holiday_list_for_employee
from erpnext.utilities.transaction_base import TransactionBase
+from frappe.utils.background_jobs import enqueue
from erpnext.payroll.doctype.additional_salary.additional_salary import get_additional_salaries
from erpnext.payroll.doctype.payroll_period.payroll_period import get_period_factor, get_payroll_period
from erpnext.payroll.doctype.employee_benefit_application.employee_benefit_application import get_benefit_component_amount
@@ -618,8 +618,7 @@ class SalarySlip(TransactionBase):
get_salary_component_data(additional_salary.component),
additional_salary.amount,
component_type,
- additional_salary,
- is_recurring = additional_salary.is_recurring
+ additional_salary
)
def add_tax_components(self, payroll_period):
@@ -640,7 +639,7 @@ class SalarySlip(TransactionBase):
tax_row = get_salary_component_data(d)
self.update_component_row(tax_row, tax_amount, "deductions")
- def update_component_row(self, component_data, amount, component_type, additional_salary=None, is_recurring = 0):
+ def update_component_row(self, component_data, amount, component_type, additional_salary=None):
component_row = None
for d in self.get(component_type):
if d.salary_component != component_data.salary_component:
@@ -681,7 +680,6 @@ class SalarySlip(TransactionBase):
component_row.set('abbr', abbr)
if additional_salary:
- component_row.is_recurring_additional_salary = is_recurring
component_row.default_amount = 0
component_row.additional_amount = amount
component_row.additional_salary = additional_salary.name
@@ -715,7 +713,6 @@ class SalarySlip(TransactionBase):
# get remaining numbers of sub-period (period for which one salary is processed)
remaining_sub_periods = get_period_factor(self.employee,
self.start_date, self.end_date, self.payroll_frequency, payroll_period)[1]
-
# get taxable_earnings, paid_taxes for previous period
previous_taxable_earnings = self.get_taxable_earnings_for_prev_period(payroll_period.start_date,
self.start_date, tax_slab.allow_tax_exemption)
@@ -875,16 +872,8 @@ class SalarySlip(TransactionBase):
if earning.is_tax_applicable:
if additional_amount:
- if not earning.is_recurring_additional_salary:
- taxable_earnings += (amount - additional_amount)
- additional_income += additional_amount
- else:
- to_date = frappe.db.get_value("Additional Salary", earning.additional_salary, 'to_date')
- period = (getdate(to_date).month - getdate(self.start_date).month) + 1
- if period > 0:
- taxable_earnings += (amount - additional_amount) * period
- additional_income += additional_amount * period
-
+ taxable_earnings += (amount - additional_amount)
+ additional_income += additional_amount
if earning.deduct_full_tax_on_selected_payroll_date:
additional_income_with_full_tax += additional_amount
continue
From a75c7c48d8c0710b6c36bc8c720f722cefdc2cd8 Mon Sep 17 00:00:00 2001
From: Subin Tom <36098155+nemesis189@users.noreply.github.com>
Date: Mon, 2 Aug 2021 11:34:28 +0530
Subject: [PATCH 203/386] fix: missing QR Code in auto email attachment
(#26599)
---
erpnext/regional/india/e_invoice/utils.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/regional/india/e_invoice/utils.py b/erpnext/regional/india/e_invoice/utils.py
index ea600d9097..cd85f6b026 100644
--- a/erpnext/regional/india/e_invoice/utils.py
+++ b/erpnext/regional/india/e_invoice/utils.py
@@ -966,7 +966,7 @@ class GSPConnector():
"attached_to_doctype": doctype,
"attached_to_name": docname,
"attached_to_field": "qrcode_image",
- "is_private": 1,
+ "is_private": 0,
"content": qr_image.getvalue()})
_file.save()
frappe.db.commit()
From 4597f151f5e3f91f34a620d87b4ad805b0498a12 Mon Sep 17 00:00:00 2001
From: Subin Tom <36098155+nemesis189@users.noreply.github.com>
Date: Mon, 2 Aug 2021 11:38:31 +0530
Subject: [PATCH 204/386] fix: POS Item Cart non-stop scroll issue (#26693)
---
erpnext/selling/page/point_of_sale/pos_item_cart.js | 7 -------
1 file changed, 7 deletions(-)
diff --git a/erpnext/selling/page/point_of_sale/pos_item_cart.js b/erpnext/selling/page/point_of_sale/pos_item_cart.js
index 6e36d2809a..a4a4b0e0ed 100644
--- a/erpnext/selling/page/point_of_sale/pos_item_cart.js
+++ b/erpnext/selling/page/point_of_sale/pos_item_cart.js
@@ -564,7 +564,6 @@ erpnext.PointOfSale.ItemCart = class {
)
set_dynamic_rate_header_width();
- this.scroll_to_item($item_to_update);
function set_dynamic_rate_header_width() {
const rate_cols = Array.from(me.$cart_items_wrapper.find(".item-rate-amount"));
@@ -639,12 +638,6 @@ erpnext.PointOfSale.ItemCart = class {
$($img).parent().replaceWith(`${item_abbr}
`);
}
- scroll_to_item($item) {
- if ($item.length === 0) return;
- const scrollTop = $item.offset().top - this.$cart_items_wrapper.offset().top + this.$cart_items_wrapper.scrollTop();
- this.$cart_items_wrapper.animate({ scrollTop });
- }
-
update_selector_value_in_cart_item(selector, value, item) {
const $item_to_update = this.get_cart_item(item);
$item_to_update.attr(`data-${selector}`, escape(value));
From a9474a9fbd407806ae7cd5f06169501c0c75bdfa Mon Sep 17 00:00:00 2001
From: Frappe PR Bot
Date: Mon, 2 Aug 2021 12:25:27 +0530
Subject: [PATCH 205/386] fix: POS Invoice consolidated Sales Invoice field set
to no copy (#26768)
---
erpnext/accounts/doctype/pos_invoice/pos_invoice.json | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/erpnext/accounts/doctype/pos_invoice/pos_invoice.json b/erpnext/accounts/doctype/pos_invoice/pos_invoice.json
index 7459c11d4d..33c3e0432b 100644
--- a/erpnext/accounts/doctype/pos_invoice/pos_invoice.json
+++ b/erpnext/accounts/doctype/pos_invoice/pos_invoice.json
@@ -1545,6 +1545,7 @@
"fieldname": "consolidated_invoice",
"fieldtype": "Link",
"label": "Consolidated Sales Invoice",
+ "no_copy": 1,
"options": "Sales Invoice",
"read_only": 1
}
@@ -1552,7 +1553,7 @@
"icon": "fa fa-file-text",
"is_submittable": 1,
"links": [],
- "modified": "2021-02-01 15:03:33.800707",
+ "modified": "2021-07-29 13:37:20.636171",
"modified_by": "Administrator",
"module": "Accounts",
"name": "POS Invoice",
From e43bdf76a5b8a76e590dd1c15605b06c534187fb Mon Sep 17 00:00:00 2001
From: Ankush
Date: Mon, 2 Aug 2021 18:57:48 +0530
Subject: [PATCH 206/386] chore: warning for shopify integration deprecation
(#26701)
* chore: warning for shopify integration deprecation
* fix: warn deprecation during patch for sysadmins
---
.../doctype/shopify_log/shopify_log.js | 3 +++
.../doctype/shopify_settings/shopify_settings.js | 4 ++++
erpnext/patches.txt | 1 +
.../patches/v13_0/shopify_deprecation_warning.py | 15 +++++++++++++++
4 files changed, 23 insertions(+)
create mode 100644 erpnext/patches/v13_0/shopify_deprecation_warning.py
diff --git a/erpnext/erpnext_integrations/doctype/shopify_log/shopify_log.js b/erpnext/erpnext_integrations/doctype/shopify_log/shopify_log.js
index d3fe7d2b4d..12faeecc87 100644
--- a/erpnext/erpnext_integrations/doctype/shopify_log/shopify_log.js
+++ b/erpnext/erpnext_integrations/doctype/shopify_log/shopify_log.js
@@ -18,5 +18,8 @@ frappe.ui.form.on('Shopify Log', {
})
}).addClass('btn-primary');
}
+
+ let app_link = "Ecommerce Integrations "
+ frm.dashboard.add_comment(__("Shopify Integration will be removed from ERPNext in Version 14. Please install {0} app to continue using it.", [app_link]), "yellow", true);
}
});
diff --git a/erpnext/erpnext_integrations/doctype/shopify_settings/shopify_settings.js b/erpnext/erpnext_integrations/doctype/shopify_settings/shopify_settings.js
index 1574795dfa..a926a7e52a 100644
--- a/erpnext/erpnext_integrations/doctype/shopify_settings/shopify_settings.js
+++ b/erpnext/erpnext_integrations/doctype/shopify_settings/shopify_settings.js
@@ -36,6 +36,10 @@ frappe.ui.form.on("Shopify Settings", "refresh", function(frm){
frm.toggle_reqd("delivery_note_series", frm.doc.sync_delivery_note);
}
+
+ let app_link = "Ecommerce Integrations "
+ frm.dashboard.add_comment(__("Shopify Integration will be removed from ERPNext in Version 14. Please install {0} app to continue using it.", [app_link]), "yellow", true);
+
})
$.extend(erpnext_integrations.shopify_settings, {
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index b2597470d4..0012641b66 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -296,3 +296,4 @@ erpnext.patches.v13_0.update_subscription_status_in_memberships
erpnext.patches.v13_0.update_export_type_for_gst
erpnext.patches.v13_0.update_tds_check_field #3
erpnext.patches.v13_0.update_recipient_email_digest
+erpnext.patches.v13_0.shopify_deprecation_warning
\ No newline at end of file
diff --git a/erpnext/patches/v13_0/shopify_deprecation_warning.py b/erpnext/patches/v13_0/shopify_deprecation_warning.py
new file mode 100644
index 0000000000..8b0f1935cf
--- /dev/null
+++ b/erpnext/patches/v13_0/shopify_deprecation_warning.py
@@ -0,0 +1,15 @@
+import click
+import frappe
+
+
+def execute():
+
+ frappe.reload_doc("erpnext_integrations", "doctype", "shopify_settings")
+ if not frappe.db.get_single_value("Shopify Settings", "enable_shopify"):
+ return
+
+ click.secho(
+ "Shopify Integration is moved to a separate app and will be removed from ERPNext in version-14.\n"
+ "Please install the app to continue using the integration: https://github.com/frappe/ecommerce_integrations",
+ fg="yellow",
+ )
From 8800aaaee7e9928ddc0148aad47c2d50d5f83030 Mon Sep 17 00:00:00 2001
From: Subin Tom
Date: Tue, 13 Jul 2021 14:58:17 +0530
Subject: [PATCH 207/386] feat: Added fields for dispatch address in Sales
Order, Sales Invoice, Delivery Note for Eway Bill
---
.../doctype/sales_invoice/sales_invoice.json | 19 +++++++++++++++++-
erpnext/regional/india/utils.py | 10 ++++++----
.../doctype/sales_order/sales_order.json | 20 ++++++++++++++++++-
.../doctype/delivery_note/delivery_note.json | 19 +++++++++++++++++-
4 files changed, 61 insertions(+), 7 deletions(-)
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
index e7dd6b8a60..0a9a105b7c 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
@@ -48,6 +48,8 @@
"shipping_address",
"company_address",
"company_address_display",
+ "dispatch_address_name",
+ "dispatch_address",
"currency_and_price_list",
"currency",
"conversion_rate",
@@ -1966,6 +1968,21 @@
"fieldname": "disable_rounded_total",
"fieldtype": "Check",
"label": "Disable Rounded Total"
+ },
+ {
+ "allow_on_submit": 1,
+ "fieldname": "dispatch_address_name",
+ "fieldtype": "Link",
+ "label": "Dispatch Address Name",
+ "options": "Address",
+ "print_hide": 1
+ },
+ {
+ "allow_on_submit": 1,
+ "fieldname": "dispatch_address",
+ "fieldtype": "Small Text",
+ "label": "Dispatch Address",
+ "read_only": 1
}
],
"icon": "fa fa-file-text",
@@ -1978,7 +1995,7 @@
"link_fieldname": "consolidated_invoice"
}
],
- "modified": "2021-05-20 22:48:33.988881",
+ "modified": "2021-07-08 14:03:55.502522",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice",
diff --git a/erpnext/regional/india/utils.py b/erpnext/regional/india/utils.py
index a4466e78f2..657fd380b4 100644
--- a/erpnext/regional/india/utils.py
+++ b/erpnext/regional/india/utils.py
@@ -431,9 +431,11 @@ def get_ewb_data(dt, dn):
company_address = frappe.get_doc('Address', doc.company_address)
billing_address = frappe.get_doc('Address', doc.customer_address)
+ #added dispatch address
+ dispatch_address = frappe.get_doc('Address', doc.dispatch_address_name)
shipping_address = frappe.get_doc('Address', doc.shipping_address_name)
- data = get_address_details(data, doc, company_address, billing_address)
+ data = get_address_details(data, doc, company_address, billing_address, dispatch_address)
data.itemList = []
data.totalValue = doc.total
@@ -519,10 +521,10 @@ def get_gstins_for_company(company):
`tabDynamic Link`.link_name = %(company)s""", {"company": company})
return company_gstins
-def get_address_details(data, doc, company_address, billing_address):
+def get_address_details(data, doc, company_address, billing_address, dispatch_address):
data.fromPincode = validate_pincode(company_address.pincode, 'Company Address')
- data.fromStateCode = data.actualFromStateCode = validate_state_code(
- company_address.gst_state_number, 'Company Address')
+ data.fromStateCode = validate_state_code(company_address.gst_state_number, 'Company Address')
+ data.actualFromStateCode = validate_state_code(dispatch_address.gst_state_number, 'Company Address')
if not doc.billing_address_gstin or len(doc.billing_address_gstin) < 15:
data.toGstin = 'URP'
diff --git a/erpnext/selling/doctype/sales_order/sales_order.json b/erpnext/selling/doctype/sales_order/sales_order.json
index 762b6f1d6c..d31db820ab 100644
--- a/erpnext/selling/doctype/sales_order/sales_order.json
+++ b/erpnext/selling/doctype/sales_order/sales_order.json
@@ -38,6 +38,8 @@
"col_break46",
"shipping_address_name",
"shipping_address",
+ "dispatch_address_name",
+ "dispatch_address",
"customer_group",
"territory",
"currency_and_price_list",
@@ -1486,13 +1488,29 @@
"fieldname": "disable_rounded_total",
"fieldtype": "Check",
"label": "Disable Rounded Total"
+ },
+ {
+ "allow_on_submit": 1,
+ "fieldname": "dispatch_address_name",
+ "fieldtype": "Link",
+ "label": "Dispatch Address Name",
+ "options": "Address",
+ "print_hide": 1
+ },
+ {
+ "allow_on_submit": 1,
+ "depends_on": "dispatch_address_name",
+ "fieldname": "dispatch_address",
+ "fieldtype": "Small Text",
+ "label": "Dispatch Address",
+ "read_only": 1
}
],
"icon": "fa fa-file-text",
"idx": 105,
"is_submittable": 1,
"links": [],
- "modified": "2021-04-15 23:55:13.439068",
+ "modified": "2021-07-08 21:37:44.177493",
"modified_by": "Administrator",
"module": "Selling",
"name": "Sales Order",
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.json b/erpnext/stock/doctype/delivery_note/delivery_note.json
index f20e76f5bf..dbfeb4a10b 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.json
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.json
@@ -32,6 +32,8 @@
"contact_info",
"shipping_address_name",
"shipping_address",
+ "dispatch_address_name",
+ "dispatch_address",
"contact_person",
"contact_display",
"contact_mobile",
@@ -1282,13 +1284,28 @@
"fieldname": "disable_rounded_total",
"fieldtype": "Check",
"label": "Disable Rounded Total"
+ },
+ {
+ "fieldname": "dispatch_address_name",
+ "fieldtype": "Link",
+ "label": "Dispatch Address Name",
+ "options": "Address",
+ "print_hide": 1
+ },
+ {
+ "depends_on": "dispatch_address_name",
+ "fieldname": "dispatch_address",
+ "fieldtype": "Small Text",
+ "label": "Dispatch Address",
+ "print_hide": 1,
+ "read_only": 1
}
],
"icon": "fa fa-truck",
"idx": 146,
"is_submittable": 1,
"links": [],
- "modified": "2021-06-11 19:27:30.901112",
+ "modified": "2021-07-08 21:37:20.802652",
"modified_by": "Administrator",
"module": "Stock",
"name": "Delivery Note",
From 6ba11a382a75232166109e7ffe2adefbe6181c66 Mon Sep 17 00:00:00 2001
From: Subin Tom
Date: Mon, 19 Jul 2021 14:37:12 +0530
Subject: [PATCH 208/386] test: Updated test case for Eway bill
---
.../sales_invoice/test_sales_invoice.py | 27 +++++++++++++++++++
erpnext/regional/india/utils.py | 4 +--
2 files changed, 29 insertions(+), 2 deletions(-)
diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
index dbc7f8632f..70bccd7166 100644
--- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
@@ -1908,6 +1908,8 @@ class TestSalesInvoice(unittest.TestCase):
self.assertEqual(data['billLists'][0]['sgstValue'], 5400)
self.assertEqual(data['billLists'][0]['vehicleNo'], 'KA12KA1234')
self.assertEqual(data['billLists'][0]['itemList'][0]['taxableAmount'], 60000)
+ self.assertEqual(data['billLists'][0]['actualFromStateCode'],7)
+ self.assertEqual(data['billLists'][0]['fromStateCode'],27)
def test_einvoice_submission_without_irn(self):
# init
@@ -2062,6 +2064,30 @@ def make_test_address_for_ewaybill():
address.save()
+ if not frappe.db.exists('Address', '_Test Dispatch-Address for Eway bill-Shipping'):
+ address = frappe.get_doc({
+ "address_line1": "_Test Dispatch Address Line 1",
+ "address_title": "_Test Dispatch-Address for Eway bill",
+ "address_type": "Shipping",
+ "city": "_Test City",
+ "state": "Test State",
+ "country": "India",
+ "doctype": "Address",
+ "is_primary_address": 0,
+ "phone": "+910000000000",
+ "gstin": "07AAACC1206D1ZI",
+ "gst_state": "Delhi",
+ "gst_state_number": "07",
+ "pincode": "1100101"
+ }).insert()
+
+ address.append("links", {
+ "link_doctype": "Company",
+ "link_name": "_Test Company"
+ })
+
+ address.save()
+
def make_test_transporter_for_ewaybill():
if not frappe.db.exists('Supplier', '_Test Transporter'):
frappe.get_doc({
@@ -2100,6 +2126,7 @@ def make_sales_invoice_for_ewaybill():
si.distance = 2000
si.company_address = "_Test Address for Eway bill-Billing"
si.customer_address = "_Test Customer-Address for Eway bill-Shipping"
+ si.dispatch_address_name = "_Test Dispatch-Address for Eway bill-Shipping"
si.vehicle_no = "KA12KA1234"
si.gst_category = "Registered Regular"
si.mode_of_transport = 'Road'
diff --git a/erpnext/regional/india/utils.py b/erpnext/regional/india/utils.py
index 657fd380b4..04db9b3abe 100644
--- a/erpnext/regional/india/utils.py
+++ b/erpnext/regional/india/utils.py
@@ -432,7 +432,7 @@ def get_ewb_data(dt, dn):
billing_address = frappe.get_doc('Address', doc.customer_address)
#added dispatch address
- dispatch_address = frappe.get_doc('Address', doc.dispatch_address_name)
+ dispatch_address = frappe.get_doc('Address', doc.dispatch_address_name) if doc.dispatch_address_name else company_address
shipping_address = frappe.get_doc('Address', doc.shipping_address_name)
data = get_address_details(data, doc, company_address, billing_address, dispatch_address)
@@ -524,7 +524,7 @@ def get_gstins_for_company(company):
def get_address_details(data, doc, company_address, billing_address, dispatch_address):
data.fromPincode = validate_pincode(company_address.pincode, 'Company Address')
data.fromStateCode = validate_state_code(company_address.gst_state_number, 'Company Address')
- data.actualFromStateCode = validate_state_code(dispatch_address.gst_state_number, 'Company Address')
+ data.actualFromStateCode = validate_state_code(dispatch_address.gst_state_number, 'Dispatch Address')
if not doc.billing_address_gstin or len(doc.billing_address_gstin) < 15:
data.toGstin = 'URP'
From f99696b75d3819214b3849bdc29d43d16142e4ce Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Mon, 2 Aug 2021 23:15:44 +0530
Subject: [PATCH 209/386] fix: Condition for fetching Payment Terms from
Sales/Purchase Orders
---
erpnext/controllers/accounts_controller.py | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index 913e70b30c..f475bc2fe2 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -1101,16 +1101,16 @@ class AccountsController(TransactionBase):
base_grand_total = flt(grand_total * self.get("conversion_rate"), self.precision("base_grand_total"))
if not self.get("payment_schedule"):
+ if self.doctype in ["Sales Invoice", "Purchase Invoice"] and not self.get("payment_terms_template"):
+ po_or_so, doctype, fieldname = self.get_order_details()
+
if self.get("payment_terms_template"):
data = get_payment_terms(self.payment_terms_template, posting_date, grand_total, base_grand_total)
for item in data:
self.append("payment_schedule", item)
- elif self.doctype in ["Sales Invoice", "Purchase Invoice"]:
- po_or_so, doctype, fieldname = self.get_order_details()
-
- if self.linked_order_has_payment_terms(po_or_so, fieldname, doctype):
- self.fetch_payment_terms_from_order(po_or_so, doctype)
+ elif self.doctype in ["Sales Invoice", "Purchase Invoice"] and self.linked_order_has_payment_terms(po_or_so, fieldname, doctype):
+ self.fetch_payment_terms_from_order(po_or_so, doctype)
elif self.doctype not in ["Purchase Receipt"]:
data = dict(due_date=due_date, invoice_portion=100, payment_amount=grand_total, base_payment_amount=base_grand_total)
From 373ed1f65c3b6fc66ae03c829a562cb884c37b6c Mon Sep 17 00:00:00 2001
From: Frappe PR Bot
Date: Tue, 3 Aug 2021 13:28:50 +0530
Subject: [PATCH 210/386] fix: remove limit from stock balance report (#26773)
(#26779)
(cherry picked from commit b3740e9afc375624dc478c97a97f757e06de084f)
Co-authored-by: Ankush
---
erpnext/stock/report/stock_balance/stock_balance.py | 8 --------
1 file changed, 8 deletions(-)
diff --git a/erpnext/stock/report/stock_balance/stock_balance.py b/erpnext/stock/report/stock_balance/stock_balance.py
index b6a8063189..9e56ad4130 100644
--- a/erpnext/stock/report/stock_balance/stock_balance.py
+++ b/erpnext/stock/report/stock_balance/stock_balance.py
@@ -16,8 +16,6 @@ def execute(filters=None):
is_reposting_item_valuation_in_progress()
if not filters: filters = {}
- validate_filters(filters)
-
from_date = filters.get('from_date')
to_date = filters.get('to_date')
@@ -295,12 +293,6 @@ def get_item_reorder_details(items):
return dict((d.parent + d.warehouse, d) for d in item_reorder_details)
-def validate_filters(filters):
- if not (filters.get("item_code") or filters.get("warehouse")):
- sle_count = flt(frappe.db.sql("""select count(name) from `tabStock Ledger Entry`""")[0][0])
- if sle_count > 500000:
- frappe.throw(_("Please set filter based on Item or Warehouse due to a large amount of entries."))
-
def get_variants_attributes():
'''Return all item variant attributes.'''
return [i.name for i in frappe.get_all('Item Attribute')]
From 5a442f1bce2de9eaccd82f39aca86118680c3b57 Mon Sep 17 00:00:00 2001
From: Frappe PR Bot
Date: Tue, 3 Aug 2021 13:29:10 +0530
Subject: [PATCH 211/386] fix: change format string to percent string
interpolation (#26774) (#26778)
(cherry picked from commit 7fe588e236051b9e03cd1b1934fa0a88379716b7)
Co-authored-by: Alan <2.alan.tom@gmail.com>
---
.../patches/v13_0/add_missing_fg_item_for_stock_entry.py | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/erpnext/patches/v13_0/add_missing_fg_item_for_stock_entry.py b/erpnext/patches/v13_0/add_missing_fg_item_for_stock_entry.py
index d7ad1fc696..0d8109c41a 100644
--- a/erpnext/patches/v13_0/add_missing_fg_item_for_stock_entry.py
+++ b/erpnext/patches/v13_0/add_missing_fg_item_for_stock_entry.py
@@ -30,19 +30,20 @@ def execute():
return
repost_stock_entries = []
+
stock_entries = frappe.db.sql_list('''
SELECT
se.name
FROM
`tabStock Entry` se
WHERE
- se.purpose = 'Manufacture' and se.docstatus < 2 and se.work_order in {work_orders}
+ se.purpose = 'Manufacture' and se.docstatus < 2 and se.work_order in %s
and not exists(
select name from `tabStock Entry Detail` sed where sed.parent = se.name and sed.is_finished_item = 1
)
- Order BY
+ ORDER BY
se.posting_date, se.posting_time
- '''.format(work_orders=tuple(work_orders)))
+ ''', (work_orders,))
if stock_entries:
print('Length of stock entries', len(stock_entries))
From 85815f989c6ab5fd5a89bf4d5ea71ffdb8c4eb0d Mon Sep 17 00:00:00 2001
From: Frappe PR Bot
Date: Tue, 3 Aug 2021 20:06:07 +0530
Subject: [PATCH 212/386] fix: Reset weight_per_unit on replacing Item (#26619)
(#26791)
* fix: Assign Item's default weight_per_unit as its weight_per_unit in get_item_details
* fix: Set weight_uom in get_item_details as Item's default weight_uom
(cherry picked from commit 471f48f64db0f8da9d4703f4b82b6f9517fbacae)
Co-authored-by: Ganga Manoj
---
erpnext/stock/get_item_details.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py
index cf52803fca..2ed7a04ba8 100644
--- a/erpnext/stock/get_item_details.py
+++ b/erpnext/stock/get_item_details.py
@@ -312,8 +312,8 @@ def get_basic_details(args, item, overwrite_warehouse=True):
"transaction_date": args.get("transaction_date"),
"against_blanket_order": args.get("against_blanket_order"),
"bom_no": item.get("default_bom"),
- "weight_per_unit": args.get("weight_per_unit") or item.get("weight_per_unit"),
- "weight_uom": args.get("weight_uom") or item.get("weight_uom")
+ "weight_per_unit": item.get("weight_per_unit"),
+ "weight_uom": item.get("weight_uom")
})
if item.get("enable_deferred_revenue") or item.get("enable_deferred_expense"):
From 1b9a5c851d372ea2dd5119a0d8e95a79d583bbf5 Mon Sep 17 00:00:00 2001
From: Frappe PR Bot
Date: Tue, 3 Aug 2021 20:06:36 +0530
Subject: [PATCH 213/386] fix: incorrect amount in work order required items
table. (#26585) (#26623)
* fix: amount in work order not equal to rate * qty
* fix: patch for amount in work order required items
(cherry picked from commit cd12d95a246bcf5c49eda78fe8ce4fa9c90e6b76)
Co-authored-by: Ankush
---
erpnext/manufacturing/doctype/bom/bom.py | 2 +-
erpnext/manufacturing/doctype/work_order/work_order.py | 2 +-
erpnext/patches.txt | 1 +
.../v13_0/update_amt_in_work_order_required_items.py | 10 ++++++++++
4 files changed, 13 insertions(+), 2 deletions(-)
create mode 100644 erpnext/patches/v13_0/update_amt_in_work_order_required_items.py
diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py
index ebd9ae2dc5..4e93fc6799 100644
--- a/erpnext/manufacturing/doctype/bom/bom.py
+++ b/erpnext/manufacturing/doctype/bom/bom.py
@@ -774,7 +774,7 @@ def get_bom_items_as_dict(bom, company, qty=1, fetch_exploded=1, fetch_scrap_ite
item.image,
bom.project,
bom_item.rate,
- bom_item.amount,
+ sum(bom_item.{qty_field}/ifnull(bom.quantity, 1)) * bom_item.rate * %(qty)s as amount,
item.stock_uom,
item.item_group,
item.allow_alternative_item,
diff --git a/erpnext/manufacturing/doctype/work_order/work_order.py b/erpnext/manufacturing/doctype/work_order/work_order.py
index 69812c7452..282b5d0afe 100644
--- a/erpnext/manufacturing/doctype/work_order/work_order.py
+++ b/erpnext/manufacturing/doctype/work_order/work_order.py
@@ -655,7 +655,7 @@ class WorkOrder(Document):
for item in sorted(item_dict.values(), key=lambda d: d['idx'] or 9999):
self.append('required_items', {
'rate': item.rate,
- 'amount': item.amount,
+ 'amount': item.rate * item.qty,
'operation': item.operation or operation,
'item_code': item.item_code,
'item_name': item.item_name,
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 0012641b66..ae01496f02 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -293,6 +293,7 @@ erpnext.patches.v13_0.update_job_card_details
erpnext.patches.v13_0.update_level_in_bom #1234sswef
erpnext.patches.v13_0.add_missing_fg_item_for_stock_entry
erpnext.patches.v13_0.update_subscription_status_in_memberships
+erpnext.patches.v13_0.update_amt_in_work_order_required_items
erpnext.patches.v13_0.update_export_type_for_gst
erpnext.patches.v13_0.update_tds_check_field #3
erpnext.patches.v13_0.update_recipient_email_digest
diff --git a/erpnext/patches/v13_0/update_amt_in_work_order_required_items.py b/erpnext/patches/v13_0/update_amt_in_work_order_required_items.py
new file mode 100644
index 0000000000..eae5ff60b9
--- /dev/null
+++ b/erpnext/patches/v13_0/update_amt_in_work_order_required_items.py
@@ -0,0 +1,10 @@
+import frappe
+
+def execute():
+ """ Correct amount in child table of required items table."""
+
+ frappe.reload_doc("manufacturing", "doctype", "work_order")
+ frappe.reload_doc("manufacturing", "doctype", "work_order_item")
+
+ frappe.db.sql("""UPDATE `tabWork Order Item` SET amount = rate * required_qty""")
+
From 9f94c19752dbca0f72d497e47b751ee5104e1e24 Mon Sep 17 00:00:00 2001
From: Dany Robert
Date: Wed, 4 Aug 2021 10:01:44 +0530
Subject: [PATCH 214/386] fix: ignore permission to update call log (#26797)
Backport of #26112
#no-docs
---
erpnext/telephony/doctype/call_log/call_log.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/telephony/doctype/call_log/call_log.py b/erpnext/telephony/doctype/call_log/call_log.py
index 4d553df08b..c00dfa9056 100644
--- a/erpnext/telephony/doctype/call_log/call_log.py
+++ b/erpnext/telephony/doctype/call_log/call_log.py
@@ -142,7 +142,7 @@ def link_existing_conversations(doc, state):
for log in logs:
call_log = frappe.get_doc('Call Log', log)
call_log.add_link(link_type=doc.doctype, link_name=doc.name)
- call_log.save()
+ call_log.save(ignore_permissions=True)
frappe.db.commit()
except Exception:
frappe.log_error(title=_('Error during caller information update'))
From df477dcae6de059c7a05bcf16f81867469cd1ff1 Mon Sep 17 00:00:00 2001
From: Anupam Kumar
Date: Wed, 4 Aug 2021 14:02:43 +0530
Subject: [PATCH 215/386] fix: bank remittance report issue (#26398) (#26766)
---
erpnext/payroll/report/bank_remittance/bank_remittance.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/erpnext/payroll/report/bank_remittance/bank_remittance.py b/erpnext/payroll/report/bank_remittance/bank_remittance.py
index 500543ceb0..05a5366a5c 100644
--- a/erpnext/payroll/report/bank_remittance/bank_remittance.py
+++ b/erpnext/payroll/report/bank_remittance/bank_remittance.py
@@ -95,6 +95,7 @@ def execute(filters=None):
"amount": salary.net_pay,
}
data.append(row)
+
return columns, data
def get_bank_accounts():
@@ -116,7 +117,7 @@ def get_payroll_entries(accounts, filters):
entries = get_all("Payroll Entry", payroll_filter, ["name", "payment_account"])
payment_accounts = [d.payment_account for d in entries]
- set_company_account(payment_accounts, entries)
+ entries = set_company_account(payment_accounts, entries)
return entries
def get_salary_slips(payroll_entries):
From 13192e1db1606c2db289360d6e0de1c535875bc3 Mon Sep 17 00:00:00 2001
From: Frappe PR Bot
Date: Wed, 4 Aug 2021 17:07:22 +0530
Subject: [PATCH 216/386] fix: trigger lost reason dialog when status is
changed to lost (#26811) (#26812)
(cherry picked from commit e5d8ba65ca1c982ff4a8db0352e81939ae64665f)
Co-authored-by: Mohammed Yusuf Shaikh <49878143+mohammedyusufshaikh@users.noreply.github.com>
---
erpnext/crm/doctype/opportunity/opportunity.js | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/erpnext/crm/doctype/opportunity/opportunity.js b/erpnext/crm/doctype/opportunity/opportunity.js
index ac374a95f4..089a63fc1c 100644
--- a/erpnext/crm/doctype/opportunity/opportunity.js
+++ b/erpnext/crm/doctype/opportunity/opportunity.js
@@ -53,6 +53,13 @@ frappe.ui.form.on("Opportunity", {
frm.get_field("items").grid.set_multiple_add("item_code", "qty");
},
+ status:function(frm){
+ if (frm.doc.status == "Lost"){
+ frm.trigger('set_as_lost_dialog');
+ }
+
+ },
+
customer_address: function(frm, cdt, cdn) {
erpnext.utils.get_address_display(frm, 'customer_address', 'address_display', false);
},
@@ -91,11 +98,6 @@ frappe.ui.form.on("Opportunity", {
frm.add_custom_button(__('Quotation'),
cur_frm.cscript.create_quotation, __('Create'));
- if(doc.status!=="Quotation") {
- frm.add_custom_button(__('Lost'), () => {
- frm.trigger('set_as_lost_dialog');
- });
- }
}
if(!frm.doc.__islocal && frm.perm[0].write && frm.doc.docstatus==0) {
From 8328f4523021e2c187fa6ec17beae20ffe500f04 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Wed, 4 Aug 2021 03:15:13 +0530
Subject: [PATCH 217/386] fix: Rename test to reflect changes in code
---
erpnext/buying/doctype/purchase_order/test_purchase_order.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/buying/doctype/purchase_order/test_purchase_order.py b/erpnext/buying/doctype/purchase_order/test_purchase_order.py
index 474c9cf3df..d7db27cb54 100644
--- a/erpnext/buying/doctype/purchase_order/test_purchase_order.py
+++ b/erpnext/buying/doctype/purchase_order/test_purchase_order.py
@@ -632,7 +632,7 @@ class TestPurchaseOrder(unittest.TestCase):
else:
raise Exception
- def test_terms_does_not_copy(self):
+ def test_terms_are_not_copied_if_automatically_fetch_payment_terms_is_unchecked(self):
po = create_purchase_order()
self.assertTrue(po.get('payment_schedule'))
From 8fced95f8cad1a3e1d2561f2beb800b416b535ba Mon Sep 17 00:00:00 2001
From: Noah Jacob
Date: Mon, 28 Jun 2021 16:50:20 +0530
Subject: [PATCH 218/386] feat: over transfer allowance for material transfers
---
.../doctype/material_request/material_request.py | 9 ++++++++-
.../stock/doctype/stock_settings/stock_settings.json | 11 +++++++++--
2 files changed, 17 insertions(+), 3 deletions(-)
diff --git a/erpnext/stock/doctype/material_request/material_request.py b/erpnext/stock/doctype/material_request/material_request.py
index 3ad9909ad0..026b85e26d 100644
--- a/erpnext/stock/doctype/material_request/material_request.py
+++ b/erpnext/stock/doctype/material_request/material_request.py
@@ -162,8 +162,15 @@ class MaterialRequest(BuyingController):
from `tabStock Entry Detail` where material_request = %s
and material_request_item = %s and docstatus = 1""",
(self.name, d.name))[0][0])
+ mr_qty_allowance = frappe.db.get_single_value('Stock Settings', 'mr_qty_allowance')
- if d.ordered_qty and d.ordered_qty > d.stock_qty:
+ if mr_qty_allowance:
+ allowed_qty = d.qty + (d.qty * (mr_qty_allowance/100))
+ if d.ordered_qty and d.ordered_qty > allowed_qty:
+ frappe.throw(_("The total Issue / Transfer quantity {0} in Material Request {1} \
+ cannot be greater than allowed requested quantity {2} for Item {3}").format(d.ordered_qty, d.parent, allowed_qty, d.item_code))
+
+ elif d.ordered_qty and d.ordered_qty > d.stock_qty:
frappe.throw(_("The total Issue / Transfer quantity {0} in Material Request {1} \
cannot be greater than requested quantity {2} for Item {3}").format(d.ordered_qty, d.parent, d.qty, d.item_code))
diff --git a/erpnext/stock/doctype/stock_settings/stock_settings.json b/erpnext/stock/doctype/stock_settings/stock_settings.json
index 2a9dcfb67e..f75cb56138 100644
--- a/erpnext/stock/doctype/stock_settings/stock_settings.json
+++ b/erpnext/stock/doctype/stock_settings/stock_settings.json
@@ -18,6 +18,7 @@
"section_break_9",
"over_delivery_receipt_allowance",
"role_allowed_to_over_deliver_receive",
+ "mr_qty_allowance",
"column_break_12",
"auto_insert_price_list_rate_if_missing",
"allow_negative_stock",
@@ -283,6 +284,12 @@
"fieldtype": "Select",
"label": "Action If Quality Inspection Is Rejected",
"options": "Stop\nWarn"
+ },
+ {
+ "description": "The percentage you are allowed to transfer more against the quantity ordered. For example, if you have ordered 100 units, and your Allowance is 10%, then you are allowed transfer 110 units.",
+ "fieldname": "mr_qty_allowance",
+ "fieldtype": "Float",
+ "label": "Over Transfer Allowance"
}
],
"icon": "icon-cog",
@@ -290,7 +297,7 @@
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
- "modified": "2021-07-10 16:17:42.159829",
+ "modified": "2021-06-28 17:02:26.683002",
"modified_by": "Administrator",
"module": "Stock",
"name": "Stock Settings",
@@ -310,4 +317,4 @@
"sort_field": "modified",
"sort_order": "ASC",
"track_changes": 1
-}
\ No newline at end of file
+}
From 673bc58193354adf0973b474ff3ff9072918d279 Mon Sep 17 00:00:00 2001
From: Noah Jacob
Date: Wed, 30 Jun 2021 20:16:50 +0530
Subject: [PATCH 219/386] test: test case for over transfer of materials
---
.../material_request/test_material_request.py | 52 +++++++++++++++++++
1 file changed, 52 insertions(+)
diff --git a/erpnext/stock/doctype/material_request/test_material_request.py b/erpnext/stock/doctype/material_request/test_material_request.py
index 72a3a5e67c..b4776ba249 100644
--- a/erpnext/stock/doctype/material_request/test_material_request.py
+++ b/erpnext/stock/doctype/material_request/test_material_request.py
@@ -329,6 +329,58 @@ class TestMaterialRequest(unittest.TestCase):
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_over_transfer_qty_allowance(self):
+ mr = frappe.new_doc('Material Request')
+ mr.company = "_Test Company"
+ mr.scheduled_date = today()
+ mr.append('items',{
+ "item_code": "_Test FG Item",
+ "item_name": "_Test FG Item",
+ "qty": 10,
+ "schedule_date": today(),
+ "uom": "_Test UOM 1",
+ "warehouse": "_Test Warehouse - _TC"
+ })
+
+ mr.material_request_type = "Material Transfer"
+ mr.insert()
+ mr.submit()
+
+ frappe.db.set_value('Stock Settings', None, 'mr_qty_allowance', 20)
+
+ # map a stock entry
+
+ se_doc = make_stock_entry(mr.name)
+ se_doc.update({
+ "posting_date": today(),
+ "posting_time": "00:00",
+ })
+ se_doc.get("items")[0].update({
+ "qty": 13,
+ "transfer_qty": 12.0,
+ "s_warehouse": "_Test Warehouse - _TC",
+ "t_warehouse": "_Test Warehouse 1 - _TC",
+ "basic_rate": 1.0
+ })
+
+ # make available the qty in _Test Warehouse 1 before transfer
+ sr = frappe.new_doc("Stock Reconciliation")
+ sr.company = "_Test Company"
+ sr.purpose = "Opening Stock"
+ sr.append('items', {
+ "item_code": "_Test FG Item",
+ "warehouse": "_Test Warehouse - _TC",
+ "qty": 20,
+ "valuation_rate": 0.01
+ })
+ sr.insert()
+ sr.submit()
+ se = frappe.copy_doc(se_doc)
+ se.insert()
+ self.assertRaises(frappe.ValidationError)
+ se.items[0].qty = 12
+ se.submit()
+
def test_completed_qty_for_over_transfer(self):
existing_requested_qty_item1 = self._get_requested_qty("_Test Item Home Desktop 100", "_Test Warehouse - _TC")
existing_requested_qty_item2 = self._get_requested_qty("_Test Item Home Desktop 200", "_Test Warehouse - _TC")
From bf8d0c256df51dd4495f8a0bbf80b8ce3b5253ab Mon Sep 17 00:00:00 2001
From: Frappe PR Bot
Date: Wed, 4 Aug 2021 22:01:17 +0530
Subject: [PATCH 220/386] fix: typo in error message (#26816) (#26817)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
(cherry picked from commit 005291e6dd4088fca23fa36b85f1755510939823)
Co-authored-by: François de Ryckel
---
erpnext/accounts/doctype/account/account.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/accounts/doctype/account/account.py b/erpnext/accounts/doctype/account/account.py
index 1be2fbf5c8..f763df0852 100644
--- a/erpnext/accounts/doctype/account/account.py
+++ b/erpnext/accounts/doctype/account/account.py
@@ -230,7 +230,7 @@ class Account(NestedSet):
if self.check_gle_exists():
throw(_("Account with existing transaction can not be converted to group."))
elif self.account_type and not self.flags.exclude_account_type_check:
- throw(_("Cannot covert to Group because Account Type is selected."))
+ throw(_("Cannot convert to Group because Account Type is selected."))
else:
self.is_group = 1
self.save()
From 23c104555b33d35d381543adce7d6bf15be91460 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Thu, 5 Aug 2021 00:28:42 +0530
Subject: [PATCH 221/386] fix: Remove irrelevant code
---
.../purchase_invoice/purchase_invoice.py | 30 -------------------
.../purchase_receipt/test_purchase_receipt.py | 27 -----------------
2 files changed, 57 deletions(-)
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
index 28a9bddc42..f7992797ed 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
@@ -1142,36 +1142,6 @@ class PurchaseInvoice(BuyingController):
if update:
self.db_set('status', self.status, update_modified = update_modified)
-# to get details of purchase invoice/receipt from which this doc was created for exchange rate difference handling
-def get_purchase_document_details(doc):
- if doc.doctype == 'Purchase Invoice':
- doc_reference = 'purchase_receipt'
- items_reference = 'pr_detail'
- parent_doctype = 'Purchase Receipt'
- child_doctype = 'Purchase Receipt Item'
- else:
- doc_reference = 'purchase_invoice'
- items_reference = 'purchase_invoice_item'
- parent_doctype = 'Purchase Invoice'
- child_doctype = 'Purchase Invoice Item'
-
- purchase_receipts_or_invoices = []
- items = []
-
- for item in doc.get('items'):
- if item.get(doc_reference):
- purchase_receipts_or_invoices.append(item.get(doc_reference))
- if item.get(items_reference):
- items.append(item.get(items_reference))
-
- exchange_rate_map = frappe._dict(frappe.get_all(parent_doctype, filters={'name': ('in',
- purchase_receipts_or_invoices)}, fields=['name', 'conversion_rate'], as_list=1))
-
- net_rate_map = frappe._dict(frappe.get_all(child_doctype, filters={'name': ('in',
- items)}, fields=['name', 'net_rate'], as_list=1))
-
- return exchange_rate_map, net_rate_map
-
def get_list_context(context=None):
from erpnext.controllers.website_list_for_contact import get_list_context
list_context = get_list_context(context)
diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
index 9a5064fcc7..fd6ac16fa3 100644
--- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
@@ -1052,33 +1052,6 @@ class TestPurchaseReceipt(unittest.TestCase):
frappe.db.set_value('Company', company, 'enable_perpetual_inventory_for_non_stock_items', before_test_value)
- def test_purchase_receipt_with_exchange_rate_difference(self):
- from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice as create_purchase_invoice
- from erpnext.accounts.doctype.purchase_invoice.purchase_invoice import make_purchase_receipt as create_purchase_receipt
-
- pi = create_purchase_invoice(company="_Test Company with perpetual inventory",
- cost_center = "Main - TCP1",
- warehouse = "Stores - TCP1",
- expense_account ="_Test Account Cost for Goods Sold - TCP1",
- currency = "USD", conversion_rate = 70)
-
- pr = create_purchase_receipt(pi.name)
- pr.conversion_rate = 80
- pr.items[0].purchase_invoice = pi.name
- pr.items[0].purchase_invoice_item = pi.items[0].name
-
- pr.save()
- pr.submit()
-
- # Get exchnage gain and loss account
- exchange_gain_loss_account = frappe.db.get_value('Company', pr.company, 'exchange_gain_loss_account')
-
- # fetching the latest GL Entry with exchange gain and loss account account
- amount = frappe.db.get_value('GL Entry', {'account': exchange_gain_loss_account, 'voucher_no': pr.name}, 'credit')
- discrepancy_caused_by_exchange_rate_diff = abs(pi.items[0].base_net_amount - pr.items[0].base_net_amount)
-
- self.assertEqual(discrepancy_caused_by_exchange_rate_diff, amount)
-
def test_payment_terms_are_fetched_when_creating_purchase_invoice(self):
from erpnext.accounts.doctype.payment_entry.test_payment_entry import create_payment_terms_template
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
From 0b11420147066cd11616e474554dd474171e9078 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Thu, 5 Aug 2021 00:35:45 +0530
Subject: [PATCH 222/386] fix: Disable automcatically_fetch_payment_terms after
running its associated tests
---
erpnext/buying/doctype/purchase_order/test_purchase_order.py | 2 ++
erpnext/selling/doctype/sales_order/test_sales_order.py | 2 ++
erpnext/stock/doctype/delivery_note/test_delivery_note.py | 2 ++
erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py | 2 ++
4 files changed, 8 insertions(+)
diff --git a/erpnext/buying/doctype/purchase_order/test_purchase_order.py b/erpnext/buying/doctype/purchase_order/test_purchase_order.py
index d7db27cb54..0db54e4206 100644
--- a/erpnext/buying/doctype/purchase_order/test_purchase_order.py
+++ b/erpnext/buying/doctype/purchase_order/test_purchase_order.py
@@ -988,6 +988,8 @@ class TestPurchaseOrder(unittest.TestCase):
# self.assertEqual(po.payment_terms_template, pi.payment_terms_template)
compare_payment_schedules(self, po, pi)
+ automatically_fetch_payment_terms(enable=0)
+
def make_pr_against_po(po, received_qty=0):
pr = make_purchase_receipt(po)
pr.get("items")[0].qty = received_qty or 5
diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py
index f4a089bcef..5639ee8069 100644
--- a/erpnext/selling/doctype/sales_order/test_sales_order.py
+++ b/erpnext/selling/doctype/sales_order/test_sales_order.py
@@ -1248,6 +1248,8 @@ class TestSalesOrder(unittest.TestCase):
self.assertEqual(so.payment_terms_template, si.payment_terms_template)
compare_payment_schedules(self, so, si)
+ automatically_fetch_payment_terms(enable=0)
+
def automatically_fetch_payment_terms(enable=1):
accounts_settings = frappe.get_doc("Accounts Settings")
accounts_settings.automatically_fetch_payment_terms = enable
diff --git a/erpnext/stock/doctype/delivery_note/test_delivery_note.py b/erpnext/stock/doctype/delivery_note/test_delivery_note.py
index ca8d8b99d3..756825e826 100644
--- a/erpnext/stock/doctype/delivery_note/test_delivery_note.py
+++ b/erpnext/stock/doctype/delivery_note/test_delivery_note.py
@@ -785,6 +785,8 @@ class TestDeliveryNote(unittest.TestCase):
self.assertEqual(so.payment_terms_template, si.payment_terms_template)
compare_payment_schedules(self, so, si)
+ automatically_fetch_payment_terms(enable=0)
+
def create_delivery_note(**args):
dn = frappe.new_doc("Delivery Note")
args = frappe._dict(args)
diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
index fd6ac16fa3..34ea3257d5 100644
--- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
@@ -1077,6 +1077,8 @@ class TestPurchaseReceipt(unittest.TestCase):
# self.assertEqual(po.payment_terms_template, pi.payment_terms_template)
compare_payment_schedules(self, po, pi)
+ automatically_fetch_payment_terms(enable=0)
+
def get_sl_entries(voucher_type, voucher_no):
return frappe.db.sql(""" select actual_qty, warehouse, stock_value_difference
from `tabStock Ledger Entry` where voucher_type=%s and voucher_no=%s
From 4a6ef9ab0f5d02cf86286e905a93261530be5d86 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Thu, 5 Aug 2021 00:52:55 +0530
Subject: [PATCH 223/386] fix: Compare Payment Schedules
---
.../doctype/sales_order/test_sales_order.py | 18 ++++++------------
1 file changed, 6 insertions(+), 12 deletions(-)
diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py
index 5639ee8069..a226da75cd 100644
--- a/erpnext/selling/doctype/sales_order/test_sales_order.py
+++ b/erpnext/selling/doctype/sales_order/test_sales_order.py
@@ -5,7 +5,7 @@ import json
import unittest
import frappe
import frappe.permissions
-from frappe.utils import flt, add_days, nowdate
+from frappe.utils import flt, add_days, nowdate, getdate
from frappe.core.doctype.user_permission.test_user_permission import create_user
from erpnext.selling.doctype.sales_order.sales_order \
import make_material_request, make_delivery_note, make_sales_invoice, WarehouseRequired
@@ -1256,17 +1256,11 @@ def automatically_fetch_payment_terms(enable=1):
accounts_settings.save()
def compare_payment_schedules(doc, doc1, doc2):
- payment_schedule1 = frappe.db.sql("""select payment_term, description, due_date, mode_of_payment, invoice_portion, payment_amount
- from `tabPayment Schedule`
- where parenttype=%s and parent=%s
- order by payment_term asc""", (doc1.doctype, doc1.name), as_dict=1)
-
- payment_schedule2 = frappe.db.sql("""select payment_term, description, due_date, mode_of_payment, invoice_portion, payment_amount
- from `tabPayment Schedule`
- where parenttype=%s and parent=%s
- order by payment_term asc""", (doc2.doctype, doc2.name), as_dict=1)
-
- doc.assertEqual(payment_schedule1, payment_schedule2)
+ for index, schedule in enumerate(doc1.get('payment_schedule')):
+ doc.assertEqual(schedule.payment_term, doc2.payment_schedule[index].payment_term)
+ doc.assertEqual(getdate(schedule.due_date), doc2.payment_schedule[index].due_date)
+ doc.assertEqual(schedule.invoice_portion, doc2.payment_schedule[index].invoice_portion)
+ doc.assertEqual(schedule.payment_amount, doc2.payment_schedule[index].payment_amount)
def make_sales_order(**args):
so = frappe.new_doc("Sales Order")
From 5b5a365aafead7d9d26fee0591765da41b85e581 Mon Sep 17 00:00:00 2001
From: Frappe PR Bot
Date: Thu, 5 Aug 2021 11:15:16 +0530
Subject: [PATCH 224/386] fix: POS payment modes displayed wrong total (#26808)
---
erpnext/selling/page/point_of_sale/pos_payment.js | 1 +
1 file changed, 1 insertion(+)
diff --git a/erpnext/selling/page/point_of_sale/pos_payment.js b/erpnext/selling/page/point_of_sale/pos_payment.js
index f1a166b523..63306adc6f 100644
--- a/erpnext/selling/page/point_of_sale/pos_payment.js
+++ b/erpnext/selling/page/point_of_sale/pos_payment.js
@@ -198,6 +198,7 @@ erpnext.PointOfSale.Payment = class {
const is_cash_shortcuts_invisible = !this.$payment_modes.find('.cash-shortcuts').is(':visible');
this.attach_cash_shortcuts(frm.doc);
!is_cash_shortcuts_invisible && this.$payment_modes.find('.cash-shortcuts').css('display', 'grid');
+ this.render_payment_mode_dom();
});
frappe.ui.form.on('POS Invoice', 'loyalty_amount', (frm) => {
From cf4078756dea4ac073af278e86510b2f94cee08b Mon Sep 17 00:00:00 2001
From: noahjacob
Date: Tue, 25 May 2021 16:40:39 +0530
Subject: [PATCH 225/386] fix: fixed fetching sales order of item variant in
production plan
---
.../production_plan/production_plan.py | 19 ++++++++++++++-----
1 file changed, 14 insertions(+), 5 deletions(-)
diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.py b/erpnext/manufacturing/doctype/production_plan/production_plan.py
index 6a024f275a..99b69263e0 100644
--- a/erpnext/manufacturing/doctype/production_plan/production_plan.py
+++ b/erpnext/manufacturing/doctype/production_plan/production_plan.py
@@ -118,16 +118,20 @@ class ProductionPlan(Document):
item_condition = ""
if self.item_code:
+ if frappe.db.exists('Item', self.item_code):
+ is_variant = frappe.db.get_value('Item', self.item_code, ['variant_of'])
+ if is_variant:
+ variant_of = is_variant
item_condition = ' and so_item.item_code = {0}'.format(frappe.db.escape(self.item_code))
-
+
items = frappe.db.sql("""select distinct parent, item_code, warehouse,
(qty - work_order_qty) * conversion_factor as pending_qty, description, name
from `tabSales Order Item` so_item
where parent in (%s) and docstatus = 1 and qty > work_order_qty
- and exists (select name from `tabBOM` bom where bom.item=so_item.item_code
+ and exists (select name from `tabBOM` bom where bom.item= "%s"
and bom.is_active = 1) %s""" % \
- (", ".join(["%s"] * len(so_list)), item_condition), tuple(so_list), as_dict=1)
-
+ (", ".join(["%s"] * len(so_list)), variant_of or "so_items.item_code", item_condition), tuple(so_list), as_dict=1)
+
if self.item_code:
item_condition = ' and so_item.item_code = {0}'.format(frappe.db.escape(self.item_code))
@@ -695,6 +699,10 @@ def get_sales_orders(self):
so_filter += "and so.status = %(sales_order_status)s"
if self.item_code:
+ if frappe.db.exists('Item', self.item_code):
+ is_variant = frappe.db.get_value('Item', self.item_code, ['variant_of'])
+ if is_variant:
+ variant_of = is_variant
item_filter += " and so_item.item_code = %(item)s"
open_so = frappe.db.sql("""
@@ -704,7 +712,7 @@ def get_sales_orders(self):
and so.docstatus = 1 and so.status not in ("Stopped", "Closed")
and so.company = %(company)s
and so_item.qty > so_item.work_order_qty {0} {1}
- and (exists (select name from `tabBOM` bom where bom.item=so_item.item_code
+ and (exists (select name from `tabBOM` bom where bom.item=%(item_code)s
and bom.is_active = 1)
or exists (select name from `tabPacked Item` pi
where pi.parent = so.name and pi.parent_item = so_item.item_code
@@ -715,6 +723,7 @@ def get_sales_orders(self):
"to_date": self.to_date,
"customer": self.customer,
"project": self.project,
+ "item_code": variant_of or "so_item.item_code",
"item": self.item_code,
"company": self.company,
"sales_order_status": self.sales_order_status
From 9b0b2daf4a049991dd47e93fa1202189c676110b Mon Sep 17 00:00:00 2001
From: noahjacob
Date: Wed, 26 May 2021 17:52:08 +0530
Subject: [PATCH 226/386] refactor: updated sql query for item variants
---
.../production_plan/production_plan.py | 27 +++++++++----------
1 file changed, 13 insertions(+), 14 deletions(-)
diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.py b/erpnext/manufacturing/doctype/production_plan/production_plan.py
index 99b69263e0..efb2d9235f 100644
--- a/erpnext/manufacturing/doctype/production_plan/production_plan.py
+++ b/erpnext/manufacturing/doctype/production_plan/production_plan.py
@@ -116,21 +116,21 @@ class ProductionPlan(Document):
so_list = self.get_so_mr_list("sales_order", "sales_orders")
- item_condition = ""
+ item_condition = variant_of_bom = ""
if self.item_code:
if frappe.db.exists('Item', self.item_code):
- is_variant = frappe.db.get_value('Item', self.item_code, ['variant_of'])
- if is_variant:
- variant_of = is_variant
+ has_variant_bom = frappe.db.exists({'doctype': 'BOM', 'item': self.item_code})
+ if not has_variant_bom:
+ variant_of_bom = "'%s'" % frappe.db.get_value('Item', self.item_code, ['variant_of'])
item_condition = ' and so_item.item_code = {0}'.format(frappe.db.escape(self.item_code))
-
+
items = frappe.db.sql("""select distinct parent, item_code, warehouse,
(qty - work_order_qty) * conversion_factor as pending_qty, description, name
from `tabSales Order Item` so_item
where parent in (%s) and docstatus = 1 and qty > work_order_qty
- and exists (select name from `tabBOM` bom where bom.item= "%s"
+ and exists (select name from `tabBOM` bom where bom.item= %s
and bom.is_active = 1) %s""" % \
- (", ".join(["%s"] * len(so_list)), variant_of or "so_items.item_code", item_condition), tuple(so_list), as_dict=1)
+ (", ".join(["%s"] * len(so_list)), variant_of_bom or "so_item.item_code", item_condition), tuple(so_list), as_dict=1)
if self.item_code:
item_condition = ' and so_item.item_code = {0}'.format(frappe.db.escape(self.item_code))
@@ -686,7 +686,7 @@ def get_material_request_items(row, sales_order, company,
}
def get_sales_orders(self):
- so_filter = item_filter = ""
+ so_filter = item_filter = variant_of_bom = ""
if self.from_date:
so_filter += " and so.transaction_date >= %(from_date)s"
if self.to_date:
@@ -700,9 +700,9 @@ def get_sales_orders(self):
if self.item_code:
if frappe.db.exists('Item', self.item_code):
- is_variant = frappe.db.get_value('Item', self.item_code, ['variant_of'])
- if is_variant:
- variant_of = is_variant
+ has_variant_bom = frappe.db.exists({'doctype': 'BOM', 'item': self.item_code})
+ if not has_variant_bom:
+ variant_of_bom = "'%s'" % frappe.db.get_value('Item', self.item_code, ['variant_of'])
item_filter += " and so_item.item_code = %(item)s"
open_so = frappe.db.sql("""
@@ -712,18 +712,17 @@ def get_sales_orders(self):
and so.docstatus = 1 and so.status not in ("Stopped", "Closed")
and so.company = %(company)s
and so_item.qty > so_item.work_order_qty {0} {1}
- and (exists (select name from `tabBOM` bom where bom.item=%(item_code)s
+ and (exists (select name from `tabBOM` bom where bom.item= {2}
and bom.is_active = 1)
or exists (select name from `tabPacked Item` pi
where pi.parent = so.name and pi.parent_item = so_item.item_code
and exists (select name from `tabBOM` bom where bom.item=pi.item_code
and bom.is_active = 1)))
- """.format(so_filter, item_filter), {
+ """.format(so_filter, item_filter, variant_of_bom or "so_item.item_code"), {
"from_date": self.from_date,
"to_date": self.to_date,
"customer": self.customer,
"project": self.project,
- "item_code": variant_of or "so_item.item_code",
"item": self.item_code,
"company": self.company,
"sales_order_status": self.sales_order_status
From b10465eebe4ef6839ad6b9c12bc0536c3abb7a91 Mon Sep 17 00:00:00 2001
From: Noah Jacob
Date: Thu, 3 Jun 2021 17:57:23 +0530
Subject: [PATCH 227/386] refactor: created function to get bom_item for query
---
.../production_plan/production_plan.py | 46 +++++++++++--------
1 file changed, 26 insertions(+), 20 deletions(-)
diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.py b/erpnext/manufacturing/doctype/production_plan/production_plan.py
index efb2d9235f..c2a365adb1 100644
--- a/erpnext/manufacturing/doctype/production_plan/production_plan.py
+++ b/erpnext/manufacturing/doctype/production_plan/production_plan.py
@@ -109,6 +109,15 @@ class ProductionPlan(Document):
so_mr_list = [d.get(field) for d in self.get(table) if d.get(field)]
return so_mr_list
+ def get_bom_item(self):
+ """Check if Item or if its Template has a BOM."""
+ bom_item = None
+ has_bom = frappe.db.exists({'doctype': 'BOM', 'item': self.item_code, 'docstatus': 1})
+ if not has_bom:
+ template_item = frappe.db.get_value('Item', self.item_code, ['variant_of'])
+ bom_item = "bom.item = {0}".format(frappe.db.escape(template_item)) if template_item else bom_item
+ return bom_item
+
def get_so_items(self):
# Check for empty table or empty rows
if not self.get("sales_orders") or not self.get_so_mr_list("sales_order", "sales_orders"):
@@ -116,21 +125,20 @@ class ProductionPlan(Document):
so_list = self.get_so_mr_list("sales_order", "sales_orders")
- item_condition = variant_of_bom = ""
- if self.item_code:
- if frappe.db.exists('Item', self.item_code):
- has_variant_bom = frappe.db.exists({'doctype': 'BOM', 'item': self.item_code})
- if not has_variant_bom:
- variant_of_bom = "'%s'" % frappe.db.get_value('Item', self.item_code, ['variant_of'])
+ item_condition = ""
+ bom_item = "bom.item = so_item.item_code"
+ if self.item_code and frappe.db.exists('Item', self.item_code):
+ bom_item = self.get_bom_item() or bom_item
item_condition = ' and so_item.item_code = {0}'.format(frappe.db.escape(self.item_code))
items = frappe.db.sql("""select distinct parent, item_code, warehouse,
- (qty - work_order_qty) * conversion_factor as pending_qty, description, name
- from `tabSales Order Item` so_item
- where parent in (%s) and docstatus = 1 and qty > work_order_qty
- and exists (select name from `tabBOM` bom where bom.item= %s
- and bom.is_active = 1) %s""" % \
- (", ".join(["%s"] * len(so_list)), variant_of_bom or "so_item.item_code", item_condition), tuple(so_list), as_dict=1)
+ (qty - work_order_qty) * conversion_factor as pending_qty, description, name
+ from `tabSales Order Item` so_item
+ where
+ parent in (%s) and docstatus = 1 and qty > work_order_qty
+ and exists (select name from `tabBOM` bom where %s
+ and bom.is_active = 1) %s""" % \
+ (", ".join(["%s"] * len(so_list)), bom_item, item_condition), tuple(so_list), as_dict=1)
if self.item_code:
item_condition = ' and so_item.item_code = {0}'.format(frappe.db.escape(self.item_code))
@@ -686,7 +694,8 @@ def get_material_request_items(row, sales_order, company,
}
def get_sales_orders(self):
- so_filter = item_filter = variant_of_bom = ""
+ so_filter = item_filter = ""
+ bom_item = "bom.item = so_item.item_code"
if self.from_date:
so_filter += " and so.transaction_date >= %(from_date)s"
if self.to_date:
@@ -698,11 +707,8 @@ def get_sales_orders(self):
if self.sales_order_status:
so_filter += "and so.status = %(sales_order_status)s"
- if self.item_code:
- if frappe.db.exists('Item', self.item_code):
- has_variant_bom = frappe.db.exists({'doctype': 'BOM', 'item': self.item_code})
- if not has_variant_bom:
- variant_of_bom = "'%s'" % frappe.db.get_value('Item', self.item_code, ['variant_of'])
+ if self.item_code and frappe.db.exists('Item', self.item_code):
+ bom_item = self.get_bom_item() or bom_item
item_filter += " and so_item.item_code = %(item)s"
open_so = frappe.db.sql("""
@@ -712,13 +718,13 @@ def get_sales_orders(self):
and so.docstatus = 1 and so.status not in ("Stopped", "Closed")
and so.company = %(company)s
and so_item.qty > so_item.work_order_qty {0} {1}
- and (exists (select name from `tabBOM` bom where bom.item= {2}
+ and (exists (select name from `tabBOM` bom where {2}
and bom.is_active = 1)
or exists (select name from `tabPacked Item` pi
where pi.parent = so.name and pi.parent_item = so_item.item_code
and exists (select name from `tabBOM` bom where bom.item=pi.item_code
and bom.is_active = 1)))
- """.format(so_filter, item_filter, variant_of_bom or "so_item.item_code"), {
+ """.format(so_filter, item_filter, bom_item), {
"from_date": self.from_date,
"to_date": self.to_date,
"customer": self.customer,
From 041ac339b1ba0ac04724b888fad6748b7a2f47b3 Mon Sep 17 00:00:00 2001
From: Noah Jacob
Date: Sun, 6 Jun 2021 18:08:39 +0530
Subject: [PATCH 228/386] style: improved formatting of sql query
---
.../production_plan/production_plan.py | 21 ++++++++++++-------
1 file changed, 14 insertions(+), 7 deletions(-)
diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.py b/erpnext/manufacturing/doctype/production_plan/production_plan.py
index c2a365adb1..8c27d6ccc9 100644
--- a/erpnext/manufacturing/doctype/production_plan/production_plan.py
+++ b/erpnext/manufacturing/doctype/production_plan/production_plan.py
@@ -131,15 +131,22 @@ class ProductionPlan(Document):
bom_item = self.get_bom_item() or bom_item
item_condition = ' and so_item.item_code = {0}'.format(frappe.db.escape(self.item_code))
- items = frappe.db.sql("""select distinct parent, item_code, warehouse,
- (qty - work_order_qty) * conversion_factor as pending_qty, description, name
- from `tabSales Order Item` so_item
- where
+ items = frappe.db.sql("""
+ select
+ distinct parent, item_code, warehouse,
+ (qty - work_order_qty) * conversion_factor as pending_qty,
+ description, name
+ from
+ `tabSales Order Item` so_item
+ where
parent in (%s) and docstatus = 1 and qty > work_order_qty
and exists (select name from `tabBOM` bom where %s
- and bom.is_active = 1) %s""" % \
- (", ".join(["%s"] * len(so_list)), bom_item, item_condition), tuple(so_list), as_dict=1)
-
+ and bom.is_active = 1) %s""" %
+ (", ".join(["%s"] * len(so_list)),
+ bom_item,
+ item_condition),
+ tuple(so_list), as_dict=1)
+
if self.item_code:
item_condition = ' and so_item.item_code = {0}'.format(frappe.db.escape(self.item_code))
From 6e07ec26173ae3e18f155fcf6013bd01b035c074 Mon Sep 17 00:00:00 2001
From: Frappe PR Bot
Date: Thu, 5 Aug 2021 20:13:28 +0530
Subject: [PATCH 229/386] fix: Do not fetch fully return issued purchase
receipts (#26809) (#26825)
(cherry picked from commit 1d90f7684e0fce8227fb566fa4110b96003d9ee5)
Co-authored-by: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com>
---
erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
index dc9094c3e9..c588d45a9f 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
@@ -134,7 +134,7 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
},
get_query_filters: {
docstatus: 1,
- status: ["not in", ["Closed", "Completed"]],
+ status: ["not in", ["Closed", "Completed", "Return Issued"]],
company: me.frm.doc.company,
is_return: 0
}
From e4a07d8ff349907129eccd1fdad48efa4429900d Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Thu, 5 Aug 2021 21:42:09 +0530
Subject: [PATCH 230/386] fix: Stop fetching amount while fetching Payment
Terms
---
erpnext/controllers/accounts_controller.py | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index f475bc2fe2..7f389cc32a 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -1175,10 +1175,7 @@ class AccountsController(TransactionBase):
'due_date': schedule.due_date,
'invoice_portion': schedule.invoice_portion,
'discount_type': schedule.discount_type,
- 'discount': schedule.discount,
- 'base_payment_amount': schedule.base_payment_amount,
- 'payment_amount': schedule.payment_amount,
- 'outstanding': schedule.outstanding
+ 'discount': schedule.discount
}
self.append("payment_schedule", payment_schedule)
From 5c21eea13d865103ee4d62f4922ae49b76382c4f Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Thu, 5 Aug 2021 21:50:09 +0530
Subject: [PATCH 231/386] fix: Fetch discount details from Payment Terms only
if Discount Type = Percentage
---
erpnext/controllers/accounts_controller.py | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index 7f389cc32a..78e4ad31ad 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -1174,9 +1174,14 @@ class AccountsController(TransactionBase):
'payment_term': schedule.payment_term,
'due_date': schedule.due_date,
'invoice_portion': schedule.invoice_portion,
- 'discount_type': schedule.discount_type,
- 'discount': schedule.discount
+ 'mode_of_payment': schedule.mode_of_payment,
+ 'description': schedule.description
}
+
+ if schedule.discount_type == 'Percentage':
+ payment_schedule['discount_type'] = schedule.discount_type
+ payment_schedule['discount'] = schedule.discount
+
self.append("payment_schedule", payment_schedule)
def set_due_date(self):
From fb80ca9e06ae57dbb61e1a3907b2cfc19b1fd925 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Thu, 5 Aug 2021 22:04:11 +0530
Subject: [PATCH 232/386] fix: Only fetch default Payment Terms Template if
present
---
erpnext/accounts/party.py | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/erpnext/accounts/party.py b/erpnext/accounts/party.py
index b97dc401e6..19a394f743 100644
--- a/erpnext/accounts/party.py
+++ b/erpnext/accounts/party.py
@@ -2,6 +2,7 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+from re import template
import frappe, erpnext
from frappe import _, msgprint, scrub
@@ -59,7 +60,10 @@ def _get_party_details(party=None, account=None, party_type="Customer", company=
billing_address=party_address, shipping_address=shipping_address)
if fetch_payment_terms_template:
- party_details["payment_terms_template"] = get_payment_terms_template(party.name, party_type, company)
+ payment_terms_template = get_payment_terms_template(party.name, party_type, company)
+
+ if payment_terms_template:
+ party_details["payment_terms_template"] = payment_terms_template
if not party_details.get("currency"):
party_details["currency"] = currency
From 232c7286364220e1286d593605e9401b35573486 Mon Sep 17 00:00:00 2001
From: GangaManoj
Date: Thu, 5 Aug 2021 23:04:58 +0530
Subject: [PATCH 233/386] Revert "fix: Only fetch default Payment Terms
Template if present"
This reverts commit fb80ca9e06ae57dbb61e1a3907b2cfc19b1fd925.
---
erpnext/accounts/party.py | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/erpnext/accounts/party.py b/erpnext/accounts/party.py
index 19a394f743..b97dc401e6 100644
--- a/erpnext/accounts/party.py
+++ b/erpnext/accounts/party.py
@@ -2,7 +2,6 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-from re import template
import frappe, erpnext
from frappe import _, msgprint, scrub
@@ -60,10 +59,7 @@ def _get_party_details(party=None, account=None, party_type="Customer", company=
billing_address=party_address, shipping_address=shipping_address)
if fetch_payment_terms_template:
- payment_terms_template = get_payment_terms_template(party.name, party_type, company)
-
- if payment_terms_template:
- party_details["payment_terms_template"] = payment_terms_template
+ party_details["payment_terms_template"] = get_payment_terms_template(party.name, party_type, company)
if not party_details.get("currency"):
party_details["currency"] = currency
From b13e46071a3b2118611557560ae626036ceb3b21 Mon Sep 17 00:00:00 2001
From: Frappe PR Bot
Date: Fri, 6 Aug 2021 10:39:58 +0530
Subject: [PATCH 234/386] fix: Let all System Managers be able to delete
Company transactions (#26815) (#26819)
(cherry picked from commit 884d8cf0653794af68b377e2f02ac60968a7ead1)
Co-authored-by: Ganga Manoj
---
.../transaction_deletion_record.json | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.json b/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.json
index 9313f95516..23e59472a6 100644
--- a/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.json
+++ b/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.json
@@ -54,7 +54,7 @@
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
- "modified": "2021-05-08 23:13:48.049879",
+ "modified": "2021-08-04 20:15:59.071493",
"modified_by": "Administrator",
"module": "Setup",
"name": "Transaction Deletion Record",
@@ -70,6 +70,7 @@
"report": 1,
"role": "System Manager",
"share": 1,
+ "submit": 1,
"write": 1
}
],
From 6871c076852d460e02158c06fc9e0f09f8c4dfaa Mon Sep 17 00:00:00 2001
From: Deepesh Garg
Date: Fri, 6 Aug 2021 10:53:38 +0530
Subject: [PATCH 235/386] test: Failing budget test due to project naming
---
erpnext/accounts/doctype/budget/test_budget.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/erpnext/accounts/doctype/budget/test_budget.py b/erpnext/accounts/doctype/budget/test_budget.py
index 603e21ea24..6c25f0024d 100644
--- a/erpnext/accounts/doctype/budget/test_budget.py
+++ b/erpnext/accounts/doctype/budget/test_budget.py
@@ -249,7 +249,7 @@ class TestBudget(unittest.TestCase):
def set_total_expense_zero(posting_date, budget_against_field=None, budget_against_CC=None):
if budget_against_field == "project":
- budget_against = "_Test Project"
+ budget_against = frappe.db.get_value("Project", {"project_name": "_Test Project"})
else:
budget_against = budget_against_CC or "_Test Cost Center - _TC"
@@ -275,7 +275,7 @@ def set_total_expense_zero(posting_date, budget_against_field=None, budget_again
"_Test Bank - _TC", -existing_expense, "_Test Cost Center - _TC", posting_date=nowdate(), submit=True)
elif budget_against_field == "project":
make_journal_entry("_Test Account Cost for Goods Sold - _TC",
- "_Test Bank - _TC", -existing_expense, "_Test Cost Center - _TC", submit=True, project="_Test Project", posting_date=nowdate())
+ "_Test Bank - _TC", -existing_expense, "_Test Cost Center - _TC", submit=True, project=budget_against, posting_date=nowdate())
def make_budget(**args):
args = frappe._dict(args)
From 2e352834a223a05f31528e57c530a318aa3ff6e6 Mon Sep 17 00:00:00 2001
From: Frappe PR Bot
Date: Fri, 6 Aug 2021 10:59:29 +0530
Subject: [PATCH 236/386] fix: fetching of item tax from hsn code (#26736)
(#26792)
* fix: fetching of item tax from hsn code
(cherry picked from commit 3a50490c04398c30663cab77f722153ec0b220e1)
Co-authored-by: Saqib
---
erpnext/hooks.py | 3 ++-
erpnext/regional/india/utils.py | 13 ++++++++++++-
erpnext/stock/doctype/item/item.js | 14 --------------
erpnext/stock/doctype/item/item.py | 5 +++++
erpnext/stock/doctype/item/regional/india.js | 15 +++++++++++++++
5 files changed, 34 insertions(+), 16 deletions(-)
create mode 100644 erpnext/stock/doctype/item/regional/india.js
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index 1ba752a146..e6b6cc4a8a 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -430,7 +430,8 @@ regional_overrides = {
'erpnext.hr.utils.calculate_annual_eligible_hra_exemption': 'erpnext.regional.india.utils.calculate_annual_eligible_hra_exemption',
'erpnext.hr.utils.calculate_hra_exemption_for_period': 'erpnext.regional.india.utils.calculate_hra_exemption_for_period',
'erpnext.controllers.accounts_controller.validate_einvoice_fields': 'erpnext.regional.india.e_invoice.utils.validate_einvoice_fields',
- 'erpnext.assets.doctype.asset.asset.get_depreciation_amount': 'erpnext.regional.india.utils.get_depreciation_amount'
+ 'erpnext.assets.doctype.asset.asset.get_depreciation_amount': 'erpnext.regional.india.utils.get_depreciation_amount',
+ 'erpnext.stock.doctype.item.item.set_item_tax_from_hsn_code': 'erpnext.regional.india.utils.set_item_tax_from_hsn_code'
},
'United Arab Emirates': {
'erpnext.controllers.taxes_and_totals.update_itemised_tax_data': 'erpnext.regional.united_arab_emirates.utils.update_itemised_tax_data',
diff --git a/erpnext/regional/india/utils.py b/erpnext/regional/india/utils.py
index 04db9b3abe..ac195a6c76 100644
--- a/erpnext/regional/india/utils.py
+++ b/erpnext/regional/india/utils.py
@@ -851,4 +851,15 @@ def get_depreciation_amount(asset, depreciable_value, row):
depreciation_amount = flt(depreciable_value * (flt(rate_of_depreciation) / 100))
- return depreciation_amount
\ No newline at end of file
+ return depreciation_amount
+
+def set_item_tax_from_hsn_code(item):
+ if not item.taxes and item.gst_hsn_code:
+ hsn_doc = frappe.get_doc("GST HSN Code", item.gst_hsn_code)
+
+ for tax in hsn_doc.taxes:
+ item.append('taxes', {
+ 'item_tax_template': tax.item_tax_template,
+ 'tax_category': tax.tax_category,
+ 'valid_from': tax.valid_from
+ })
\ No newline at end of file
diff --git a/erpnext/stock/doctype/item/item.js b/erpnext/stock/doctype/item/item.js
index 264baeaa47..3ca98738cb 100644
--- a/erpnext/stock/doctype/item/item.js
+++ b/erpnext/stock/doctype/item/item.js
@@ -138,20 +138,6 @@ frappe.ui.form.on("Item", {
frm.toggle_reqd('customer', frm.doc.is_customer_provided_item ? 1:0);
},
- gst_hsn_code: function(frm) {
- if((!frm.doc.taxes || !frm.doc.taxes.length) && frm.doc.gst_hsn_code) {
- frappe.db.get_doc("GST HSN Code", frm.doc.gst_hsn_code).then(hsn_doc => {
- $.each(hsn_doc.taxes || [], function(i, tax) {
- let a = frappe.model.add_child(cur_frm.doc, 'Item Tax', 'taxes');
- a.item_tax_template = tax.item_tax_template;
- a.tax_category = tax.tax_category;
- a.valid_from = tax.valid_from;
- frm.refresh_field('taxes');
- });
- });
- }
- },
-
is_fixed_asset: function(frm) {
// set serial no to false & toggles its visibility
frm.set_value('has_serial_no', 0);
diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py
index fbd30cf6c7..9bf4dbf2e8 100644
--- a/erpnext/stock/doctype/item/item.py
+++ b/erpnext/stock/doctype/item/item.py
@@ -123,6 +123,7 @@ class Item(WebsiteGenerator):
self.cant_change()
self.update_show_in_website()
self.validate_item_tax_net_rate_range()
+ set_item_tax_from_hsn_code(self)
if not self.is_new():
self.old_item_group = frappe.db.get_value(self.doctype, self.name, "item_group")
@@ -1305,3 +1306,7 @@ def update_variants(variants, template, publish_progress=True):
def on_doctype_update():
# since route is a Text column, it needs a length for indexing
frappe.db.add_index("Item", ["route(500)"])
+
+@erpnext.allow_regional
+def set_item_tax_from_hsn_code(item):
+ pass
\ No newline at end of file
diff --git a/erpnext/stock/doctype/item/regional/india.js b/erpnext/stock/doctype/item/regional/india.js
new file mode 100644
index 0000000000..77ae51fa34
--- /dev/null
+++ b/erpnext/stock/doctype/item/regional/india.js
@@ -0,0 +1,15 @@
+frappe.ui.form.on('Item', {
+ gst_hsn_code: function(frm) {
+ if ((!frm.doc.taxes || !frm.doc.taxes.length) && frm.doc.gst_hsn_code) {
+ frappe.db.get_doc("GST HSN Code", frm.doc.gst_hsn_code).then(hsn_doc => {
+ $.each(hsn_doc.taxes || [], function(i, tax) {
+ let a = frappe.model.add_child(cur_frm.doc, 'Item Tax', 'taxes');
+ a.item_tax_template = tax.item_tax_template;
+ a.tax_category = tax.tax_category;
+ a.valid_from = tax.valid_from;
+ frm.refresh_field('taxes');
+ });
+ });
+ }
+ },
+});
\ No newline at end of file
From cb44aed78b3e8a427bd8d1387664e9c3037745ce Mon Sep 17 00:00:00 2001
From: Noah Jacob
Date: Thu, 5 Aug 2021 16:11:36 +0530
Subject: [PATCH 237/386] test: get sales order with variant
---
.../production_plan/test_production_plan.py | 55 +++++++++++++++++++
1 file changed, 55 insertions(+)
diff --git a/erpnext/manufacturing/doctype/production_plan/test_production_plan.py b/erpnext/manufacturing/doctype/production_plan/test_production_plan.py
index 93e6d7a97f..af8de8ee0e 100644
--- a/erpnext/manufacturing/doctype/production_plan/test_production_plan.py
+++ b/erpnext/manufacturing/doctype/production_plan/test_production_plan.py
@@ -11,6 +11,7 @@ from erpnext.manufacturing.doctype.production_plan.production_plan import get_sa
from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import create_stock_reconciliation
from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order
from erpnext.manufacturing.doctype.production_plan.production_plan import get_items_for_material_requests, get_warehouse_list
+from erpnext.controllers.item_variant import create_variant
class TestProductionPlan(unittest.TestCase):
def setUp(self):
@@ -271,6 +272,60 @@ class TestProductionPlan(unittest.TestCase):
self.assertEqual(warehouses, expected_warehouses)
+ def test_get_sales_order_with_variant(self):
+ if not frappe.db.exists('Item', {"item_code": 'PIV'}):
+ item = create_item('PIV', valuation_rate = 100)
+ variant_settings = {
+ "attributes": [
+ {
+ "attribute": "Colour"
+ },
+ ],
+ "has_variants": 1
+ }
+ item.update(variant_settings)
+ item.save()
+ parent_bom = make_bom(item = 'PIV', raw_materials = ['PIV'])
+ if not frappe.db.exists('BOM', {"item": 'PIV'}):
+ parent_bom = make_bom(item = 'PIV', raw_materials = ['PIV'])
+ else:
+ parent_bom = frappe.get_doc('BOM', {"item": 'PIV'})
+
+ if not frappe.db.exists('Item', {"item_code": 'PIV-RED'}):
+ variant = create_variant("PIV", {"Colour": "Red"})
+ variant.save()
+ variant_bom = make_bom(item = variant.item_code, raw_materials = [variant.item_code])
+ else:
+ variant = frappe.get_doc('Item', 'PIV-RED')
+ if not frappe.db.exists('BOM', {"item": 'PIV-RED'}):
+ variant_bom = make_bom(item = variant.item_code, raw_materials = [variant.item_code])
+
+ """Testing when item variant has a BOM"""
+ so = make_sales_order(item_code="PIV-RED", qty=5)
+ pln = frappe.new_doc('Production Plan')
+ pln.company = so.company
+ pln.get_items_from = 'Sales Order'
+ pln.item_code = 'PIV-RED'
+ pln.get_open_sales_orders()
+ self.assertEqual(pln.sales_orders[0].sales_order, so.name)
+ pln.get_so_items()
+ self.assertEqual(pln.po_items[0].item_code, 'PIV-RED')
+ self.assertEqual(pln.po_items[0].bom_no, variant_bom.name)
+ so.cancel()
+ frappe.delete_doc('Sales Order', so.name)
+ variant_bom.cancel()
+ frappe.delete_doc('BOM', variant_bom.name)
+
+ """Testing when item variant doesn't have a BOM"""
+ so = make_sales_order(item_code="PIV-RED", qty=5)
+ pln.get_open_sales_orders()
+ self.assertEqual(pln.sales_orders[0].sales_order, so.name)
+ pln.po_items = []
+ pln.get_so_items()
+ self.assertEqual(pln.po_items[0].item_code, 'PIV-RED')
+ self.assertEqual(pln.po_items[0].bom_no, parent_bom.name)
+
+ frappe.db.rollback()
def create_production_plan(**args):
args = frappe._dict(args)
From c8e6c070328d11e2c8db68c366c53f703f53388a Mon Sep 17 00:00:00 2001
From: Frappe PR Bot
Date: Fri, 6 Aug 2021 12:33:18 +0530
Subject: [PATCH 238/386] fix(e-invoicing): cannot generate IRNs for standalone
credit notes (#26824) (#26833)
---
erpnext/regional/india/e_invoice/utils.py | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/erpnext/regional/india/e_invoice/utils.py b/erpnext/regional/india/e_invoice/utils.py
index cd85f6b026..e65442dbff 100644
--- a/erpnext/regional/india/e_invoice/utils.py
+++ b/erpnext/regional/india/e_invoice/utils.py
@@ -316,10 +316,6 @@ def get_payment_details(invoice):
))
def get_return_doc_reference(invoice):
- if not invoice.return_against:
- frappe.throw(_('For generating IRN, reference to the original invoice is mandatory for a credit note. Please set {} field to generate e-invoice.')
- .format(frappe.bold('Return Against')), title=_('Missing Field'))
-
invoice_date = frappe.db.get_value('Sales Invoice', invoice.return_against, 'posting_date')
return frappe._dict(dict(
invoice_name=invoice.return_against, invoice_date=format_date(invoice_date, 'dd/mm/yyyy')
@@ -435,7 +431,7 @@ def make_einvoice(invoice):
if invoice.is_pos and invoice.base_paid_amount:
payment_details = get_payment_details(invoice)
- if invoice.is_return:
+ if invoice.is_return and invoice.return_against:
prev_doc_details = get_return_doc_reference(invoice)
if invoice.transporter and not invoice.is_return:
From 9ea24db20a215e637ef497d1f4594474f8adde6a Mon Sep 17 00:00:00 2001
From: Frappe PR Bot
Date: Fri, 6 Aug 2021 21:14:40 +0530
Subject: [PATCH 239/386] test: use item that allows fractional UOM in test
(#26837) (#26838)
(cherry picked from commit 614336fe1d2f2d136809e29d394800994e7ae4c9)
Co-authored-by: Ankush
---
.../stock/doctype/purchase_receipt/test_purchase_receipt.py | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
index 2eb8bfd5d2..ca6e61fe6b 100644
--- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
@@ -23,9 +23,7 @@ class TestPurchaseReceipt(unittest.TestCase):
def test_reverse_purchase_receipt_sle(self):
- frappe.db.set_value('UOM', '_Test UOM', 'must_be_whole_number', 0)
-
- pr = make_purchase_receipt(qty=0.5)
+ pr = make_purchase_receipt(qty=0.5, item_code="_Test Item Home Desktop 200")
sl_entry = frappe.db.get_all("Stock Ledger Entry", {"voucher_type": "Purchase Receipt",
"voucher_no": pr.name}, ['actual_qty'])
@@ -41,8 +39,6 @@ class TestPurchaseReceipt(unittest.TestCase):
self.assertEqual(len(sl_entry_cancelled), 2)
self.assertEqual(sl_entry_cancelled[1].actual_qty, -0.5)
- frappe.db.set_value('UOM', '_Test UOM', 'must_be_whole_number', 1)
-
def test_make_purchase_invoice(self):
if not frappe.db.exists('Payment Terms Template', '_Test Payment Terms Template For Purchase Invoice'):
frappe.get_doc({
From aec784640796a73261abf6d0511483a1b7031de9 Mon Sep 17 00:00:00 2001
From: Frappe PR Bot
Date: Fri, 6 Aug 2021 21:55:01 +0530
Subject: [PATCH 240/386] test: fix pricelist tests (#26839) (#26840)
problem: exchange rate API is returning exchange rates for "_Test currency".
These tests were relying on failure of that function.
(cherry picked from commit 27a29eb6bc67fc8dce482c0b38239929cf3fc6fb)
Co-authored-by: Ankush
---
erpnext/stock/doctype/batch/test_batch.py | 9 ++++++---
erpnext/stock/doctype/item/test_item.py | 9 ++++++---
2 files changed, 12 insertions(+), 6 deletions(-)
diff --git a/erpnext/stock/doctype/batch/test_batch.py b/erpnext/stock/doctype/batch/test_batch.py
index cbd272df4b..a85a0222b5 100644
--- a/erpnext/stock/doctype/batch/test_batch.py
+++ b/erpnext/stock/doctype/batch/test_batch.py
@@ -269,11 +269,14 @@ class TestBatch(unittest.TestCase):
batch2 = create_batch('_Test Batch Price Item', 300, 1)
batch3 = create_batch('_Test Batch Price Item', 400, 0)
+ company = "_Test Company with perpetual inventory"
+ currency = frappe.get_cached_value("Company", company, "default_currency")
+
args = frappe._dict({
"item_code": "_Test Batch Price Item",
- "company": "_Test Company with perpetual inventory",
+ "company": company,
"price_list": "_Test Price List",
- "currency": "_Test Currency",
+ "currency": currency,
"doctype": "Sales Invoice",
"conversion_rate": 1,
"price_list_currency": "_Test Currency",
@@ -333,4 +336,4 @@ def make_new_batch(**args):
except frappe.DuplicateEntryError:
batch = frappe.get_doc("Batch", args.batch_id)
- return batch
\ No newline at end of file
+ return batch
diff --git a/erpnext/stock/doctype/item/test_item.py b/erpnext/stock/doctype/item/test_item.py
index c7467a5a0f..9ec44d2e2e 100644
--- a/erpnext/stock/doctype/item/test_item.py
+++ b/erpnext/stock/doctype/item/test_item.py
@@ -83,14 +83,17 @@ class TestItem(unittest.TestCase):
make_test_objects("Item Price")
+ company = "_Test Company"
+ currency = frappe.get_cached_value("Company", company, "default_currency")
+
details = get_item_details({
"item_code": "_Test Item",
- "company": "_Test Company",
+ "company": company,
"price_list": "_Test Price List",
- "currency": "_Test Currency",
+ "currency": currency,
"doctype": "Sales Order",
"conversion_rate": 1,
- "price_list_currency": "_Test Currency",
+ "price_list_currency": currency,
"plc_conversion_rate": 1,
"order_type": "Sales",
"customer": "_Test Customer",
From 0bba425fe300305c7d55a543dd42f98549d9b021 Mon Sep 17 00:00:00 2001
From: Deepesh Garg
Date: Fri, 6 Aug 2021 23:53:16 +0530
Subject: [PATCH 241/386] fix: Ignore default payment term templates when
coping payment terms from orders
---
.../purchase_invoice/purchase_invoice.js | 5 +-
.../purchase_invoice/purchase_invoice.json | 635 +++++++++++----
.../doctype/sales_invoice/sales_invoice.json | 731 +++++++++++++-----
erpnext/accounts/party.py | 4 +-
.../doctype/purchase_order/purchase_order.py | 7 +-
erpnext/controllers/accounts_controller.py | 31 +-
erpnext/controllers/buying_controller.py | 3 +-
erpnext/public/js/utils/party.js | 1 +
.../purchase_receipt/purchase_receipt.py | 5 +-
9 files changed, 1060 insertions(+), 362 deletions(-)
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
index dc9094c3e9..299531d9f3 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
@@ -275,7 +275,7 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
// Do not update if inter company reference is there as the details will already be updated
if(this.frm.updating_party_details || this.frm.doc.inter_company_invoice_reference)
return;
-
+
erpnext.utils.get_party_details(this.frm, "erpnext.accounts.party.get_party_details",
{
posting_date: this.frm.doc.posting_date,
@@ -283,7 +283,8 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
party: this.frm.doc.supplier,
party_type: "Supplier",
account: this.frm.doc.credit_to,
- price_list: this.frm.doc.buying_price_list
+ price_list: this.frm.doc.buying_price_list,
+ fetch_payment_terms_template: cint(!this.frm.doc.ignore_default_payment_terms_template)
}, function() {
me.apply_pricing_rule();
me.frm.doc.apply_tds = me.frm.supplier_tds ? 1 : 0;
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
index 00ef7d5c18..f1bf595a39 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
@@ -131,6 +131,7 @@
"advances",
"payment_schedule_section",
"payment_terms_template",
+ "ignore_default_payment_terms_template",
"payment_schedule",
"terms_section_break",
"tc_name",
@@ -175,7 +176,9 @@
"hidden": 1,
"label": "Title",
"no_copy": 1,
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "naming_series",
@@ -187,7 +190,9 @@
"options": "ACC-PINV-.YYYY.-\nACC-PINV-RET-.YYYY.-",
"print_hide": 1,
"reqd": 1,
- "set_only_once": 1
+ "set_only_once": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "supplier",
@@ -199,7 +204,9 @@
"options": "Supplier",
"print_hide": 1,
"reqd": 1,
- "search_index": 1
+ "search_index": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"bold": 1,
@@ -211,7 +218,9 @@
"label": "Supplier Name",
"oldfieldname": "supplier_name",
"oldfieldtype": "Data",
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fetch_from": "supplier.tax_id",
@@ -219,21 +228,27 @@
"fieldtype": "Read Only",
"label": "Tax Id",
"print_hide": 1,
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "due_date",
"fieldtype": "Date",
"label": "Due Date",
"oldfieldname": "due_date",
- "oldfieldtype": "Date"
+ "oldfieldtype": "Date",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"default": "0",
"fieldname": "is_paid",
"fieldtype": "Check",
"label": "Is Paid",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"default": "0",
@@ -241,19 +256,25 @@
"fieldtype": "Check",
"label": "Is Return (Debit Note)",
"no_copy": 1,
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"default": "0",
"fieldname": "apply_tds",
"fieldtype": "Check",
"label": "Apply Tax Withholding Amount",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "column_break1",
"fieldtype": "Column Break",
"oldfieldtype": "Column Break",
+ "show_days": 1,
+ "show_seconds": 1,
"width": "50%"
},
{
@@ -263,13 +284,17 @@
"label": "Company",
"options": "Company",
"print_hide": 1,
- "remember_last_selected_value": 1
+ "remember_last_selected_value": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "cost_center",
"fieldtype": "Link",
"label": "Cost Center",
- "options": "Cost Center"
+ "options": "Cost Center",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"default": "Today",
@@ -281,7 +306,9 @@
"oldfieldtype": "Date",
"print_hide": 1,
"reqd": 1,
- "search_index": 1
+ "search_index": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "posting_time",
@@ -290,6 +317,8 @@
"no_copy": 1,
"print_hide": 1,
"print_width": "100px",
+ "show_days": 1,
+ "show_seconds": 1,
"width": "100px"
},
{
@@ -298,7 +327,9 @@
"fieldname": "set_posting_time",
"fieldtype": "Check",
"label": "Edit Posting Date and Time",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "amended_from",
@@ -310,44 +341,58 @@
"oldfieldtype": "Link",
"options": "Purchase Invoice",
"print_hide": 1,
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"collapsible": 1,
"collapsible_depends_on": "eval:doc.on_hold",
"fieldname": "sb_14",
"fieldtype": "Section Break",
- "label": "Hold Invoice"
+ "label": "Hold Invoice",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"default": "0",
"fieldname": "on_hold",
"fieldtype": "Check",
- "label": "Hold Invoice"
+ "label": "Hold Invoice",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"depends_on": "eval:doc.on_hold",
"description": "Once set, this invoice will be on hold till the set date",
"fieldname": "release_date",
"fieldtype": "Date",
- "label": "Release Date"
+ "label": "Release Date",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "cb_17",
- "fieldtype": "Column Break"
+ "fieldtype": "Column Break",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"depends_on": "eval:doc.on_hold",
"fieldname": "hold_comment",
"fieldtype": "Small Text",
- "label": "Reason For Putting On Hold"
+ "label": "Reason For Putting On Hold",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"collapsible": 1,
"collapsible_depends_on": "bill_no",
"fieldname": "supplier_invoice_details",
"fieldtype": "Section Break",
- "label": "Supplier Invoice Details"
+ "label": "Supplier Invoice Details",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "bill_no",
@@ -355,11 +400,15 @@
"label": "Supplier Invoice No",
"oldfieldname": "bill_no",
"oldfieldtype": "Data",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "column_break_15",
- "fieldtype": "Column Break"
+ "fieldtype": "Column Break",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "bill_date",
@@ -368,13 +417,17 @@
"no_copy": 1,
"oldfieldname": "bill_date",
"oldfieldtype": "Date",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"depends_on": "return_against",
"fieldname": "returns",
"fieldtype": "Section Break",
- "label": "Returns"
+ "label": "Returns",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"depends_on": "return_against",
@@ -384,26 +437,34 @@
"no_copy": 1,
"options": "Purchase Invoice",
"print_hide": 1,
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"collapsible": 1,
"fieldname": "section_addresses",
"fieldtype": "Section Break",
- "label": "Address and Contact"
+ "label": "Address and Contact",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "supplier_address",
"fieldtype": "Link",
"label": "Select Supplier Address",
"options": "Address",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "address_display",
"fieldtype": "Small Text",
"label": "Address",
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "contact_person",
@@ -411,51 +472,67 @@
"in_global_search": 1,
"label": "Contact Person",
"options": "Contact",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "contact_display",
"fieldtype": "Small Text",
"label": "Contact",
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "contact_mobile",
"fieldtype": "Small Text",
"label": "Mobile No",
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "contact_email",
"fieldtype": "Small Text",
"label": "Contact Email",
"print_hide": 1,
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "col_break_address",
- "fieldtype": "Column Break"
+ "fieldtype": "Column Break",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "shipping_address",
"fieldtype": "Link",
"label": "Select Shipping Address",
"options": "Address",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "shipping_address_display",
"fieldtype": "Small Text",
"label": "Shipping Address",
"print_hide": 1,
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"collapsible": 1,
"fieldname": "currency_and_price_list",
"fieldtype": "Section Break",
"label": "Currency and Price List",
- "options": "fa fa-tag"
+ "options": "fa fa-tag",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "currency",
@@ -464,7 +541,9 @@
"oldfieldname": "currency",
"oldfieldtype": "Select",
"options": "Currency",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "conversion_rate",
@@ -473,18 +552,24 @@
"oldfieldname": "conversion_rate",
"oldfieldtype": "Currency",
"precision": "9",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "column_break2",
- "fieldtype": "Column Break"
+ "fieldtype": "Column Break",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "buying_price_list",
"fieldtype": "Link",
"label": "Price List",
"options": "Price List",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "price_list_currency",
@@ -492,14 +577,18 @@
"label": "Price List Currency",
"options": "Currency",
"print_hide": 1,
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "plc_conversion_rate",
"fieldtype": "Float",
"label": "Price List Exchange Rate",
"precision": "9",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"default": "0",
@@ -508,11 +597,15 @@
"label": "Ignore Pricing Rule",
"no_copy": 1,
"permlevel": 1,
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "sec_warehouse",
- "fieldtype": "Section Break"
+ "fieldtype": "Section Break",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"depends_on": "update_stock",
@@ -521,7 +614,9 @@
"fieldtype": "Link",
"label": "Set Accepted Warehouse",
"options": "Warehouse",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"depends_on": "update_stock",
@@ -531,11 +626,15 @@
"label": "Rejected Warehouse",
"no_copy": 1,
"options": "Warehouse",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "col_break_warehouse",
- "fieldtype": "Column Break"
+ "fieldtype": "Column Break",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"default": "No",
@@ -543,25 +642,33 @@
"fieldtype": "Select",
"label": "Raw Materials Supplied",
"options": "No\nYes",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "items_section",
"fieldtype": "Section Break",
"oldfieldtype": "Section Break",
- "options": "fa fa-shopping-cart"
+ "options": "fa fa-shopping-cart",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"default": "0",
"fieldname": "update_stock",
"fieldtype": "Check",
"label": "Update Stock",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "scan_barcode",
"fieldtype": "Data",
- "label": "Scan Barcode"
+ "label": "Scan Barcode",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"allow_bulk_edit": 1,
@@ -571,25 +678,33 @@
"oldfieldname": "entries",
"oldfieldtype": "Table",
"options": "Purchase Invoice Item",
- "reqd": 1
+ "reqd": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "pricing_rule_details",
"fieldtype": "Section Break",
- "label": "Pricing Rules"
+ "label": "Pricing Rules",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "pricing_rules",
"fieldtype": "Table",
"label": "Pricing Rule Detail",
"options": "Pricing Rule Detail",
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"collapsible_depends_on": "supplied_items",
"fieldname": "raw_materials_supplied",
"fieldtype": "Section Break",
- "label": "Raw Materials Supplied"
+ "label": "Raw Materials Supplied",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"depends_on": "update_stock",
@@ -597,17 +712,23 @@
"fieldtype": "Table",
"label": "Supplied Items",
"no_copy": 1,
- "options": "Purchase Receipt Item Supplied"
+ "options": "Purchase Receipt Item Supplied",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "section_break_26",
- "fieldtype": "Section Break"
+ "fieldtype": "Section Break",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "total_qty",
"fieldtype": "Float",
"label": "Total Quantity",
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "base_total",
@@ -615,7 +736,9 @@
"label": "Total (Company Currency)",
"options": "Company:company:default_currency",
"print_hide": 1,
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "base_net_total",
@@ -625,18 +748,24 @@
"oldfieldtype": "Currency",
"options": "Company:company:default_currency",
"print_hide": 1,
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "column_break_28",
- "fieldtype": "Column Break"
+ "fieldtype": "Column Break",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "total",
"fieldtype": "Currency",
"label": "Total",
"options": "currency",
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "net_total",
@@ -646,42 +775,56 @@
"oldfieldtype": "Currency",
"options": "currency",
"print_hide": 1,
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "total_net_weight",
"fieldtype": "Float",
"label": "Total Net Weight",
"print_hide": 1,
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "taxes_section",
"fieldtype": "Section Break",
"oldfieldtype": "Section Break",
- "options": "fa fa-money"
+ "options": "fa fa-money",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "tax_category",
"fieldtype": "Link",
"label": "Tax Category",
"options": "Tax Category",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "column_break_49",
- "fieldtype": "Column Break"
+ "fieldtype": "Column Break",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "shipping_rule",
"fieldtype": "Link",
"label": "Shipping Rule",
"options": "Shipping Rule",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "section_break_51",
- "fieldtype": "Section Break"
+ "fieldtype": "Section Break",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "taxes_and_charges",
@@ -690,7 +833,9 @@
"oldfieldname": "purchase_other_charges",
"oldfieldtype": "Link",
"options": "Purchase Taxes and Charges Template",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "taxes",
@@ -698,13 +843,17 @@
"label": "Purchase Taxes and Charges",
"oldfieldname": "purchase_tax_details",
"oldfieldtype": "Table",
- "options": "Purchase Taxes and Charges"
+ "options": "Purchase Taxes and Charges",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"collapsible": 1,
"fieldname": "sec_tax_breakup",
"fieldtype": "Section Break",
- "label": "Tax Breakup"
+ "label": "Tax Breakup",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "other_charges_calculation",
@@ -713,13 +862,17 @@
"no_copy": 1,
"oldfieldtype": "HTML",
"print_hide": 1,
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "totals",
"fieldtype": "Section Break",
"oldfieldtype": "Section Break",
- "options": "fa fa-money"
+ "options": "fa fa-money",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "base_taxes_and_charges_added",
@@ -729,7 +882,9 @@
"oldfieldtype": "Currency",
"options": "Company:company:default_currency",
"print_hide": 1,
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "base_taxes_and_charges_deducted",
@@ -739,7 +894,9 @@
"oldfieldtype": "Currency",
"options": "Company:company:default_currency",
"print_hide": 1,
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "base_total_taxes_and_charges",
@@ -749,11 +906,15 @@
"oldfieldtype": "Currency",
"options": "Company:company:default_currency",
"print_hide": 1,
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "column_break_40",
- "fieldtype": "Column Break"
+ "fieldtype": "Column Break",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "taxes_and_charges_added",
@@ -763,7 +924,9 @@
"oldfieldtype": "Currency",
"options": "currency",
"print_hide": 1,
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "taxes_and_charges_deducted",
@@ -773,7 +936,9 @@
"oldfieldtype": "Currency",
"options": "currency",
"print_hide": 1,
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "total_taxes_and_charges",
@@ -781,14 +946,18 @@
"label": "Total Taxes and Charges",
"options": "currency",
"print_hide": 1,
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"collapsible": 1,
"collapsible_depends_on": "discount_amount",
"fieldname": "section_break_44",
"fieldtype": "Section Break",
- "label": "Additional Discount"
+ "label": "Additional Discount",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"default": "Grand Total",
@@ -796,7 +965,9 @@
"fieldtype": "Select",
"label": "Apply Additional Discount On",
"options": "\nGrand Total\nNet Total",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "base_discount_amount",
@@ -804,28 +975,38 @@
"label": "Additional Discount Amount (Company Currency)",
"options": "Company:company:default_currency",
"print_hide": 1,
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "column_break_46",
- "fieldtype": "Column Break"
+ "fieldtype": "Column Break",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "additional_discount_percentage",
"fieldtype": "Float",
"label": "Additional Discount Percentage",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "discount_amount",
"fieldtype": "Currency",
"label": "Additional Discount Amount",
"options": "currency",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "section_break_49",
- "fieldtype": "Section Break"
+ "fieldtype": "Section Break",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "base_grand_total",
@@ -835,7 +1016,9 @@
"oldfieldtype": "Currency",
"options": "Company:company:default_currency",
"print_hide": 1,
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"depends_on": "eval:!doc.disable_rounded_total",
@@ -845,7 +1028,9 @@
"no_copy": 1,
"options": "Company:company:default_currency",
"print_hide": 1,
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"depends_on": "eval:!doc.disable_rounded_total",
@@ -855,7 +1040,9 @@
"no_copy": 1,
"options": "Company:company:default_currency",
"print_hide": 1,
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "base_in_words",
@@ -865,13 +1052,17 @@
"oldfieldname": "in_words",
"oldfieldtype": "Data",
"print_hide": 1,
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "column_break8",
"fieldtype": "Column Break",
"oldfieldtype": "Column Break",
"print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1,
"width": "50%"
},
{
@@ -882,7 +1073,9 @@
"oldfieldname": "grand_total_import",
"oldfieldtype": "Currency",
"options": "currency",
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"depends_on": "eval:!doc.disable_rounded_total",
@@ -892,7 +1085,9 @@
"no_copy": 1,
"options": "currency",
"print_hide": 1,
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"depends_on": "eval:!doc.disable_rounded_total",
@@ -902,7 +1097,9 @@
"no_copy": 1,
"options": "currency",
"print_hide": 1,
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "in_words",
@@ -912,7 +1109,9 @@
"oldfieldname": "in_words_import",
"oldfieldtype": "Data",
"print_hide": 1,
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "total_advance",
@@ -923,7 +1122,9 @@
"oldfieldtype": "Currency",
"options": "party_account_currency",
"print_hide": 1,
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "outstanding_amount",
@@ -934,14 +1135,18 @@
"oldfieldtype": "Currency",
"options": "party_account_currency",
"print_hide": 1,
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"default": "0",
"depends_on": "grand_total",
"fieldname": "disable_rounded_total",
"fieldtype": "Check",
- "label": "Disable Rounded Total"
+ "label": "Disable Rounded Total",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"collapsible": 1,
@@ -949,20 +1154,26 @@
"depends_on": "eval:doc.is_paid===1||(doc.advances && doc.advances.length>0)",
"fieldname": "payments_section",
"fieldtype": "Section Break",
- "label": "Payments"
+ "label": "Payments",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "mode_of_payment",
"fieldtype": "Link",
"label": "Mode of Payment",
"options": "Mode of Payment",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "cash_bank_account",
"fieldtype": "Link",
"label": "Cash/Bank Account",
- "options": "Account"
+ "options": "Account",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "clearance_date",
@@ -970,11 +1181,15 @@
"label": "Clearance Date",
"no_copy": 1,
"print_hide": 1,
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "col_br_payments",
- "fieldtype": "Column Break"
+ "fieldtype": "Column Break",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"depends_on": "is_paid",
@@ -983,7 +1198,9 @@
"label": "Paid Amount",
"no_copy": 1,
"options": "currency",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "base_paid_amount",
@@ -992,7 +1209,9 @@
"no_copy": 1,
"options": "Company:company:default_currency",
"print_hide": 1,
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"collapsible": 1,
@@ -1000,7 +1219,9 @@
"depends_on": "grand_total",
"fieldname": "write_off",
"fieldtype": "Section Break",
- "label": "Write Off"
+ "label": "Write Off",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "write_off_amount",
@@ -1008,7 +1229,9 @@
"label": "Write Off Amount",
"no_copy": 1,
"options": "currency",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "base_write_off_amount",
@@ -1017,11 +1240,15 @@
"no_copy": 1,
"options": "Company:company:default_currency",
"print_hide": 1,
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "column_break_61",
- "fieldtype": "Column Break"
+ "fieldtype": "Column Break",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"depends_on": "eval:flt(doc.write_off_amount)!=0",
@@ -1029,7 +1256,9 @@
"fieldtype": "Link",
"label": "Write Off Account",
"options": "Account",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"depends_on": "eval:flt(doc.write_off_amount)!=0",
@@ -1037,7 +1266,9 @@
"fieldtype": "Link",
"label": "Write Off Cost Center",
"options": "Cost Center",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"collapsible": 1,
@@ -1047,13 +1278,17 @@
"label": "Advance Payments",
"oldfieldtype": "Section Break",
"options": "fa fa-money",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"default": "0",
"fieldname": "allocate_advances_automatically",
"fieldtype": "Check",
- "label": "Set Advances and Allocate (FIFO)"
+ "label": "Set Advances and Allocate (FIFO)",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"depends_on": "eval:!doc.allocate_advances_automatically",
@@ -1061,7 +1296,9 @@
"fieldtype": "Button",
"label": "Get Advances Paid",
"oldfieldtype": "Button",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "advances",
@@ -1071,20 +1308,26 @@
"oldfieldname": "advance_allocation_details",
"oldfieldtype": "Table",
"options": "Purchase Invoice Advance",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"collapsible": 1,
"collapsible_depends_on": "eval:(!doc.is_return)",
"fieldname": "payment_schedule_section",
"fieldtype": "Section Break",
- "label": "Payment Terms"
+ "label": "Payment Terms",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "payment_terms_template",
"fieldtype": "Link",
"label": "Payment Terms Template",
- "options": "Payment Terms Template"
+ "options": "Payment Terms Template",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "payment_schedule",
@@ -1092,7 +1335,9 @@
"label": "Payment Schedule",
"no_copy": 1,
"options": "Payment Schedule",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"collapsible": 1,
@@ -1100,25 +1345,33 @@
"fieldname": "terms_section_break",
"fieldtype": "Section Break",
"label": "Terms and Conditions",
- "options": "fa fa-legal"
+ "options": "fa fa-legal",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "tc_name",
"fieldtype": "Link",
"label": "Terms",
"options": "Terms and Conditions",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "terms",
"fieldtype": "Text Editor",
- "label": "Terms and Conditions1"
+ "label": "Terms and Conditions1",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"collapsible": 1,
"fieldname": "printing_settings",
"fieldtype": "Section Break",
- "label": "Printing Settings"
+ "label": "Printing Settings",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"allow_on_submit": 1,
@@ -1126,7 +1379,9 @@
"fieldtype": "Link",
"label": "Letter Head",
"options": "Letter Head",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"allow_on_submit": 1,
@@ -1134,11 +1389,15 @@
"fieldname": "group_same_items",
"fieldtype": "Check",
"label": "Group same items",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "column_break_112",
- "fieldtype": "Column Break"
+ "fieldtype": "Column Break",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"allow_on_submit": 1,
@@ -1150,14 +1409,18 @@
"oldfieldtype": "Link",
"options": "Print Heading",
"print_hide": 1,
- "report_hide": 1
+ "report_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "language",
"fieldtype": "Data",
"label": "Print Language",
"print_hide": 1,
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"collapsible": 1,
@@ -1166,7 +1429,9 @@
"label": "More Information",
"oldfieldtype": "Section Break",
"options": "fa fa-file-text",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "credit_to",
@@ -1177,7 +1442,9 @@
"options": "Account",
"print_hide": 1,
"reqd": 1,
- "search_index": 1
+ "search_index": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "party_account_currency",
@@ -1187,7 +1454,9 @@
"no_copy": 1,
"options": "Currency",
"print_hide": 1,
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"default": "No",
@@ -1197,7 +1466,9 @@
"oldfieldname": "is_opening",
"oldfieldtype": "Select",
"options": "No\nYes",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "against_expense_account",
@@ -1207,11 +1478,15 @@
"no_copy": 1,
"oldfieldname": "against_expense_account",
"oldfieldtype": "Small Text",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "column_break_63",
- "fieldtype": "Column Break"
+ "fieldtype": "Column Break",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"default": "Draft",
@@ -1220,7 +1495,9 @@
"in_standard_filter": 1,
"label": "Status",
"options": "\nDraft\nReturn\nDebit Note Issued\nSubmitted\nPaid\nUnpaid\nOverdue\nCancelled\nInternal Transfer",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "inter_company_invoice_reference",
@@ -1229,7 +1506,9 @@
"no_copy": 1,
"options": "Sales Invoice",
"print_hide": 1,
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "remarks",
@@ -1238,14 +1517,18 @@
"no_copy": 1,
"oldfieldname": "remarks",
"oldfieldtype": "Text",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"collapsible": 1,
"fieldname": "subscription_section",
"fieldtype": "Section Break",
"label": "Subscription Section",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"allow_on_submit": 1,
@@ -1254,7 +1537,9 @@
"fieldtype": "Date",
"label": "From Date",
"no_copy": 1,
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"allow_on_submit": 1,
@@ -1263,11 +1548,15 @@
"fieldtype": "Date",
"label": "To Date",
"no_copy": 1,
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "column_break_114",
- "fieldtype": "Column Break"
+ "fieldtype": "Column Break",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "auto_repeat",
@@ -1276,24 +1565,32 @@
"no_copy": 1,
"options": "Auto Repeat",
"print_hide": 1,
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"allow_on_submit": 1,
"depends_on": "eval: doc.auto_repeat",
"fieldname": "update_auto_repeat_reference",
"fieldtype": "Button",
- "label": "Update Auto Repeat Reference"
+ "label": "Update Auto Repeat Reference",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"collapsible": 1,
"fieldname": "accounting_dimensions_section",
"fieldtype": "Section Break",
- "label": "Accounting Dimensions "
+ "label": "Accounting Dimensions ",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "dimension_col_break",
- "fieldtype": "Column Break"
+ "fieldtype": "Column Break",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"default": "0",
@@ -1301,7 +1598,9 @@
"fieldname": "is_internal_supplier",
"fieldtype": "Check",
"label": "Is Internal Supplier",
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "tax_withholding_category",
@@ -1309,25 +1608,33 @@
"hidden": 1,
"label": "Tax Withholding Category",
"options": "Tax Withholding Category",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "billing_address",
"fieldtype": "Link",
"label": "Select Billing Address",
- "options": "Address"
+ "options": "Address",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "billing_address_display",
"fieldtype": "Small Text",
"label": "Billing Address",
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "project",
"fieldtype": "Link",
"label": "Project",
- "options": "Project"
+ "options": "Project",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"depends_on": "eval:doc.is_internal_supplier",
@@ -1335,7 +1642,9 @@
"fieldname": "unrealized_profit_loss_account",
"fieldtype": "Link",
"label": "Unrealized Profit / Loss Account",
- "options": "Account"
+ "options": "Account",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"depends_on": "eval:doc.is_internal_supplier",
@@ -1344,7 +1653,9 @@
"fieldname": "represents_company",
"fieldtype": "Link",
"label": "Represents Company",
- "options": "Company"
+ "options": "Company",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"depends_on": "eval:doc.update_stock && doc.is_internal_supplier",
@@ -1356,6 +1667,8 @@
"options": "Warehouse",
"print_hide": 1,
"print_width": "50px",
+ "show_days": 1,
+ "show_seconds": 1,
"width": "50px"
},
{
@@ -1367,6 +1680,8 @@
"options": "Warehouse",
"print_hide": 1,
"print_width": "50px",
+ "show_days": 1,
+ "show_seconds": 1,
"width": "50px"
},
{
@@ -1376,14 +1691,26 @@
"label": "Per Received",
"no_copy": 1,
"print_hide": 1,
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
+ },
+ {
+ "default": "0",
+ "fieldname": "ignore_default_payment_terms_template",
+ "fieldtype": "Check",
+ "hidden": 1,
+ "label": "Ignore Default Payment Terms Template",
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
}
],
"icon": "fa fa-file-text",
"idx": 204,
"is_submittable": 1,
"links": [],
- "modified": "2021-06-15 18:20:56.806195",
+ "modified": "2021-08-07 17:53:14.351439",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Invoice",
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
index e7dd6b8a60..23e8091761 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
@@ -125,6 +125,7 @@
"get_advances",
"advances",
"payment_schedule_section",
+ "ignore_default_payment_terms_template",
"payment_terms_template",
"payment_schedule",
"payments_section",
@@ -195,7 +196,9 @@
"fieldtype": "Section Break",
"hide_days": 1,
"hide_seconds": 1,
- "options": "fa fa-user"
+ "options": "fa fa-user",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"allow_on_submit": 1,
@@ -207,7 +210,9 @@
"hide_seconds": 1,
"label": "Title",
"no_copy": 1,
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"bold": 1,
@@ -222,7 +227,9 @@
"options": "ACC-SINV-.YYYY.-\nACC-SINV-RET-.YYYY.-",
"print_hide": 1,
"reqd": 1,
- "set_only_once": 1
+ "set_only_once": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"bold": 1,
@@ -236,7 +243,9 @@
"oldfieldtype": "Link",
"options": "Customer",
"print_hide": 1,
- "search_index": 1
+ "search_index": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"bold": 1,
@@ -250,7 +259,9 @@
"label": "Customer Name",
"oldfieldname": "customer_name",
"oldfieldtype": "Data",
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "tax_id",
@@ -259,7 +270,9 @@
"hide_seconds": 1,
"label": "Tax Id",
"print_hide": 1,
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "project",
@@ -271,7 +284,9 @@
"oldfieldname": "project_name",
"oldfieldtype": "Link",
"options": "Project",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"default": "0",
@@ -282,7 +297,9 @@
"label": "Include Payment (POS)",
"oldfieldname": "is_pos",
"oldfieldtype": "Check",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"depends_on": "is_pos",
@@ -292,7 +309,9 @@
"hide_seconds": 1,
"label": "POS Profile",
"options": "POS Profile",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"default": "0",
@@ -302,14 +321,18 @@
"hide_seconds": 1,
"label": "Is Return (Credit Note)",
"no_copy": 1,
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "column_break1",
"fieldtype": "Column Break",
"hide_days": 1,
"hide_seconds": 1,
- "oldfieldtype": "Column Break"
+ "oldfieldtype": "Column Break",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "company",
@@ -323,7 +346,9 @@
"options": "Company",
"print_hide": 1,
"remember_last_selected_value": 1,
- "reqd": 1
+ "reqd": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "cost_center",
@@ -331,7 +356,9 @@
"hide_days": 1,
"hide_seconds": 1,
"label": "Cost Center",
- "options": "Cost Center"
+ "options": "Cost Center",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"bold": 1,
@@ -345,7 +372,9 @@
"oldfieldname": "posting_date",
"oldfieldtype": "Date",
"reqd": 1,
- "search_index": 1
+ "search_index": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "posting_time",
@@ -356,7 +385,9 @@
"no_copy": 1,
"oldfieldname": "posting_time",
"oldfieldtype": "Time",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"default": "0",
@@ -366,7 +397,9 @@
"hide_days": 1,
"hide_seconds": 1,
"label": "Edit Posting Date and Time",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "due_date",
@@ -376,7 +409,9 @@
"label": "Payment Due Date",
"no_copy": 1,
"oldfieldname": "due_date",
- "oldfieldtype": "Date"
+ "oldfieldtype": "Date",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "amended_from",
@@ -390,7 +425,9 @@
"oldfieldtype": "Link",
"options": "Sales Invoice",
"print_hide": 1,
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"depends_on": "eval:doc.return_against || doc.is_debit_note",
@@ -403,7 +440,9 @@
"options": "Sales Invoice",
"print_hide": 1,
"read_only_depends_on": "eval:doc.is_return",
- "search_index": 1
+ "search_index": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"default": "0",
@@ -412,7 +451,9 @@
"fieldtype": "Check",
"hide_days": 1,
"hide_seconds": 1,
- "label": "Update Billed Amount in Sales Order"
+ "label": "Update Billed Amount in Sales Order",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"collapsible": 1,
@@ -421,7 +462,9 @@
"fieldtype": "Section Break",
"hide_days": 1,
"hide_seconds": 1,
- "label": "Customer PO Details"
+ "label": "Customer PO Details",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"allow_on_submit": 1,
@@ -431,13 +474,17 @@
"hide_seconds": 1,
"label": "Customer's Purchase Order",
"no_copy": 1,
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "column_break_23",
"fieldtype": "Column Break",
"hide_days": 1,
- "hide_seconds": 1
+ "hide_seconds": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"allow_on_submit": 1,
@@ -445,7 +492,9 @@
"fieldtype": "Date",
"hide_days": 1,
"hide_seconds": 1,
- "label": "Customer's Purchase Order Date"
+ "label": "Customer's Purchase Order Date",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"collapsible": 1,
@@ -453,7 +502,9 @@
"fieldtype": "Section Break",
"hide_days": 1,
"hide_seconds": 1,
- "label": "Address and Contact"
+ "label": "Address and Contact",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "customer_address",
@@ -462,7 +513,9 @@
"hide_seconds": 1,
"label": "Customer Address",
"options": "Address",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "address_display",
@@ -470,7 +523,9 @@
"hide_days": 1,
"hide_seconds": 1,
"label": "Address",
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "contact_person",
@@ -480,7 +535,9 @@
"in_global_search": 1,
"label": "Contact Person",
"options": "Contact",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "contact_display",
@@ -488,7 +545,9 @@
"hide_days": 1,
"hide_seconds": 1,
"label": "Contact",
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "contact_mobile",
@@ -497,7 +556,9 @@
"hide_days": 1,
"hide_seconds": 1,
"label": "Mobile No",
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "contact_email",
@@ -508,7 +569,9 @@
"label": "Contact Email",
"options": "Email",
"print_hide": 1,
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "territory",
@@ -517,13 +580,17 @@
"hide_seconds": 1,
"label": "Territory",
"options": "Territory",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "col_break4",
"fieldtype": "Column Break",
"hide_days": 1,
- "hide_seconds": 1
+ "hide_seconds": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "shipping_address_name",
@@ -532,7 +599,9 @@
"hide_seconds": 1,
"label": "Shipping Address Name",
"options": "Address",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "shipping_address",
@@ -541,7 +610,9 @@
"hide_seconds": 1,
"label": "Shipping Address",
"print_hide": 1,
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "company_address",
@@ -550,7 +621,9 @@
"hide_seconds": 1,
"label": "Company Address Name",
"options": "Address",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "company_address_display",
@@ -560,7 +633,9 @@
"hide_seconds": 1,
"label": "Company Address",
"print_hide": 1,
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"collapsible": 1,
@@ -569,7 +644,9 @@
"fieldtype": "Section Break",
"hide_days": 1,
"hide_seconds": 1,
- "label": "Currency and Price List"
+ "label": "Currency and Price List",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "currency",
@@ -581,7 +658,9 @@
"oldfieldtype": "Select",
"options": "Currency",
"print_hide": 1,
- "reqd": 1
+ "reqd": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"description": "Rate at which Customer Currency is converted to customer's base currency",
@@ -594,13 +673,17 @@
"oldfieldtype": "Currency",
"precision": "9",
"print_hide": 1,
- "reqd": 1
+ "reqd": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "column_break2",
"fieldtype": "Column Break",
"hide_days": 1,
"hide_seconds": 1,
+ "show_days": 1,
+ "show_seconds": 1,
"width": "50%"
},
{
@@ -613,7 +696,9 @@
"oldfieldtype": "Select",
"options": "Price List",
"print_hide": 1,
- "reqd": 1
+ "reqd": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "price_list_currency",
@@ -624,7 +709,9 @@
"options": "Currency",
"print_hide": 1,
"read_only": 1,
- "reqd": 1
+ "reqd": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"description": "Rate at which Price list currency is converted to customer's base currency",
@@ -635,7 +722,9 @@
"label": "Price List Exchange Rate",
"precision": "9",
"print_hide": 1,
- "reqd": 1
+ "reqd": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"default": "0",
@@ -646,14 +735,18 @@
"label": "Ignore Pricing Rule",
"no_copy": 1,
"permlevel": 1,
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "sec_warehouse",
"fieldtype": "Section Break",
"hide_days": 1,
"hide_seconds": 1,
- "label": "Warehouse"
+ "label": "Warehouse",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"depends_on": "update_stock",
@@ -663,7 +756,9 @@
"hide_seconds": 1,
"label": "Source Warehouse",
"options": "Warehouse",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "items_section",
@@ -672,7 +767,9 @@
"hide_seconds": 1,
"label": "Items",
"oldfieldtype": "Section Break",
- "options": "fa fa-shopping-cart"
+ "options": "fa fa-shopping-cart",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"default": "0",
@@ -683,14 +780,18 @@
"label": "Update Stock",
"oldfieldname": "update_stock",
"oldfieldtype": "Check",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "scan_barcode",
"fieldtype": "Data",
"hide_days": 1,
"hide_seconds": 1,
- "label": "Scan Barcode"
+ "label": "Scan Barcode",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"allow_bulk_edit": 1,
@@ -702,14 +803,18 @@
"oldfieldname": "entries",
"oldfieldtype": "Table",
"options": "Sales Invoice Item",
- "reqd": 1
+ "reqd": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "pricing_rule_details",
"fieldtype": "Section Break",
"hide_days": 1,
"hide_seconds": 1,
- "label": "Pricing Rules"
+ "label": "Pricing Rules",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "pricing_rules",
@@ -718,7 +823,9 @@
"hide_seconds": 1,
"label": "Pricing Rule Detail",
"options": "Pricing Rule Detail",
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "packing_list",
@@ -727,7 +834,9 @@
"hide_seconds": 1,
"label": "Packing List",
"options": "fa fa-suitcase",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "packed_items",
@@ -736,7 +845,9 @@
"hide_seconds": 1,
"label": "Packed Items",
"options": "Packed Item",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "product_bundle_help",
@@ -744,7 +855,9 @@
"hide_days": 1,
"hide_seconds": 1,
"label": "Product Bundle Help",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"collapsible": 1,
@@ -754,7 +867,9 @@
"fieldtype": "Section Break",
"hide_days": 1,
"hide_seconds": 1,
- "label": "Time Sheet List"
+ "label": "Time Sheet List",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "timesheets",
@@ -763,7 +878,9 @@
"hide_seconds": 1,
"label": "Time Sheets",
"options": "Sales Invoice Timesheet",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"default": "0",
@@ -774,13 +891,17 @@
"label": "Total Billing Amount",
"options": "currency",
"print_hide": 1,
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "section_break_30",
"fieldtype": "Section Break",
"hide_days": 1,
- "hide_seconds": 1
+ "hide_seconds": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "total_qty",
@@ -788,7 +909,9 @@
"hide_days": 1,
"hide_seconds": 1,
"label": "Total Quantity",
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "base_total",
@@ -798,7 +921,9 @@
"label": "Total (Company Currency)",
"options": "Company:company:default_currency",
"print_hide": 1,
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "base_net_total",
@@ -811,13 +936,17 @@
"options": "Company:company:default_currency",
"print_hide": 1,
"read_only": 1,
- "reqd": 1
+ "reqd": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "column_break_32",
"fieldtype": "Column Break",
"hide_days": 1,
- "hide_seconds": 1
+ "hide_seconds": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "total",
@@ -826,7 +955,9 @@
"hide_seconds": 1,
"label": "Total",
"options": "currency",
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "net_total",
@@ -836,7 +967,9 @@
"label": "Net Total",
"options": "currency",
"print_hide": 1,
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "total_net_weight",
@@ -845,7 +978,9 @@
"hide_seconds": 1,
"label": "Total Net Weight",
"print_hide": 1,
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "taxes_section",
@@ -853,7 +988,9 @@
"hide_days": 1,
"hide_seconds": 1,
"oldfieldtype": "Section Break",
- "options": "fa fa-money"
+ "options": "fa fa-money",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "taxes_and_charges",
@@ -864,13 +1001,17 @@
"oldfieldname": "charge",
"oldfieldtype": "Link",
"options": "Sales Taxes and Charges Template",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "column_break_38",
"fieldtype": "Column Break",
"hide_days": 1,
- "hide_seconds": 1
+ "hide_seconds": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "shipping_rule",
@@ -880,7 +1021,9 @@
"label": "Shipping Rule",
"oldfieldtype": "Button",
"options": "Shipping Rule",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "tax_category",
@@ -889,13 +1032,17 @@
"hide_seconds": 1,
"label": "Tax Category",
"options": "Tax Category",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "section_break_40",
"fieldtype": "Section Break",
"hide_days": 1,
- "hide_seconds": 1
+ "hide_seconds": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "taxes",
@@ -905,7 +1052,9 @@
"label": "Sales Taxes and Charges",
"oldfieldname": "other_charges",
"oldfieldtype": "Table",
- "options": "Sales Taxes and Charges"
+ "options": "Sales Taxes and Charges",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"collapsible": 1,
@@ -913,7 +1062,9 @@
"fieldtype": "Section Break",
"hide_days": 1,
"hide_seconds": 1,
- "label": "Tax Breakup"
+ "label": "Tax Breakup",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "other_charges_calculation",
@@ -924,13 +1075,17 @@
"no_copy": 1,
"oldfieldtype": "HTML",
"print_hide": 1,
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "section_break_43",
"fieldtype": "Section Break",
"hide_days": 1,
- "hide_seconds": 1
+ "hide_seconds": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "base_total_taxes_and_charges",
@@ -942,13 +1097,17 @@
"oldfieldtype": "Currency",
"options": "Company:company:default_currency",
"print_hide": 1,
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "column_break_47",
"fieldtype": "Column Break",
"hide_days": 1,
- "hide_seconds": 1
+ "hide_seconds": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "total_taxes_and_charges",
@@ -958,7 +1117,9 @@
"label": "Total Taxes and Charges",
"options": "currency",
"print_hide": 1,
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"collapsible": 1,
@@ -966,7 +1127,9 @@
"fieldtype": "Section Break",
"hide_days": 1,
"hide_seconds": 1,
- "label": "Loyalty Points Redemption"
+ "label": "Loyalty Points Redemption",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"depends_on": "redeem_loyalty_points",
@@ -976,7 +1139,9 @@
"hide_seconds": 1,
"label": "Loyalty Points",
"no_copy": 1,
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"depends_on": "redeem_loyalty_points",
@@ -988,7 +1153,9 @@
"no_copy": 1,
"options": "Company:company:default_currency",
"print_hide": 1,
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"default": "0",
@@ -998,13 +1165,17 @@
"hide_seconds": 1,
"label": "Redeem Loyalty Points",
"no_copy": 1,
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "column_break_77",
"fieldtype": "Column Break",
"hide_days": 1,
- "hide_seconds": 1
+ "hide_seconds": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fetch_from": "customer.loyalty_program",
@@ -1016,7 +1187,9 @@
"no_copy": 1,
"options": "Loyalty Program",
"print_hide": 1,
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"depends_on": "redeem_loyalty_points",
@@ -1026,7 +1199,9 @@
"hide_seconds": 1,
"label": "Redemption Account",
"no_copy": 1,
- "options": "Account"
+ "options": "Account",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"depends_on": "redeem_loyalty_points",
@@ -1036,7 +1211,9 @@
"hide_seconds": 1,
"label": "Redemption Cost Center",
"no_copy": 1,
- "options": "Cost Center"
+ "options": "Cost Center",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"collapsible": 1,
@@ -1045,7 +1222,9 @@
"fieldtype": "Section Break",
"hide_days": 1,
"hide_seconds": 1,
- "label": "Additional Discount"
+ "label": "Additional Discount",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"default": "Grand Total",
@@ -1055,7 +1234,9 @@
"hide_seconds": 1,
"label": "Apply Additional Discount On",
"options": "\nGrand Total\nNet Total",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "base_discount_amount",
@@ -1065,13 +1246,17 @@
"label": "Additional Discount Amount (Company Currency)",
"options": "Company:company:default_currency",
"print_hide": 1,
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "column_break_51",
"fieldtype": "Column Break",
"hide_days": 1,
- "hide_seconds": 1
+ "hide_seconds": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "additional_discount_percentage",
@@ -1079,7 +1264,9 @@
"hide_days": 1,
"hide_seconds": 1,
"label": "Additional Discount Percentage",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "discount_amount",
@@ -1088,7 +1275,9 @@
"hide_seconds": 1,
"label": "Additional Discount Amount",
"options": "currency",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "totals",
@@ -1097,7 +1286,9 @@
"hide_seconds": 1,
"oldfieldtype": "Section Break",
"options": "fa fa-money",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "base_grand_total",
@@ -1110,7 +1301,9 @@
"options": "Company:company:default_currency",
"print_hide": 1,
"read_only": 1,
- "reqd": 1
+ "reqd": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"depends_on": "eval:!doc.disable_rounded_total",
@@ -1122,7 +1315,9 @@
"no_copy": 1,
"options": "Company:company:default_currency",
"print_hide": 1,
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"depends_on": "eval:!doc.disable_rounded_total",
@@ -1135,7 +1330,9 @@
"oldfieldtype": "Currency",
"options": "Company:company:default_currency",
"print_hide": 1,
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"description": "In Words will be visible once you save the Sales Invoice.",
@@ -1148,7 +1345,9 @@
"oldfieldname": "in_words",
"oldfieldtype": "Data",
"print_hide": 1,
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "column_break5",
@@ -1157,6 +1356,8 @@
"hide_seconds": 1,
"oldfieldtype": "Column Break",
"print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1,
"width": "50%"
},
{
@@ -1171,7 +1372,9 @@
"oldfieldtype": "Currency",
"options": "currency",
"read_only": 1,
- "reqd": 1
+ "reqd": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"depends_on": "eval:!doc.disable_rounded_total",
@@ -1183,7 +1386,9 @@
"no_copy": 1,
"options": "currency",
"print_hide": 1,
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"bold": 1,
@@ -1196,7 +1401,9 @@
"oldfieldname": "rounded_total_export",
"oldfieldtype": "Currency",
"options": "currency",
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "in_words",
@@ -1208,7 +1415,9 @@
"oldfieldname": "in_words_export",
"oldfieldtype": "Data",
"print_hide": 1,
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "total_advance",
@@ -1220,7 +1429,9 @@
"oldfieldtype": "Currency",
"options": "party_account_currency",
"print_hide": 1,
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "outstanding_amount",
@@ -1233,7 +1444,9 @@
"oldfieldtype": "Currency",
"options": "party_account_currency",
"print_hide": 1,
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"collapsible": 1,
@@ -1245,7 +1458,9 @@
"label": "Advance Payments",
"oldfieldtype": "Section Break",
"options": "fa fa-money",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"default": "0",
@@ -1253,7 +1468,9 @@
"fieldtype": "Check",
"hide_days": 1,
"hide_seconds": 1,
- "label": "Allocate Advances Automatically (FIFO)"
+ "label": "Allocate Advances Automatically (FIFO)",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"depends_on": "eval:!doc.allocate_advances_automatically",
@@ -1262,7 +1479,9 @@
"hide_days": 1,
"hide_seconds": 1,
"label": "Get Advances Received",
- "options": "set_advances"
+ "options": "set_advances",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "advances",
@@ -1273,7 +1492,9 @@
"oldfieldname": "advance_adjustment_details",
"oldfieldtype": "Table",
"options": "Sales Invoice Advance",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"collapsible": 1,
@@ -1282,7 +1503,9 @@
"fieldtype": "Section Break",
"hide_days": 1,
"hide_seconds": 1,
- "label": "Payment Terms"
+ "label": "Payment Terms",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"depends_on": "eval:(!doc.is_pos && !doc.is_return)",
@@ -1293,7 +1516,9 @@
"label": "Payment Terms Template",
"no_copy": 1,
"options": "Payment Terms Template",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"depends_on": "eval:(!doc.is_pos && !doc.is_return)",
@@ -1304,7 +1529,9 @@
"label": "Payment Schedule",
"no_copy": 1,
"options": "Payment Schedule",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"depends_on": "eval:doc.is_pos===1||(doc.advances && doc.advances.length>0)",
@@ -1313,7 +1540,9 @@
"hide_days": 1,
"hide_seconds": 1,
"label": "Payments",
- "options": "fa fa-money"
+ "options": "fa fa-money",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"depends_on": "is_pos",
@@ -1326,7 +1555,9 @@
"oldfieldname": "cash_bank_account",
"oldfieldtype": "Link",
"options": "Account",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"depends_on": "eval:doc.is_pos===1",
@@ -1336,13 +1567,17 @@
"hide_seconds": 1,
"label": "Sales Invoice Payment",
"options": "Sales Invoice Payment",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "section_break_84",
"fieldtype": "Section Break",
"hide_days": 1,
- "hide_seconds": 1
+ "hide_seconds": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "base_paid_amount",
@@ -1353,13 +1588,17 @@
"no_copy": 1,
"options": "Company:company:default_currency",
"print_hide": 1,
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "column_break_86",
"fieldtype": "Column Break",
"hide_days": 1,
- "hide_seconds": 1
+ "hide_seconds": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"depends_on": "eval: doc.is_pos || doc.redeem_loyalty_points",
@@ -1373,13 +1612,17 @@
"oldfieldtype": "Currency",
"options": "currency",
"print_hide": 1,
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "section_break_88",
"fieldtype": "Section Break",
"hide_days": 1,
- "hide_seconds": 1
+ "hide_seconds": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"depends_on": "is_pos",
@@ -1391,13 +1634,17 @@
"no_copy": 1,
"options": "Company:company:default_currency",
"print_hide": 1,
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "column_break_90",
"fieldtype": "Column Break",
"hide_days": 1,
- "hide_seconds": 1
+ "hide_seconds": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"depends_on": "is_pos",
@@ -1408,7 +1655,9 @@
"label": "Change Amount",
"no_copy": 1,
"options": "currency",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"depends_on": "is_pos",
@@ -1418,7 +1667,9 @@
"hide_seconds": 1,
"label": "Account for Change Amount",
"options": "Account",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"collapsible": 1,
@@ -1429,6 +1680,8 @@
"hide_days": 1,
"hide_seconds": 1,
"label": "Write Off",
+ "show_days": 1,
+ "show_seconds": 1,
"width": "50%"
},
{
@@ -1439,7 +1692,9 @@
"label": "Write Off Amount",
"no_copy": 1,
"options": "currency",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "base_write_off_amount",
@@ -1450,7 +1705,9 @@
"no_copy": 1,
"options": "Company:company:default_currency",
"print_hide": 1,
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"default": "0",
@@ -1460,13 +1717,17 @@
"hide_days": 1,
"hide_seconds": 1,
"label": "Write Off Outstanding Amount",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "column_break_74",
"fieldtype": "Column Break",
"hide_days": 1,
- "hide_seconds": 1
+ "hide_seconds": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "write_off_account",
@@ -1475,7 +1736,9 @@
"hide_seconds": 1,
"label": "Write Off Account",
"options": "Account",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "write_off_cost_center",
@@ -1484,7 +1747,9 @@
"hide_seconds": 1,
"label": "Write Off Cost Center",
"options": "Cost Center",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"collapsible": 1,
@@ -1494,7 +1759,9 @@
"hide_days": 1,
"hide_seconds": 1,
"label": "Terms and Conditions",
- "oldfieldtype": "Section Break"
+ "oldfieldtype": "Section Break",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "tc_name",
@@ -1505,7 +1772,9 @@
"oldfieldname": "tc_name",
"oldfieldtype": "Link",
"options": "Terms and Conditions",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "terms",
@@ -1514,7 +1783,9 @@
"hide_seconds": 1,
"label": "Terms and Conditions Details",
"oldfieldname": "terms",
- "oldfieldtype": "Text Editor"
+ "oldfieldtype": "Text Editor",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"collapsible": 1,
@@ -1522,7 +1793,9 @@
"fieldtype": "Section Break",
"hide_days": 1,
"hide_seconds": 1,
- "label": "Printing Settings"
+ "label": "Printing Settings",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"allow_on_submit": 1,
@@ -1534,7 +1807,9 @@
"oldfieldname": "letter_head",
"oldfieldtype": "Select",
"options": "Letter Head",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"allow_on_submit": 1,
@@ -1544,7 +1819,9 @@
"hide_days": 1,
"hide_seconds": 1,
"label": "Group same items",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "language",
@@ -1553,13 +1830,17 @@
"hide_seconds": 1,
"label": "Print Language",
"print_hide": 1,
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "column_break_84",
"fieldtype": "Column Break",
"hide_days": 1,
- "hide_seconds": 1
+ "hide_seconds": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"allow_on_submit": 1,
@@ -1573,7 +1854,9 @@
"oldfieldtype": "Link",
"options": "Print Heading",
"print_hide": 1,
- "report_hide": 1
+ "report_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"collapsible": 1,
@@ -1582,7 +1865,9 @@
"fieldtype": "Section Break",
"hide_days": 1,
"hide_seconds": 1,
- "label": "More Information"
+ "label": "More Information",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "inter_company_invoice_reference",
@@ -1591,7 +1876,9 @@
"hide_seconds": 1,
"label": "Inter Company Invoice Reference",
"options": "Purchase Invoice",
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "customer_group",
@@ -1601,7 +1888,9 @@
"hide_seconds": 1,
"label": "Customer Group",
"options": "Customer Group",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "campaign",
@@ -1612,7 +1901,9 @@
"oldfieldname": "campaign",
"oldfieldtype": "Link",
"options": "Campaign",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"default": "0",
@@ -1622,13 +1913,17 @@
"hide_seconds": 1,
"label": "Is Discounted",
"no_copy": 1,
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "col_break23",
"fieldtype": "Column Break",
"hide_days": 1,
"hide_seconds": 1,
+ "show_days": 1,
+ "show_seconds": 1,
"width": "50%"
},
{
@@ -1642,7 +1937,9 @@
"no_copy": 1,
"options": "\nDraft\nReturn\nCredit Note Issued\nSubmitted\nPaid\nUnpaid\nUnpaid and Discounted\nOverdue and Discounted\nOverdue\nCancelled\nInternal Transfer",
"print_hide": 1,
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "source",
@@ -1653,7 +1950,9 @@
"oldfieldname": "source",
"oldfieldtype": "Select",
"options": "Lead Source",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"collapsible": 1,
@@ -1664,7 +1963,9 @@
"label": "Accounting Details",
"oldfieldtype": "Section Break",
"options": "fa fa-file-text",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "debit_to",
@@ -1677,7 +1978,9 @@
"options": "Account",
"print_hide": 1,
"reqd": 1,
- "search_index": 1
+ "search_index": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "party_account_currency",
@@ -1689,7 +1992,9 @@
"no_copy": 1,
"options": "Currency",
"print_hide": 1,
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"default": "No",
@@ -1701,7 +2006,9 @@
"oldfieldname": "is_opening",
"oldfieldtype": "Select",
"options": "No\nYes",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "c_form_applicable",
@@ -1711,7 +2018,9 @@
"label": "C-Form Applicable",
"no_copy": 1,
"options": "No\nYes",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "c_form_no",
@@ -1722,7 +2031,9 @@
"no_copy": 1,
"options": "C-Form",
"print_hide": 1,
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "column_break8",
@@ -1730,7 +2041,9 @@
"hide_days": 1,
"hide_seconds": 1,
"oldfieldtype": "Column Break",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "remarks",
@@ -1741,7 +2054,9 @@
"no_copy": 1,
"oldfieldname": "remarks",
"oldfieldtype": "Text",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"collapsible": 1,
@@ -1753,7 +2068,9 @@
"label": "Commission",
"oldfieldtype": "Section Break",
"options": "fa fa-group",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "sales_partner",
@@ -1764,7 +2081,9 @@
"oldfieldname": "sales_partner",
"oldfieldtype": "Link",
"options": "Sales Partner",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "column_break10",
@@ -1773,6 +2092,8 @@
"hide_seconds": 1,
"oldfieldtype": "Column Break",
"print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1,
"width": "50%"
},
{
@@ -1783,7 +2104,9 @@
"label": "Commission Rate (%)",
"oldfieldname": "commission_rate",
"oldfieldtype": "Currency",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "total_commission",
@@ -1794,7 +2117,9 @@
"oldfieldname": "total_commission",
"oldfieldtype": "Currency",
"options": "Company:company:default_currency",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"collapsible": 1,
@@ -1804,7 +2129,9 @@
"hide_days": 1,
"hide_seconds": 1,
"label": "Sales Team",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"allow_on_submit": 1,
@@ -1816,7 +2143,9 @@
"oldfieldname": "sales_team",
"oldfieldtype": "Table",
"options": "Sales Team",
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"collapsible": 1,
@@ -1824,7 +2153,9 @@
"fieldtype": "Section Break",
"hide_days": 1,
"hide_seconds": 1,
- "label": "Subscription Section"
+ "label": "Subscription Section",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"allow_on_submit": 1,
@@ -1834,7 +2165,9 @@
"hide_seconds": 1,
"label": "From Date",
"no_copy": 1,
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"allow_on_submit": 1,
@@ -1844,13 +2177,17 @@
"hide_seconds": 1,
"label": "To Date",
"no_copy": 1,
- "print_hide": 1
+ "print_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "column_break_140",
"fieldtype": "Column Break",
"hide_days": 1,
- "hide_seconds": 1
+ "hide_seconds": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"allow_on_submit": 1,
@@ -1862,7 +2199,9 @@
"no_copy": 1,
"options": "Auto Repeat",
"print_hide": 1,
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"allow_on_submit": 1,
@@ -1871,7 +2210,9 @@
"fieldtype": "Button",
"hide_days": 1,
"hide_seconds": 1,
- "label": "Update Auto Repeat Reference"
+ "label": "Update Auto Repeat Reference",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "against_income_account",
@@ -1884,7 +2225,9 @@
"oldfieldname": "against_income_account",
"oldfieldtype": "Small Text",
"print_hide": 1,
- "report_hide": 1
+ "report_hide": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"collapsible": 1,
@@ -1892,13 +2235,17 @@
"fieldtype": "Section Break",
"hide_days": 1,
"hide_seconds": 1,
- "label": "Accounting Dimensions"
+ "label": "Accounting Dimensions",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "dimension_col_break",
"fieldtype": "Column Break",
"hide_days": 1,
- "hide_seconds": 1
+ "hide_seconds": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"default": "0",
@@ -1906,7 +2253,9 @@
"fieldname": "is_consolidated",
"fieldtype": "Check",
"label": "Is Consolidated",
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"default": "0",
@@ -1916,14 +2265,18 @@
"hide_days": 1,
"hide_seconds": 1,
"label": "Is Internal Customer",
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fetch_from": "company.tax_id",
"fieldname": "company_tax_id",
"fieldtype": "Data",
"label": "Company Tax ID",
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"depends_on": "eval:doc.is_internal_customer",
@@ -1931,7 +2284,9 @@
"fieldname": "unrealized_profit_loss_account",
"fieldtype": "Link",
"label": "Unrealized Profit / Loss Account",
- "options": "Account"
+ "options": "Account",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"depends_on": "eval:doc.is_internal_customer",
@@ -1941,31 +2296,51 @@
"fieldtype": "Link",
"label": "Represents Company",
"options": "Company",
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "column_break_55",
- "fieldtype": "Column Break"
+ "fieldtype": "Column Break",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"depends_on": "eval: doc.is_internal_customer && doc.update_stock",
"fieldname": "set_target_warehouse",
"fieldtype": "Link",
"label": "Set Target Warehouse",
- "options": "Warehouse"
+ "options": "Warehouse",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"default": "0",
"fieldname": "is_debit_note",
"fieldtype": "Check",
- "label": "Is Debit Note"
+ "label": "Is Debit Note",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"default": "0",
"depends_on": "grand_total",
"fieldname": "disable_rounded_total",
"fieldtype": "Check",
- "label": "Disable Rounded Total"
+ "label": "Disable Rounded Total",
+ "show_days": 1,
+ "show_seconds": 1
+ },
+ {
+ "default": "0",
+ "fieldname": "ignore_default_payment_terms_template",
+ "fieldtype": "Check",
+ "hidden": 1,
+ "label": "Ignore Default Payment Terms Template",
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
}
],
"icon": "fa fa-file-text",
@@ -1978,7 +2353,7 @@
"link_fieldname": "consolidated_invoice"
}
],
- "modified": "2021-05-20 22:48:33.988881",
+ "modified": "2021-08-06 23:02:20.445127",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice",
diff --git a/erpnext/accounts/party.py b/erpnext/accounts/party.py
index b97dc401e6..329f9a97b8 100644
--- a/erpnext/accounts/party.py
+++ b/erpnext/accounts/party.py
@@ -8,7 +8,7 @@ from frappe import _, msgprint, scrub
from frappe.core.doctype.user_permission.user_permission import get_permitted_documents
from frappe.model.utils import get_fetch_values
from frappe.utils import (add_days, getdate, formatdate, date_diff,
- add_years, get_timestamp, nowdate, flt, cstr, add_months, get_last_day)
+ add_years, get_timestamp, nowdate, flt, cstr, add_months, get_last_day, cint)
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
@@ -58,7 +58,7 @@ def _get_party_details(party=None, account=None, party_type="Customer", company=
customer_group=party_details.customer_group, supplier_group=party_details.supplier_group, tax_category=party_details.tax_category,
billing_address=party_address, shipping_address=shipping_address)
- if fetch_payment_terms_template:
+ if cint(fetch_payment_terms_template):
party_details["payment_terms_template"] = get_payment_terms_template(party.name, party_type, company)
if not party_details.get("currency"):
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py
index f68d81909a..94684bff1c 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.py
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.py
@@ -447,10 +447,11 @@ def get_mapped_purchase_invoice(source_name, target_doc=None, ignore_permissions
target.flags.ignore_permissions = ignore_permissions
set_missing_values(source, target)
#Get the advance paid Journal Entries in Purchase Invoice Advance
-
if target.get("allocate_advances_automatically"):
target.set_advances()
+ target.set_payment_schedule()
+
def update_item(obj, target, source_parent):
target.amount = flt(obj.amount) - flt(obj.billed_amt)
target.base_amount = target.amount * flt(source_parent.conversion_rate)
@@ -492,10 +493,6 @@ def get_mapped_purchase_invoice(source_name, target_doc=None, ignore_permissions
doc = get_mapped_doc("Purchase Order", source_name, fields,
target_doc, postprocess, ignore_permissions=ignore_permissions)
- automatically_fetch_payment_terms = cint(frappe.db.get_single_value('Accounts Settings', 'automatically_fetch_payment_terms'))
- if automatically_fetch_payment_terms:
- doc.set_payment_schedule()
-
return doc
@frappe.whitelist()
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index 78e4ad31ad..00f40cda2c 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -1091,6 +1091,8 @@ class AccountsController(TransactionBase):
if self.doctype in ("Sales Invoice", "Purchase Invoice"):
base_grand_total = base_grand_total - flt(self.base_write_off_amount)
grand_total = grand_total - flt(self.write_off_amount)
+ po_or_so, doctype, fieldname = self.get_order_details()
+ automatically_fetch_payment_terms = cint(frappe.db.get_single_value('Accounts Settings', 'automatically_fetch_payment_terms'))
if self.get("total_advance"):
if party_account_currency == self.company_currency:
@@ -1101,28 +1103,25 @@ class AccountsController(TransactionBase):
base_grand_total = flt(grand_total * self.get("conversion_rate"), self.precision("base_grand_total"))
if not self.get("payment_schedule"):
- if self.doctype in ["Sales Invoice", "Purchase Invoice"] and not self.get("payment_terms_template"):
- po_or_so, doctype, fieldname = self.get_order_details()
-
- if self.get("payment_terms_template"):
+ if self.doctype in ["Sales Invoice", "Purchase Invoice"] and self.linked_order_has_payment_terms(po_or_so, fieldname, doctype):
+ self.fetch_payment_terms_from_order(po_or_so, doctype)
+ if self.get('payment_terms_template'):
+ self.ignore_default_payment_terms_template = 1
+ elif self.get("payment_terms_template"):
data = get_payment_terms(self.payment_terms_template, posting_date, grand_total, base_grand_total)
for item in data:
self.append("payment_schedule", item)
-
- elif self.doctype in ["Sales Invoice", "Purchase Invoice"] and self.linked_order_has_payment_terms(po_or_so, fieldname, doctype):
- self.fetch_payment_terms_from_order(po_or_so, doctype)
-
elif self.doctype not in ["Purchase Receipt"]:
data = dict(due_date=due_date, invoice_portion=100, payment_amount=grand_total, base_payment_amount=base_grand_total)
self.append("payment_schedule", data)
- else:
- for d in self.get("payment_schedule"):
- if d.invoice_portion:
- d.payment_amount = flt(grand_total * flt(d.invoice_portion / 100), d.precision('payment_amount'))
- d.base_payment_amount = flt(base_grand_total * flt(d.invoice_portion / 100), d.precision('base_payment_amount'))
- d.outstanding = d.payment_amount
- elif not d.invoice_portion:
- d.base_payment_amount = flt(base_grand_total * self.get("conversion_rate"), d.precision('base_payment_amount'))
+
+ for d in self.get("payment_schedule"):
+ if d.invoice_portion:
+ d.payment_amount = flt(grand_total * flt(d.invoice_portion / 100), d.precision('payment_amount'))
+ d.base_payment_amount = flt(base_grand_total * flt(d.invoice_portion / 100), d.precision('base_payment_amount'))
+ d.outstanding = d.payment_amount
+ elif not d.invoice_portion:
+ d.base_payment_amount = flt(base_grand_total * self.get("conversion_rate"), d.precision('base_payment_amount'))
def get_order_details(self):
diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py
index 6a550e0e97..974ade3584 100644
--- a/erpnext/controllers/buying_controller.py
+++ b/erpnext/controllers/buying_controller.py
@@ -72,7 +72,8 @@ class BuyingController(StockController, Subcontracting):
# set contact and address details for supplier, if they are not mentioned
if getattr(self, "supplier", None):
self.update_if_missing(get_party_details(self.supplier, party_type="Supplier", ignore_permissions=self.flags.ignore_permissions,
- doctype=self.doctype, company=self.company, party_address=self.supplier_address, shipping_address=self.get('shipping_address')))
+ doctype=self.doctype, company=self.company, party_address=self.supplier_address, shipping_address=self.get('shipping_address'),
+ fetch_payment_terms_template= not self.get('ignore_default_payment_terms_template')))
self.set_missing_item_details(for_validate)
diff --git a/erpnext/public/js/utils/party.js b/erpnext/public/js/utils/party.js
index a79eadc761..54df0d63cb 100644
--- a/erpnext/public/js/utils/party.js
+++ b/erpnext/public/js/utils/party.js
@@ -76,6 +76,7 @@ erpnext.utils.get_party_details = function(frm, method, args, callback) {
if (args) {
args.posting_date = frm.doc.posting_date || frm.doc.transaction_date;
+ args.fetch_payment_terms_template = cint(!frm.doc.ignore_default_payment_terms_template)
}
}
if (!args || !args.party) return;
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
index b05cc7875c..d071f01047 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
@@ -598,6 +598,7 @@ def make_purchase_invoice(source_name, target_doc=None):
doc.run_method("onload")
doc.run_method("set_missing_values")
doc.run_method("calculate_taxes_and_totals")
+ doc.set_payment_schedule()
def update_item(source_doc, target_doc, source_parent):
target_doc.qty, returned_qty = get_pending_qty(source_doc)
@@ -654,10 +655,6 @@ def make_purchase_invoice(source_name, target_doc=None):
}
}, target_doc, set_missing_values)
- automatically_fetch_payment_terms = cint(frappe.db.get_single_value('Accounts Settings', 'automatically_fetch_payment_terms'))
- if automatically_fetch_payment_terms:
- doc.set_payment_schedule()
-
return doclist
def get_invoiced_qty_map(purchase_receipt):
From a27ef14db63b3492c48b0c7352e01df98fd18d5d Mon Sep 17 00:00:00 2001
From: Deepesh Garg
Date: Sat, 7 Aug 2021 00:12:57 +0530
Subject: [PATCH 242/386] fix: Override template only if setting is enabled
---
erpnext/controllers/accounts_controller.py | 3 ++-
erpnext/public/js/utils/party.js | 2 +-
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index 405216bf6f..d967100806 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -1108,7 +1108,8 @@ class AccountsController(TransactionBase):
base_grand_total = flt(grand_total * self.get("conversion_rate"), self.precision("base_grand_total"))
if not self.get("payment_schedule"):
- if self.doctype in ["Sales Invoice", "Purchase Invoice"] and self.linked_order_has_payment_terms(po_or_so, fieldname, doctype):
+ if self.doctype in ["Sales Invoice", "Purchase Invoice"] and automatically_fetch_payment_terms \
+ and self.linked_order_has_payment_terms(po_or_so, fieldname, doctype):
self.fetch_payment_terms_from_order(po_or_so, doctype)
if self.get('payment_terms_template'):
self.ignore_default_payment_terms_template = 1
diff --git a/erpnext/public/js/utils/party.js b/erpnext/public/js/utils/party.js
index 54df0d63cb..4d432e3d5c 100644
--- a/erpnext/public/js/utils/party.js
+++ b/erpnext/public/js/utils/party.js
@@ -76,7 +76,7 @@ erpnext.utils.get_party_details = function(frm, method, args, callback) {
if (args) {
args.posting_date = frm.doc.posting_date || frm.doc.transaction_date;
- args.fetch_payment_terms_template = cint(!frm.doc.ignore_default_payment_terms_template)
+ args.fetch_payment_terms_template = cint(!frm.doc.ignore_default_payment_terms_template);
}
}
if (!args || !args.party) return;
From 25d131a39ffa7624938ccb8bf4742913bf376c52 Mon Sep 17 00:00:00 2001
From: Deepesh Garg
Date: Sat, 7 Aug 2021 17:39:40 +0530
Subject: [PATCH 243/386] test: Improve test case for not coping payment terms
---
.../buying/doctype/purchase_order/purchase_order.py | 1 +
.../doctype/purchase_order/test_purchase_order.py | 12 ++++++++----
erpnext/selling/doctype/sales_order/sales_order.py | 1 +
3 files changed, 10 insertions(+), 4 deletions(-)
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py
index 94684bff1c..a0b1e073cc 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.py
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.py
@@ -471,6 +471,7 @@ def get_mapped_purchase_invoice(source_name, target_doc=None, ignore_permissions
"party_account_currency": "party_account_currency",
"supplier_warehouse":"supplier_warehouse"
},
+ "field_no_map" : ["payment_terms_template"],
"validation": {
"docstatus": ["=", 1],
}
diff --git a/erpnext/buying/doctype/purchase_order/test_purchase_order.py b/erpnext/buying/doctype/purchase_order/test_purchase_order.py
index 0db54e4206..d06f9d2027 100644
--- a/erpnext/buying/doctype/purchase_order/test_purchase_order.py
+++ b/erpnext/buying/doctype/purchase_order/test_purchase_order.py
@@ -633,13 +633,17 @@ class TestPurchaseOrder(unittest.TestCase):
raise Exception
def test_terms_are_not_copied_if_automatically_fetch_payment_terms_is_unchecked(self):
- po = create_purchase_order()
-
- self.assertTrue(po.get('payment_schedule'))
+ po = create_purchase_order(do_not_save=1)
+ po.payment_terms_template = '_Test Payment Term Template'
+ po.save()
+ po.submit()
+ company = frappe.get_doc('Company', '_Test Company', 'payment_terms', '_Test Payment Term Template 1')
pi = make_pi_from_po(po.name)
+ pi.save()
- self.assertFalse(pi.get('payment_schedule'))
+ self.assertEqual(pi.get('payment_terms_template'), '_Test Payment Term Template 1')
+ frappe.db.set_value('Company', '_Test Company', 'payment_terms', '')
def test_terms_copied(self):
po = create_purchase_order(do_not_save=1)
diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py
index 2b9d516e21..bba54018ae 100755
--- a/erpnext/selling/doctype/sales_order/sales_order.py
+++ b/erpnext/selling/doctype/sales_order/sales_order.py
@@ -670,6 +670,7 @@ def make_sales_invoice(source_name, target_doc=None, ignore_permissions=False):
"party_account_currency": "party_account_currency",
"payment_terms_template": "payment_terms_template"
},
+ "field_no_map": ["payment_terms_template"],
"validation": {
"docstatus": ["=", 1]
}
From 5ace2767afac395e94991d1563d03eff1f53e9e9 Mon Sep 17 00:00:00 2001
From: Deepesh Garg
Date: Sun, 8 Aug 2021 19:17:38 +0530
Subject: [PATCH 244/386] test: Fix test cases for payment terms fetch
---
.../buying/doctype/purchase_order/test_purchase_order.py | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/erpnext/buying/doctype/purchase_order/test_purchase_order.py b/erpnext/buying/doctype/purchase_order/test_purchase_order.py
index d06f9d2027..d668c76b6b 100644
--- a/erpnext/buying/doctype/purchase_order/test_purchase_order.py
+++ b/erpnext/buying/doctype/purchase_order/test_purchase_order.py
@@ -484,6 +484,9 @@ class TestPurchaseOrder(unittest.TestCase):
def test_make_purchase_invoice_with_terms(self):
+ from erpnext.selling.doctype.sales_order.test_sales_order import automatically_fetch_payment_terms, compare_payment_schedules
+
+ automatically_fetch_payment_terms()
po = create_purchase_order(do_not_save=True)
self.assertRaises(frappe.ValidationError, make_pi_from_po, po.name)
@@ -509,6 +512,7 @@ class TestPurchaseOrder(unittest.TestCase):
self.assertEqual(getdate(pi.payment_schedule[0].due_date), getdate(po.transaction_date))
self.assertEqual(pi.payment_schedule[1].payment_amount, 2500.0)
self.assertEqual(getdate(pi.payment_schedule[1].due_date), add_days(getdate(po.transaction_date), 30))
+ automatically_fetch_payment_terms(enable=0)
def test_subcontracting(self):
po = create_purchase_order(item_code="_Test FG Item", is_subcontracted="Yes")
@@ -638,7 +642,7 @@ class TestPurchaseOrder(unittest.TestCase):
po.save()
po.submit()
- company = frappe.get_doc('Company', '_Test Company', 'payment_terms', '_Test Payment Term Template 1')
+ frappe.db.set_value('Company', '_Test Company', 'payment_terms', '_Test Payment Term Template 1')
pi = make_pi_from_po(po.name)
pi.save()
@@ -992,7 +996,7 @@ class TestPurchaseOrder(unittest.TestCase):
# self.assertEqual(po.payment_terms_template, pi.payment_terms_template)
compare_payment_schedules(self, po, pi)
- automatically_fetch_payment_terms(enable=0)
+ automatically_fetch_payment_terms(enable=0)
def make_pr_against_po(po, received_qty=0):
pr = make_purchase_receipt(po)
From bba9aac9c0fd3d5c047ec6eccca098654e240bb0 Mon Sep 17 00:00:00 2001
From: Frappe PR Bot
Date: Mon, 9 Aug 2021 10:58:39 +0530
Subject: [PATCH 245/386] feat: add french address template (bp #26316)
* add french address template
Co-authored-by: HENRY Florian
(cherry picked from commit 07e65ab5895f166b6dceb38dfbea1cb90f6015b9)
---
erpnext/regional/address_template/templates/france.html | 5 +++++
1 file changed, 5 insertions(+)
create mode 100644 erpnext/regional/address_template/templates/france.html
diff --git a/erpnext/regional/address_template/templates/france.html b/erpnext/regional/address_template/templates/france.html
new file mode 100644
index 0000000000..752331eeec
--- /dev/null
+++ b/erpnext/regional/address_template/templates/france.html
@@ -0,0 +1,5 @@
+{% if address_line1 %}{{ address_line1 }}{% endif -%}
+{% if address_line2 %} {{ address_line2 }}{% endif -%}
+{% if pincode %} {{ pincode }}{% endif -%}
+{% if city %} {{ city }}{% endif -%}
+{% if country %} {{ country }}{% endif -%}
From 3dfbf19e8f6ee97be7a1a727b98bfc0db1ec3db7 Mon Sep 17 00:00:00 2001
From: Frappe PR Bot
Date: Mon, 9 Aug 2021 11:33:55 +0530
Subject: [PATCH 246/386] fix: allow alternative items when using job card (bp
#26724)
(cherry picked from commit 7e0c57fa3fe62417ad3be75412e0c031d6486bb8)
Co-authored-by: Ankush
---
erpnext/manufacturing/doctype/job_card/job_card.py | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/erpnext/manufacturing/doctype/job_card/job_card.py b/erpnext/manufacturing/doctype/job_card/job_card.py
index 69c7f5c614..66e2394b84 100644
--- a/erpnext/manufacturing/doctype/job_card/job_card.py
+++ b/erpnext/manufacturing/doctype/job_card/job_card.py
@@ -608,6 +608,11 @@ def make_stock_entry(source_name, target_doc=None):
target.set_missing_values()
target.set_stock_entry_type()
+ wo_allows_alternate_item = frappe.db.get_value("Work Order", target.work_order, "allow_alternative_item")
+ for item in target.items:
+ item.allow_alternative_item = int(wo_allows_alternate_item and
+ frappe.get_cached_value("Item", item.item_code, "allow_alternative_item"))
+
doclist = get_mapped_doc("Job Card", source_name, {
"Job Card": {
"doctype": "Stock Entry",
@@ -698,4 +703,4 @@ def make_corrective_job_card(source_name, operation=None, for_operation=None, ta
}
}, target_doc, set_missing_values)
- return doclist
\ No newline at end of file
+ return doclist
From 210441d9b59f58f450bad4d61879e61549f5ac5c Mon Sep 17 00:00:00 2001
From: Frappe PR Bot
Date: Mon, 9 Aug 2021 11:34:33 +0530
Subject: [PATCH 247/386] fix: price list with 0 value are ignored (bp #26655)
* fix: price list with 0 value are ignored
Steps to reproduce:
1. Create 2 item price for two different supplier. One of them should be
zero.
2. Create PO
3. Add supplier with non-zero price and add item.
4. change supplier. Price won't change. If price was non-zero it
would've changed.
Root cause: falsiness check instead of null value check is used for
checking if price list value exists. 0 is evaluated as false.
* refactor: make get_price_list_rate function pure
(cherry picked from commit 16d4de5130097bc2dfdc7e073f1e13f0a22481d1)
Co-authored-by: Ankush
---
erpnext/manufacturing/doctype/bom/bom.py | 5 ++---
erpnext/stock/get_item_details.py | 21 ++++++++++++---------
2 files changed, 14 insertions(+), 12 deletions(-)
diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py
index 4e93fc6799..0ba85078ea 100644
--- a/erpnext/manufacturing/doctype/bom/bom.py
+++ b/erpnext/manufacturing/doctype/bom/bom.py
@@ -717,9 +717,8 @@ def get_bom_item_rate(args, bom_doc):
"ignore_conversion_rate": True
})
item_doc = frappe.get_cached_doc("Item", args.get("item_code"))
- out = frappe._dict()
- get_price_list_rate(bom_args, item_doc, out)
- rate = out.price_list_rate
+ price_list_data = get_price_list_rate(bom_args, item_doc)
+ rate = price_list_data.price_list_rate
return rate
diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py
index 2ed7a04ba8..be8508a000 100644
--- a/erpnext/stock/get_item_details.py
+++ b/erpnext/stock/get_item_details.py
@@ -74,8 +74,7 @@ def get_item_details(args, doc=None, for_validate=False, overwrite_warehouse=Tru
update_party_blanket_order(args, out)
-
- get_price_list_rate(args, item, out)
+ out.update(get_price_list_rate(args, item))
if args.customer and cint(args.is_pos):
out.update(get_pos_profile_item_details(args.company, args, update_data=True))
@@ -638,7 +637,10 @@ def get_default_supplier(args, item, item_group, brand):
or item_group.get("default_supplier")
or brand.get("default_supplier"))
-def get_price_list_rate(args, item_doc, out):
+def get_price_list_rate(args, item_doc, out=None):
+ if out is None:
+ out = frappe._dict()
+
meta = frappe.get_meta(args.parenttype or args.doctype)
if meta.get_field("currency") or args.get('currency'):
@@ -651,17 +653,17 @@ def get_price_list_rate(args, item_doc, out):
if meta.get_field("currency"):
validate_conversion_rate(args, meta)
- price_list_rate = get_price_list_rate_for(args, item_doc.name) or 0
+ price_list_rate = get_price_list_rate_for(args, item_doc.name)
# variant
- if not price_list_rate and item_doc.variant_of:
+ if price_list_rate is None and item_doc.variant_of:
price_list_rate = get_price_list_rate_for(args, item_doc.variant_of)
# insert in database
- if not price_list_rate:
+ if price_list_rate is None:
if args.price_list and args.rate:
insert_item_price(args)
- return {}
+ return out
out.price_list_rate = flt(price_list_rate) * flt(args.plc_conversion_rate) \
/ flt(args.conversion_rate)
@@ -671,6 +673,8 @@ def get_price_list_rate(args, item_doc, out):
out.update(get_last_purchase_details(item_doc.name,
args.name, args.conversion_rate))
+ return out
+
def insert_item_price(args):
"""Insert Item Price if Price List and Price List Rate are specified and currency is the same"""
if frappe.db.get_value("Price List", args.price_list, "currency", cache=True) == args.currency \
@@ -1073,9 +1077,8 @@ def apply_price_list(args, as_doc=False):
}
def apply_price_list_on_item(args):
- item_details = frappe._dict()
item_doc = frappe.get_doc("Item", args.item_code)
- get_price_list_rate(args, item_doc, item_details)
+ item_details = get_price_list_rate(args, item_doc)
item_details.update(get_pricing_rule_for_item(args, item_details.price_list_rate))
From a8166c06c7e471cfcf67d4ec6cacdc2d67e12485 Mon Sep 17 00:00:00 2001
From: Marica
Date: Mon, 9 Aug 2021 12:24:04 +0530
Subject: [PATCH 248/386] fix: Faulty Gl Entry for Asset LCVs (#26803)
* fix: Faulty Gl Entry for Asset LCVs
- Both Gl entries were crediting in their respective accounts
- Asset Account must be debited into
* fix: Use keyword arguments instead of positional for better readability
* chore: Test for LCV for draft asset created via Purchase Receipt
---
.../test_landed_cost_voucher.py | 35 +++-
.../purchase_receipt/purchase_receipt.py | 151 +++++++++++++++---
2 files changed, 159 insertions(+), 27 deletions(-)
diff --git a/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py b/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py
index 32b08f60c4..128a2ab62f 100644
--- a/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py
+++ b/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py
@@ -11,6 +11,7 @@ from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt \
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
from erpnext.accounts.doctype.account.test_account import get_inventory_account
from erpnext.accounts.doctype.account.test_account import create_account
+from erpnext.assets.doctype.asset.test_asset import create_asset_category, create_fixed_asset_item
class TestLandedCostVoucher(unittest.TestCase):
def test_landed_cost_voucher(self):
@@ -250,6 +251,38 @@ class TestLandedCostVoucher(unittest.TestCase):
self.assertEqual(entry.credit, amounts[0])
self.assertEqual(entry.credit_in_account_currency, amounts[1])
+ def test_asset_lcv(self):
+ "Check if LCV for an Asset updates the Assets Gross Purchase Amount correctly."
+ if not frappe.db.exists("Asset Category", "Computers"):
+ create_asset_category()
+
+ if not frappe.db.exists("Item", "Macbook Pro"):
+ create_fixed_asset_item()
+
+ pr = make_purchase_receipt(item_code="Macbook Pro", qty=1, rate=50000)
+
+ # check if draft asset was created
+ assets = frappe.db.get_all('Asset', filters={'purchase_receipt': pr.name})
+ self.assertEqual(len(assets), 1)
+
+ frappe.db.set_value("Company", pr.company, "capital_work_in_progress_account", "CWIP Account - _TC")
+ lcv = make_landed_cost_voucher(
+ company = pr.company,
+ receipt_document_type = "Purchase Receipt",
+ receipt_document=pr.name,
+ charges=80,
+ expense_account="Expenses Included In Valuation - _TC")
+
+ lcv.save()
+ lcv.submit()
+
+ # lcv updates amount in draft asset
+ self.assertEqual(frappe.db.get_value("Asset", assets[0].name, "gross_purchase_amount"), 50080)
+
+ # tear down
+ lcv.cancel()
+ pr.cancel()
+
def make_landed_cost_voucher(** args):
args = frappe._dict(args)
ref_doc = frappe.get_doc(args.receipt_document_type, args.receipt_document)
@@ -268,7 +301,7 @@ def make_landed_cost_voucher(** args):
lcv.set("taxes", [{
"description": "Shipping Charges",
- "expense_account": "Expenses Included In Valuation - TCP1",
+ "expense_account": args.expense_account or "Expenses Included In Valuation - TCP1",
"amount": args.charges
}])
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
index 26ea11e01d..96e14ef759 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
@@ -286,8 +286,16 @@ class PurchaseReceipt(BuyingController):
and warehouse_account_name == supplier_warehouse_account:
continue
- self.add_gl_entry(gl_entries, warehouse_account_name, d.cost_center, stock_value_diff, 0.0, remarks,
- stock_rbnb, account_currency=warehouse_account_currency, item=d)
+ self.add_gl_entry(
+ gl_entries=gl_entries,
+ account=warehouse_account_name,
+ cost_center=d.cost_center,
+ debit=stock_value_diff,
+ credit=0.0,
+ remarks=remarks,
+ against_account=stock_rbnb,
+ account_currency=warehouse_account_currency,
+ item=d)
# GL Entry for from warehouse or Stock Received but not billed
# Intentionally passed negative debit amount to avoid incorrect GL Entry validation
@@ -300,9 +308,17 @@ class PurchaseReceipt(BuyingController):
account = warehouse_account[d.from_warehouse]['account'] \
if d.from_warehouse else stock_rbnb
- self.add_gl_entry(gl_entries, account, d.cost_center,
- -1 * flt(d.base_net_amount, d.precision("base_net_amount")), 0.0, remarks, warehouse_account_name,
- debit_in_account_currency=-1 * credit_amount, account_currency=credit_currency, item=d)
+ self.add_gl_entry(
+ gl_entries=gl_entries,
+ account=account,
+ cost_center=d.cost_center,
+ debit=-1 * flt(d.base_net_amount, d.precision("base_net_amount")),
+ credit=0.0,
+ remarks=remarks,
+ against_account=warehouse_account_name,
+ debit_in_account_currency=-1 * credit_amount,
+ account_currency=credit_currency,
+ item=d)
# Amount added through landed-cos-voucher
if d.landed_cost_voucher_amount and landed_cost_entries:
@@ -311,14 +327,31 @@ class PurchaseReceipt(BuyingController):
credit_amount = (flt(amount["base_amount"]) if (amount["base_amount"] or
account_currency!=self.company_currency) else flt(amount["amount"]))
- self.add_gl_entry(gl_entries, account, d.cost_center, 0.0, credit_amount, remarks,
- warehouse_account_name, credit_in_account_currency=flt(amount["amount"]),
- account_currency=account_currency, project=d.project, item=d)
+ self.add_gl_entry(
+ gl_entries=gl_entries,
+ account=account,
+ cost_center=d.cost_center,
+ debit=0.0,
+ credit=credit_amount,
+ remarks=remarks,
+ against_account=warehouse_account_name,
+ credit_in_account_currency=flt(amount["amount"]),
+ account_currency=account_currency,
+ project=d.project,
+ item=d)
# sub-contracting warehouse
if flt(d.rm_supp_cost) and warehouse_account.get(self.supplier_warehouse):
- self.add_gl_entry(gl_entries, supplier_warehouse_account, d.cost_center, 0.0, flt(d.rm_supp_cost),
- remarks, warehouse_account_name, account_currency=supplier_warehouse_account_currency, item=d)
+ self.add_gl_entry(
+ gl_entries=gl_entries,
+ account=supplier_warehouse_account,
+ cost_center=d.cost_center,
+ debit=0.0,
+ credit=flt(d.rm_supp_cost),
+ remarks=remarks,
+ against_account=warehouse_account_name,
+ account_currency=supplier_warehouse_account_currency,
+ item=d)
# divisional loss adjustment
valuation_amount_as_per_doc = flt(d.base_net_amount, d.precision("base_net_amount")) + \
@@ -335,8 +368,17 @@ class PurchaseReceipt(BuyingController):
cost_center = d.cost_center or frappe.get_cached_value("Company", self.company, "cost_center")
- self.add_gl_entry(gl_entries, loss_account, cost_center, divisional_loss, 0.0, remarks,
- warehouse_account_name, account_currency=credit_currency, project=d.project, item=d)
+ self.add_gl_entry(
+ gl_entries=gl_entries,
+ account=loss_account,
+ cost_center=cost_center,
+ debit=divisional_loss,
+ credit=0.0,
+ remarks=remarks,
+ against_account=warehouse_account_name,
+ account_currency=credit_currency,
+ project=d.project,
+ item=d)
elif d.warehouse not in warehouse_with_no_account or \
d.rejected_warehouse not in warehouse_with_no_account:
@@ -347,12 +389,30 @@ class PurchaseReceipt(BuyingController):
debit_currency = get_account_currency(d.expense_account)
remarks = self.get("remarks") or _("Accounting Entry for Service")
- self.add_gl_entry(gl_entries, service_received_but_not_billed_account, d.cost_center, 0.0, d.amount,
- remarks, d.expense_account, account_currency=credit_currency, project=d.project,
+ self.add_gl_entry(
+ gl_entries=gl_entries,
+ account=service_received_but_not_billed_account,
+ cost_center=d.cost_center,
+ debit=0.0,
+ credit=d.amount,
+ remarks=remarks,
+ against_account=d.expense_account,
+ account_currency=credit_currency,
+ project=d.project,
voucher_detail_no=d.name, item=d)
- self.add_gl_entry(gl_entries, d.expense_account, d.cost_center, d.amount, 0.0, remarks, service_received_but_not_billed_account,
- account_currency = debit_currency, project=d.project, voucher_detail_no=d.name, item=d)
+ self.add_gl_entry(
+ gl_entries=gl_entries,
+ account=d.expense_account,
+ cost_center=d.cost_center,
+ debit=d.amount,
+ credit=0.0,
+ remarks=remarks,
+ against_account=service_received_but_not_billed_account,
+ account_currency = debit_currency,
+ project=d.project,
+ voucher_detail_no=d.name,
+ item=d)
if warehouse_with_no_account:
frappe.msgprint(_("No accounting entries for the following warehouses") + ": \n" +
@@ -402,8 +462,15 @@ class PurchaseReceipt(BuyingController):
applicable_amount = negative_expense_to_be_booked * (valuation_tax[tax.name] / total_valuation_amount)
amount_including_divisional_loss -= applicable_amount
- self.add_gl_entry(gl_entries, account, tax.cost_center, 0.0, applicable_amount, self.remarks or _("Accounting Entry for Stock"),
- against_account, item=tax)
+ self.add_gl_entry(
+ gl_entries=gl_entries,
+ account=account,
+ cost_center=tax.cost_center,
+ debit=0.0,
+ credit=applicable_amount,
+ remarks=self.remarks or _("Accounting Entry for Stock"),
+ against_account=against_account,
+ item=tax)
i += 1
@@ -456,15 +523,31 @@ class PurchaseReceipt(BuyingController):
# debit cwip account
debit_in_account_currency = (base_asset_amount
if cwip_account_currency == self.company_currency else asset_amount)
- self.add_gl_entry(gl_entries, cwip_account, item.cost_center, base_asset_amount, 0.0, remarks,
- arbnb_account, debit_in_account_currency=debit_in_account_currency, item=item)
+ self.add_gl_entry(
+ gl_entries=gl_entries,
+ account=cwip_account,
+ cost_center=item.cost_center,
+ debit=base_asset_amount,
+ credit=0.0,
+ remarks=remarks,
+ against_account=arbnb_account,
+ debit_in_account_currency=debit_in_account_currency,
+ item=item)
asset_rbnb_currency = get_account_currency(arbnb_account)
# credit arbnb account
credit_in_account_currency = (base_asset_amount
if asset_rbnb_currency == self.company_currency else asset_amount)
- self.add_gl_entry(gl_entries, arbnb_account, item.cost_center, 0.0, base_asset_amount, remarks,
- cwip_account, credit_in_account_currency=credit_in_account_currency, item=item)
+ self.add_gl_entry(
+ gl_entries=gl_entries,
+ account=arbnb_account,
+ cost_center=item.cost_center,
+ debit=0.0,
+ credit=base_asset_amount,
+ remarks=remarks,
+ against_account=cwip_account,
+ credit_in_account_currency=credit_in_account_currency,
+ item=item)
def add_lcv_gl_entries(self, item, gl_entries):
expenses_included_in_asset_valuation = self.get_company_default("expenses_included_in_asset_valuation")
@@ -477,11 +560,27 @@ class PurchaseReceipt(BuyingController):
remarks = self.get("remarks") or _("Accounting Entry for Stock")
- self.add_gl_entry(gl_entries, expenses_included_in_asset_valuation, item.cost_center, 0.0, flt(item.landed_cost_voucher_amount),
- remarks, asset_account, project=item.project, item=item)
+ self.add_gl_entry(
+ gl_entries=gl_entries,
+ account=expenses_included_in_asset_valuation,
+ cost_center=item.cost_center,
+ debit=0.0,
+ credit=flt(item.landed_cost_voucher_amount),
+ remarks=remarks,
+ against_account=asset_account,
+ project=item.project,
+ item=item)
- self.add_gl_entry(gl_entries, asset_account, item.cost_center, 0.0, flt(item.landed_cost_voucher_amount),
- remarks, expenses_included_in_asset_valuation, project=item.project, item=item)
+ self.add_gl_entry(
+ gl_entries=gl_entries,
+ account=asset_account,
+ cost_center=item.cost_center,
+ debit=flt(item.landed_cost_voucher_amount),
+ credit=0.0,
+ remarks=remarks,
+ against_account=expenses_included_in_asset_valuation,
+ project=item.project,
+ item=item)
def update_assets(self, item, valuation_rate):
assets = frappe.db.get_all('Asset',
From ea83e2b45fb4219bf643e844ba85d682b6c44556 Mon Sep 17 00:00:00 2001
From: Frappe PR Bot
Date: Mon, 9 Aug 2021 14:48:59 +0530
Subject: [PATCH 249/386] fix: validate python expressions (#26835) (#26856)
(cherry picked from commit 07337d5c78c14119ae9fc5d010080a1db61d0bdd)
Co-authored-by: Ankush
---
erpnext/accounts/doctype/pricing_rule/pricing_rule.json | 5 +++--
.../item_quality_inspection_parameter.json | 5 +++--
2 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.json b/erpnext/accounts/doctype/pricing_rule/pricing_rule.json
index 428989aa96..0be41b4063 100644
--- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.json
+++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.json
@@ -558,7 +558,8 @@
"description": "Simple Python Expression, Example: territory != 'All Territories'",
"fieldname": "condition",
"fieldtype": "Code",
- "label": "Condition"
+ "label": "Condition",
+ "options": "PythonExpression"
},
{
"fieldname": "column_break_42",
@@ -575,7 +576,7 @@
"icon": "fa fa-gift",
"idx": 1,
"links": [],
- "modified": "2021-03-06 22:01:24.840422",
+ "modified": "2021-08-06 15:10:04.219321",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Pricing Rule",
diff --git a/erpnext/stock/doctype/item_quality_inspection_parameter/item_quality_inspection_parameter.json b/erpnext/stock/doctype/item_quality_inspection_parameter/item_quality_inspection_parameter.json
index 9b1a47eed6..5de45cbcad 100644
--- a/erpnext/stock/doctype/item_quality_inspection_parameter/item_quality_inspection_parameter.json
+++ b/erpnext/stock/doctype/item_quality_inspection_parameter/item_quality_inspection_parameter.json
@@ -47,7 +47,8 @@
"description": "Simple Python formula applied on Reading fields. Numeric eg. 1: reading_1 > 0.2 and reading_1 < 0.5 \nNumeric eg. 2: mean > 3.5 (mean of populated fields) \nValue based eg.: reading_value in (\"A\", \"B\", \"C\") ",
"fieldname": "acceptance_formula",
"fieldtype": "Code",
- "label": "Acceptance Criteria Formula"
+ "label": "Acceptance Criteria Formula",
+ "options": "PythonExpression"
},
{
"default": "0",
@@ -89,7 +90,7 @@
"idx": 1,
"istable": 1,
"links": [],
- "modified": "2021-02-04 18:50:02.056173",
+ "modified": "2021-08-06 15:08:20.911338",
"modified_by": "Administrator",
"module": "Stock",
"name": "Item Quality Inspection Parameter",
From 9f5111809d2264c555b2990a2dbe4340dc2fbad5 Mon Sep 17 00:00:00 2001
From: Ankush
Date: Mon, 9 Aug 2021 15:35:26 +0530
Subject: [PATCH 250/386] test: fix flaky purchase receipt test (#26859)
(#26860)
# Conflicts:
# erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
---
.../purchase_receipt/test_purchase_receipt.py | 15 ++-------------
1 file changed, 2 insertions(+), 13 deletions(-)
diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
index ca6e61fe6b..b4abeff94f 100644
--- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
@@ -324,18 +324,7 @@ class TestPurchaseReceipt(unittest.TestCase):
pr1.submit()
self.assertRaises(frappe.ValidationError, pr2.submit)
-
- pr1.cancel()
- se.cancel()
- se1.cancel()
- se2.cancel()
- se3.cancel()
- po.reload()
- pr2.load_from_db()
- pr2.cancel()
-
- po.load_from_db()
- po.cancel()
+ frappe.db.rollback()
def test_serial_no_supplier(self):
pr = make_purchase_receipt(item_code="_Test Serialized Item With Series", qty=1)
@@ -1040,7 +1029,7 @@ class TestPurchaseReceipt(unittest.TestCase):
'account': srbnb_account,
'voucher_detail_no': pr.items[1].name
}, pluck="name")
-
+
# check if the entries are not merged into one
# seperate entries should be made since voucher_detail_no is different
self.assertEqual(len(item_one_gl_entry), 1)
From 0ff9ef673c0ec99667f6ade2e3de41bf61224ad0 Mon Sep 17 00:00:00 2001
From: Frappe PR Bot
Date: Mon, 9 Aug 2021 17:58:18 +0530
Subject: [PATCH 251/386] fix: add parameter for db insert while adding item
tax (#26855) (#26858)
(cherry picked from commit b3bbebd27c73827d5a88ff47d0d16fb73dcf6de2)
Co-authored-by: Afshan <33727827+AfshanKhan@users.noreply.github.com>
---
erpnext/controllers/accounts_controller.py | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index a9b7efbe98..498f3cf0e9 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -1507,7 +1507,7 @@ def set_child_tax_template_and_map(item, child_item, parent_doc):
if child_item.get("item_tax_template"):
child_item.item_tax_rate = get_item_tax_map(parent_doc.get('company'), child_item.item_tax_template, as_json=True)
-def add_taxes_from_tax_template(child_item, parent_doc):
+def add_taxes_from_tax_template(child_item, parent_doc, db_insert=True):
add_taxes_from_item_tax_template = frappe.db.get_single_value("Accounts Settings", "add_taxes_from_item_tax_template")
if child_item.get("item_tax_rate") and add_taxes_from_item_tax_template:
@@ -1530,7 +1530,8 @@ def add_taxes_from_tax_template(child_item, parent_doc):
"category" : "Total",
"add_deduct_tax" : "Add"
})
- tax_row.db_insert()
+ if db_insert:
+ tax_row.db_insert()
def set_order_defaults(parent_doctype, parent_doctype_name, child_doctype, child_docname, trans_item):
"""
From 18bd182f615ab8894ab505184ad9f3e604913977 Mon Sep 17 00:00:00 2001
From: Frappe PR Bot
Date: Mon, 9 Aug 2021 18:34:51 +0530
Subject: [PATCH 252/386] patch: delete all orphaned tables docs (#26863)
---
erpnext/patches.txt | 1 +
.../patches/v13_0/delete_orphaned_tables.py | 69 +++++++++++++++++++
2 files changed, 70 insertions(+)
create mode 100644 erpnext/patches/v13_0/delete_orphaned_tables.py
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index ae01496f02..ada3badd7c 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -294,6 +294,7 @@ erpnext.patches.v13_0.update_level_in_bom #1234sswef
erpnext.patches.v13_0.add_missing_fg_item_for_stock_entry
erpnext.patches.v13_0.update_subscription_status_in_memberships
erpnext.patches.v13_0.update_amt_in_work_order_required_items
+erpnext.patches.v13_0.delete_orphaned_tables
erpnext.patches.v13_0.update_export_type_for_gst
erpnext.patches.v13_0.update_tds_check_field #3
erpnext.patches.v13_0.update_recipient_email_digest
diff --git a/erpnext/patches/v13_0/delete_orphaned_tables.py b/erpnext/patches/v13_0/delete_orphaned_tables.py
new file mode 100644
index 0000000000..1d6eebe039
--- /dev/null
+++ b/erpnext/patches/v13_0/delete_orphaned_tables.py
@@ -0,0 +1,69 @@
+# Copyright (c) 2019, Frappe and Contributors
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+
+import frappe
+from frappe.utils import getdate
+
+def execute():
+ frappe.reload_doc('setup', 'doctype', 'transaction_deletion_record')
+
+ if has_deleted_company_transactions():
+ child_doctypes = get_child_doctypes_whose_parent_doctypes_were_affected()
+
+ for doctype in child_doctypes:
+ docs = frappe.get_all(doctype, fields=['name', 'parent', 'parenttype', 'creation'])
+
+ for doc in docs:
+ if not frappe.db.exists(doc['parenttype'], doc['parent']):
+ frappe.db.delete(doctype, {'name': doc['name']})
+
+ elif check_for_new_doc_with_same_name_as_deleted_parent(doc):
+ frappe.db.delete(doctype, {'name': doc['name']})
+
+def has_deleted_company_transactions():
+ return frappe.get_all('Transaction Deletion Record')
+
+def get_child_doctypes_whose_parent_doctypes_were_affected():
+ parent_doctypes = get_affected_doctypes()
+ child_doctypes = frappe.get_all(
+ 'DocField',
+ filters={
+ 'fieldtype': 'Table',
+ 'parent':['in', parent_doctypes]
+ }, pluck='options')
+
+ return child_doctypes
+
+def get_affected_doctypes():
+ affected_doctypes = []
+ tdr_docs = frappe.get_all('Transaction Deletion Record', pluck="name")
+
+ for tdr in tdr_docs:
+ tdr_doc = frappe.get_doc("Transaction Deletion Record", tdr)
+
+ for doctype in tdr_doc.doctypes:
+ if is_not_child_table(doctype.doctype_name):
+ affected_doctypes.append(doctype.doctype_name)
+
+ affected_doctypes = remove_duplicate_items(affected_doctypes)
+ return affected_doctypes
+
+def is_not_child_table(doctype):
+ return not bool(frappe.get_value('DocType', doctype, 'istable'))
+
+def remove_duplicate_items(affected_doctypes):
+ return list(set(affected_doctypes))
+
+def check_for_new_doc_with_same_name_as_deleted_parent(doc):
+ """
+ Compares creation times of parent and child docs.
+ Since Transaction Deletion Record resets the naming series after deletion,
+ it allows the creation of new docs with the same names as the deleted ones.
+ """
+
+ parent_creation_time = frappe.db.get_value(doc['parenttype'], doc['parent'], 'creation')
+ child_creation_time = doc['creation']
+
+ return getdate(parent_creation_time) > getdate(child_creation_time)
\ No newline at end of file
From 0a90302170e499b468ced0a437ed1c2a7fab6dbe Mon Sep 17 00:00:00 2001
From: Francisco Roldan
Date: Mon, 9 Aug 2021 11:41:56 -0300
Subject: [PATCH 253/386] fix: depends_on in price list field
---
.../accounts/doctype/subscription_plan/subscription_plan.json | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/erpnext/accounts/doctype/subscription_plan/subscription_plan.json b/erpnext/accounts/doctype/subscription_plan/subscription_plan.json
index 46ce0939e4..771611a786 100644
--- a/erpnext/accounts/doctype/subscription_plan/subscription_plan.json
+++ b/erpnext/accounts/doctype/subscription_plan/subscription_plan.json
@@ -78,7 +78,7 @@
"label": "Cost"
},
{
- "depends_on": "eval:doc.price_determination==\"Based on price list\"",
+ "depends_on": "eval:doc.price_determination==\"Based On Price List\"",
"fieldname": "price_list",
"fieldtype": "Link",
"label": "Price List",
@@ -147,7 +147,7 @@
}
],
"links": [],
- "modified": "2020-06-25 10:53:44.205774",
+ "modified": "2021-08-09 10:53:44.205774",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Subscription Plan",
From b73bb3e5013e08276f7af4f83321cc600b081ad0 Mon Sep 17 00:00:00 2001
From: Deepesh Garg
Date: Thu, 5 Aug 2021 22:38:00 +0530
Subject: [PATCH 254/386] fix: Add discount account handling in Purchase
Invoice
---
.../purchase_invoice/purchase_invoice.py | 25 +++++++++++--------
1 file changed, 14 insertions(+), 11 deletions(-)
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
index feae213d92..d0f4e96541 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
@@ -519,6 +519,10 @@ class PurchaseInvoice(BuyingController):
if d.category in ('Valuation', 'Total and Valuation')
and flt(d.base_tax_amount_after_discount_amount)]
+ exchange_rate_map, net_rate_map = get_purchase_document_details(self)
+
+ enable_discount_accounting = cint(frappe.db.get_single_value('Accounts Settings', 'enable_discount_accounting'))
+
for item in self.get("items"):
if flt(item.base_net_amount):
account_currency = get_account_currency(item.expense_account)
@@ -609,11 +613,7 @@ class PurchaseInvoice(BuyingController):
if (not item.enable_deferred_expense or self.is_return) else item.deferred_expense_account)
if not item.is_fixed_asset:
- if frappe.db.get_single_value('Accounts Settings', 'enable_discount_accounting'):
- amount = flt(item.base_amount, item.precision("base_amount"))
- else:
- amount = flt(item.base_net_amount, item.precision("base_net_amount"))
-
+ dummy, amount = self.get_amount_and_base_amount(item, enable_discount_accounting)
else:
amount = flt(item.base_net_amount + item.item_tax_amount, item.precision("base_net_amount"))
@@ -827,8 +827,11 @@ class PurchaseInvoice(BuyingController):
def make_tax_gl_entries(self, gl_entries):
# tax table gl entries
valuation_tax = {}
+ enable_discount_accounting = cint(frappe.db.get_single_value('Accounts Settings', 'enable_discount_accounting'))
+
for tax in self.get("taxes"):
- if tax.category in ("Total", "Valuation and Total") and flt(tax.base_tax_amount_after_discount_amount):
+ amount, base_amount = self.get_tax_amounts(tax, enable_discount_accounting)
+ if tax.category in ("Total", "Valuation and Total") and flt(base_amount):
account_currency = get_account_currency(tax.account_head)
dr_or_cr = "debit" if tax.add_deduct_tax == "Add" else "credit"
@@ -837,21 +840,21 @@ class PurchaseInvoice(BuyingController):
self.get_gl_dict({
"account": tax.account_head,
"against": self.supplier,
- dr_or_cr: tax.base_tax_amount_after_discount_amount,
- dr_or_cr + "_in_account_currency": tax.base_tax_amount_after_discount_amount \
+ dr_or_cr: base_amount,
+ dr_or_cr + "_in_account_currency": base_amount \
if account_currency==self.company_currency \
- else tax.tax_amount_after_discount_amount,
+ else amount,
"cost_center": tax.cost_center
}, account_currency, item=tax)
)
# accumulate valuation tax
- if self.is_opening == "No" and tax.category in ("Valuation", "Valuation and Total") and flt(tax.base_tax_amount_after_discount_amount) \
+ if self.is_opening == "No" and tax.category in ("Valuation", "Valuation and Total") and flt(base_amount) \
and not self.is_internal_transfer():
if self.auto_accounting_for_stock and not tax.cost_center:
frappe.throw(_("Cost Center is required in row {0} in Taxes table for type {1}").format(tax.idx, _(tax.category)))
valuation_tax.setdefault(tax.name, 0)
valuation_tax[tax.name] += \
- (tax.add_deduct_tax == "Add" and 1 or -1) * flt(tax.base_tax_amount_after_discount_amount)
+ (tax.add_deduct_tax == "Add" and 1 or -1) * flt(base_amount)
if self.is_opening == "No" and self.negative_expense_to_be_booked and valuation_tax:
# credit valuation tax amount in "Expenses Included In Valuation"
From 428ccebad95a82ca0a38c35924fe5756ac35311b Mon Sep 17 00:00:00 2001
From: Deepesh Garg
Date: Thu, 5 Aug 2021 22:38:24 +0530
Subject: [PATCH 255/386] test: Update test cases for discount accounting
---
.../purchase_invoice/test_purchase_invoice.py | 27 ++++++++++---------
.../sales_invoice/test_sales_invoice.py | 24 +++++++++--------
2 files changed, 28 insertions(+), 23 deletions(-)
diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
index d60f0a40b1..f0f5a58d15 100644
--- a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
@@ -235,39 +235,41 @@ class TestPurchaseInvoice(unittest.TestCase):
discount_account = create_account(account_name="Discount Account",
parent_account="Indirect Expenses - _TC", company="_Test Company")
- pi = make_purchase_invoice(discount_account=discount_account, discount_amount=100)
+ pi = make_purchase_invoice(discount_account=discount_account, rate=45)
expected_gle = [
- ["_Test Account Cost for Goods Sold - _TC", 350.0, 0.0, nowdate()],
- ["Creditors - _TC", 0.0, 250.0, nowdate()],
- ["Discount Account - _TC", 0.0, 100.0, nowdate()]
+ ["_Test Account Cost for Goods Sold - _TC", 250.0, 0.0, nowdate()],
+ ["Creditors - _TC", 0.0, 225.0, nowdate()],
+ ["Discount Account - _TC", 0.0, 25.0, nowdate()]
]
check_gl_entries(self, pi.name, expected_gle, nowdate())
+ enable_discount_accounting(enable=0)
def test_additional_discount_for_purchase_invoice_with_discount_accounting_enabled(self):
enable_discount_accounting()
additional_discount_account = create_account(account_name="Discount Account",
parent_account="Indirect Expenses - _TC", company="_Test Company")
- pi = make_purchase_invoice(qty=1, rate=100, do_not_save=1, parent_cost_center="Main - _TC")
+ pi = make_purchase_invoice(do_not_save=1, parent_cost_center="Main - _TC")
pi.apply_discount_on = "Grand Total"
pi.additional_discount_account = additional_discount_account
- pi.additional_discount_percentage = 20
+ pi.additional_discount_percentage = 10
+ pi.disable_rounded_total = 1
pi.append("taxes", {
- "charge_type": "Actual",
+ "charge_type": "On Net Total",
"account_head": "_Test Account VAT - _TC",
"cost_center": "Main - _TC",
"description": "Test",
- "tax_amount": 20
+ "rate": 10
})
pi.submit()
expected_gle = [
- ["_Test Account Cost for Goods Sold - _TC", 100.0, 0.0, nowdate()],
- ["_Test Account VAT - _TC", 20.0, 0.0, nowdate()],
- ["Creditors - _TC", 0.0, 96.0, nowdate()],
- ["Discount Account - _TC", 0.0, 24.0, nowdate()]
+ ["_Test Account Cost for Goods Sold - _TC", 250.0, 0.0, nowdate()],
+ ["_Test Account VAT - _TC", 25.0, 0.0, nowdate()],
+ ["Creditors - _TC", 0.0, 247.5, nowdate()],
+ ["Discount Account - _TC", 0.0, 27.5, nowdate()]
]
check_gl_entries(self, pi.name, expected_gle, nowdate())
@@ -1260,6 +1262,7 @@ def make_purchase_invoice(**args):
"received_qty": args.received_qty or 0,
"rejected_qty": args.rejected_qty or 0,
"rate": args.rate or 50,
+ "price_list_rate": args.price_list_rate or 50,
"expense_account": args.expense_account or '_Test Account Cost for Goods Sold - _TC',
"discount_account": args.discount_account or None,
"discount_amount": args.discount_amount or 0,
diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
index af317db712..12f03be288 100644
--- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
@@ -1993,15 +1993,16 @@ class TestSalesInvoice(unittest.TestCase):
discount_account = create_account(account_name="Discount Account",
parent_account="Indirect Expenses - _TC", company="_Test Company")
- si = create_sales_invoice(discount_account=discount_account, discount_amount=100)
+ si = create_sales_invoice(discount_account=discount_account, discount_percentage=10, rate=90)
expected_gle = [
- ["Debtors - _TC", 100.0, 0.0, nowdate()],
- ["Discount Account - _TC", 100.0, 0.0, nowdate()],
- ["Sales - _TC", 0.0, 200.0, nowdate()]
+ ["Debtors - _TC", 90.0, 0.0, nowdate()],
+ ["Discount Account - _TC", 10.0, 0.0, nowdate()],
+ ["Sales - _TC", 0.0, 100.0, nowdate()]
]
check_gl_entries(self, si.name, expected_gle, add_days(nowdate(), -1))
+ enable_discount_accounting(enable=0)
def test_additional_discount_for_sales_invoice_with_discount_accounting_enabled(self):
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import enable_discount_accounting
@@ -2010,28 +2011,28 @@ class TestSalesInvoice(unittest.TestCase):
additional_discount_account = create_account(account_name="Discount Account",
parent_account="Indirect Expenses - _TC", company="_Test Company")
- si = create_sales_invoice(rate=100, parent_cost_center='Main - _TC', do_not_save=1)
+ si = create_sales_invoice(parent_cost_center='Main - _TC', do_not_save=1)
si.apply_discount_on = "Grand Total"
si.additional_discount_account = additional_discount_account
si.additional_discount_percentage = 20
si.append("taxes", {
- "charge_type": "Actual",
+ "charge_type": "On Net Total",
"account_head": "_Test Account VAT - _TC",
"cost_center": "Main - _TC",
"description": "Test",
- "rate": 0,
- "tax_amount": 20
+ "rate": 10
})
si.submit()
expected_gle = [
- ["_Test Account VAT - _TC", 0.0, 20.0, nowdate()],
- ["Debtors - _TC", 96.0, 0.0, nowdate()],
- ["Discount Account - _TC", 24.0, 0.0, nowdate()],
+ ["_Test Account VAT - _TC", 0.0, 10.0, nowdate()],
+ ["Debtors - _TC", 88, 0.0, nowdate()],
+ ["Discount Account - _TC", 22.0, 0.0, nowdate()],
["Sales - _TC", 0.0, 100.0, nowdate()]
]
check_gl_entries(self, si.name, expected_gle, add_days(nowdate(), -1))
+ enable_discount_accounting(enable=0)
def get_sales_invoice_for_e_invoice():
si = make_sales_invoice_for_ewaybill()
@@ -2238,6 +2239,7 @@ def create_sales_invoice(**args):
"uom": args.uom or "Nos",
"stock_uom": args.uom or "Nos",
"rate": args.rate if args.get("rate") is not None else 100,
+ "price_list_rate": args.price_list_rate if args.get("price_list_rate") is not None else 100,
"income_account": args.income_account or "Sales - _TC",
"expense_account": args.expense_account or "Cost of Goods Sold - _TC",
"discount_account": args.discount_account or None,
From 797170e9138310da53ef33ecb2f8397f8b292882 Mon Sep 17 00:00:00 2001
From: Deepesh Garg
Date: Tue, 10 Aug 2021 11:02:21 +0530
Subject: [PATCH 256/386] fix: Linting issues
---
.../accounts/doctype/purchase_invoice/purchase_invoice.py | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
index d0f4e96541..d7d9a3886a 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
@@ -519,8 +519,6 @@ class PurchaseInvoice(BuyingController):
if d.category in ('Valuation', 'Total and Valuation')
and flt(d.base_tax_amount_after_discount_amount)]
- exchange_rate_map, net_rate_map = get_purchase_document_details(self)
-
enable_discount_accounting = cint(frappe.db.get_single_value('Accounts Settings', 'enable_discount_accounting'))
for item in self.get("items"):
@@ -841,8 +839,8 @@ class PurchaseInvoice(BuyingController):
"account": tax.account_head,
"against": self.supplier,
dr_or_cr: base_amount,
- dr_or_cr + "_in_account_currency": base_amount \
- if account_currency==self.company_currency \
+ dr_or_cr + "_in_account_currency": base_amount
+ if account_currency==self.company_currency
else amount,
"cost_center": tax.cost_center
}, account_currency, item=tax)
From 415519af15244b985a79d91691f7f2ba9a9b691c Mon Sep 17 00:00:00 2001
From: noahjacob
Date: Fri, 7 May 2021 13:00:46 +0530
Subject: [PATCH 257/386] feat: added multi-select fields to create multiple
pricing rules.
---
.../doctype/campaign_item/__init__.py | 0
.../doctype/campaign_item/campaign_item.json | 31 +
.../doctype/campaign_item/campaign_item.py | 10 +
.../doctype/customer_group_item/__init__.py | 0
.../customer_group_item.json | 31 +
.../customer_group_item.py | 10 +
.../doctype/customer_item/__init__.py | 0
.../doctype/customer_item/customer_item.json | 31 +
.../doctype/customer_item/customer_item.py | 10 +
.../promotional_scheme.json | 1226 ++---------------
.../promotional_scheme/promotional_scheme.py | 97 +-
.../doctype/sales_partner_item/__init__.py | 0
.../sales_partner_item.json | 31 +
.../sales_partner_item/sales_partner_item.py | 10 +
.../doctype/supplier_group_item/__init__.py | 0
.../supplier_group_item.json | 31 +
.../supplier_group_item.py | 10 +
.../doctype/supplier_item/__init__.py | 0
.../doctype/supplier_item/supplier_item.json | 31 +
.../doctype/supplier_item/supplier_item.py | 10 +
.../doctype/territory_item/__init__.py | 0
.../territory_item/territory_item.json | 31 +
.../doctype/territory_item/territory_item.py | 10 +
23 files changed, 443 insertions(+), 1167 deletions(-)
create mode 100644 erpnext/accounts/doctype/campaign_item/__init__.py
create mode 100644 erpnext/accounts/doctype/campaign_item/campaign_item.json
create mode 100644 erpnext/accounts/doctype/campaign_item/campaign_item.py
create mode 100644 erpnext/accounts/doctype/customer_group_item/__init__.py
create mode 100644 erpnext/accounts/doctype/customer_group_item/customer_group_item.json
create mode 100644 erpnext/accounts/doctype/customer_group_item/customer_group_item.py
create mode 100644 erpnext/accounts/doctype/customer_item/__init__.py
create mode 100644 erpnext/accounts/doctype/customer_item/customer_item.json
create mode 100644 erpnext/accounts/doctype/customer_item/customer_item.py
create mode 100644 erpnext/accounts/doctype/sales_partner_item/__init__.py
create mode 100644 erpnext/accounts/doctype/sales_partner_item/sales_partner_item.json
create mode 100644 erpnext/accounts/doctype/sales_partner_item/sales_partner_item.py
create mode 100644 erpnext/accounts/doctype/supplier_group_item/__init__.py
create mode 100644 erpnext/accounts/doctype/supplier_group_item/supplier_group_item.json
create mode 100644 erpnext/accounts/doctype/supplier_group_item/supplier_group_item.py
create mode 100644 erpnext/accounts/doctype/supplier_item/__init__.py
create mode 100644 erpnext/accounts/doctype/supplier_item/supplier_item.json
create mode 100644 erpnext/accounts/doctype/supplier_item/supplier_item.py
create mode 100644 erpnext/accounts/doctype/territory_item/__init__.py
create mode 100644 erpnext/accounts/doctype/territory_item/territory_item.json
create mode 100644 erpnext/accounts/doctype/territory_item/territory_item.py
diff --git a/erpnext/accounts/doctype/campaign_item/__init__.py b/erpnext/accounts/doctype/campaign_item/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/accounts/doctype/campaign_item/campaign_item.json b/erpnext/accounts/doctype/campaign_item/campaign_item.json
new file mode 100644
index 0000000000..69383a482b
--- /dev/null
+++ b/erpnext/accounts/doctype/campaign_item/campaign_item.json
@@ -0,0 +1,31 @@
+{
+ "actions": [],
+ "creation": "2021-05-06 16:18:25.410476",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "campaign"
+ ],
+ "fields": [
+ {
+ "fieldname": "campaign",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Campaign",
+ "options": "Campaign"
+ }
+ ],
+ "index_web_pages_for_search": 1,
+ "istable": 1,
+ "links": [],
+ "modified": "2021-05-07 10:43:49.717633",
+ "modified_by": "Administrator",
+ "module": "Accounts",
+ "name": "Campaign Item",
+ "owner": "Administrator",
+ "permissions": [],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/campaign_item/campaign_item.py b/erpnext/accounts/doctype/campaign_item/campaign_item.py
new file mode 100644
index 0000000000..e5ca7e5368
--- /dev/null
+++ b/erpnext/accounts/doctype/campaign_item/campaign_item.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+# import frappe
+from frappe.model.document import Document
+
+class CampaignItem(Document):
+ pass
diff --git a/erpnext/accounts/doctype/customer_group_item/__init__.py b/erpnext/accounts/doctype/customer_group_item/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/accounts/doctype/customer_group_item/customer_group_item.json b/erpnext/accounts/doctype/customer_group_item/customer_group_item.json
new file mode 100644
index 0000000000..bd1229d4e0
--- /dev/null
+++ b/erpnext/accounts/doctype/customer_group_item/customer_group_item.json
@@ -0,0 +1,31 @@
+{
+ "actions": [],
+ "creation": "2021-05-06 16:12:42.558878",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "customer_group"
+ ],
+ "fields": [
+ {
+ "fieldname": "customer_group",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Customer Group",
+ "options": "Customer Group"
+ }
+ ],
+ "index_web_pages_for_search": 1,
+ "istable": 1,
+ "links": [],
+ "modified": "2021-05-07 10:39:21.563506",
+ "modified_by": "Administrator",
+ "module": "Accounts",
+ "name": "Customer Group Item",
+ "owner": "Administrator",
+ "permissions": [],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/customer_group_item/customer_group_item.py b/erpnext/accounts/doctype/customer_group_item/customer_group_item.py
new file mode 100644
index 0000000000..ea24788ad5
--- /dev/null
+++ b/erpnext/accounts/doctype/customer_group_item/customer_group_item.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+# import frappe
+from frappe.model.document import Document
+
+class CustomerGroupItem(Document):
+ pass
diff --git a/erpnext/accounts/doctype/customer_item/__init__.py b/erpnext/accounts/doctype/customer_item/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/accounts/doctype/customer_item/customer_item.json b/erpnext/accounts/doctype/customer_item/customer_item.json
new file mode 100644
index 0000000000..f3dac02f94
--- /dev/null
+++ b/erpnext/accounts/doctype/customer_item/customer_item.json
@@ -0,0 +1,31 @@
+{
+ "actions": [],
+ "creation": "2021-05-05 14:04:54.266353",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "customer"
+ ],
+ "fields": [
+ {
+ "fieldname": "customer",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Customer ",
+ "options": "Customer"
+ }
+ ],
+ "index_web_pages_for_search": 1,
+ "istable": 1,
+ "links": [],
+ "modified": "2021-05-06 10:02:32.967841",
+ "modified_by": "Administrator",
+ "module": "Accounts",
+ "name": "Customer Item",
+ "owner": "Administrator",
+ "permissions": [],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/customer_item/customer_item.py b/erpnext/accounts/doctype/customer_item/customer_item.py
new file mode 100644
index 0000000000..4aad84ec14
--- /dev/null
+++ b/erpnext/accounts/doctype/customer_item/customer_item.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+# import frappe
+from frappe.model.document import Document
+
+class CustomerItem(Document):
+ pass
diff --git a/erpnext/accounts/doctype/promotional_scheme/promotional_scheme.json b/erpnext/accounts/doctype/promotional_scheme/promotional_scheme.json
index cc71324dbc..1d68b23d6c 100644
--- a/erpnext/accounts/doctype/promotional_scheme/promotional_scheme.json
+++ b/erpnext/accounts/doctype/promotional_scheme/promotional_scheme.json
@@ -1,1381 +1,339 @@
{
- "allow_copy": 0,
- "allow_events_in_timeline": 0,
- "allow_guest_to_view": 0,
+ "actions": [],
"allow_import": 1,
"allow_rename": 1,
"autoname": "Prompt",
- "beta": 0,
"creation": "2019-02-08 17:10:36.077402",
- "custom": 0,
- "docstatus": 0,
"doctype": "DocType",
- "document_type": "",
"editable_grid": 1,
"engine": "InnoDB",
+ "field_order": [
+ "section_break_1",
+ "apply_on",
+ "disable",
+ "column_break_3",
+ "items",
+ "item_groups",
+ "brands",
+ "mixed_conditions",
+ "is_cumulative",
+ "section_break_10",
+ "apply_rule_on_other",
+ "column_break_11",
+ "other_item_code",
+ "other_item_group",
+ "other_brand",
+ "section_break_8",
+ "selling",
+ "buying",
+ "column_break_12",
+ "applicable_for",
+ "customer",
+ "customer_group",
+ "territory",
+ "sales_partner",
+ "campaign",
+ "supplier",
+ "supplier_group",
+ "period_settings_section",
+ "valid_from",
+ "valid_upto",
+ "column_break_26",
+ "company",
+ "currency",
+ "section_break_14",
+ "price_discount_slabs",
+ "section_break_15",
+ "product_discount_slabs"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "section_break_1",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "",
- "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,
"default": "Item Code",
- "fetch_if_empty": 0,
"fieldname": "apply_on",
"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": "Apply On",
- "length": 0,
- "no_copy": 0,
"options": "\nItem Code\nItem Group\nBrand\nTransaction",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "reqd": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
+ "default": "0",
"fieldname": "disable",
"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": "Disable",
- "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": "Disable"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
- "fetch_if_empty": 0,
"fieldname": "column_break_3",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "fieldtype": "Column Break"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"depends_on": "eval:doc.apply_on == 'Item Code'",
- "fetch_if_empty": 0,
"fieldname": "items",
"fieldtype": "Table",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Pricing Rule Item Code",
- "length": 0,
- "no_copy": 0,
- "options": "Pricing Rule Item Code",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "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": "Pricing Rule Item Code"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"depends_on": "eval:doc.apply_on == 'Item Group'",
- "fetch_if_empty": 0,
"fieldname": "item_groups",
"fieldtype": "Table",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Pricing Rule Item Group",
- "length": 0,
- "no_copy": 0,
- "options": "Pricing Rule Item Group",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "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": "Pricing Rule Item Group"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"depends_on": "eval:doc.apply_on == 'Brand'",
- "fetch_if_empty": 0,
"fieldname": "brands",
"fieldtype": "Table",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Pricing Rule Brand",
- "length": 0,
- "no_copy": 0,
- "options": "Pricing Rule Brand",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "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": "Pricing Rule Brand"
},
{
- "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": "mixed_conditions",
"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": "Mixed Conditions",
- "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": "Mixed Conditions"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
+ "default": "0",
"fieldname": "is_cumulative",
"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 Cumulative",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "label": "Is Cumulative"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
"collapsible": 1,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "section_break_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,
- "label": "Discount on Other Item",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "label": "Discount on Other Item"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
- "fetch_if_empty": 0,
"fieldname": "apply_rule_on_other",
"fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Apply Rule On Other",
- "length": 0,
- "no_copy": 0,
- "options": "\nItem Code\nItem Group\nBrand",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "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": "\nItem Code\nItem Group\nBrand"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
- "fetch_if_empty": 0,
"fieldname": "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
+ "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.apply_rule_on_other == 'Item Code'",
- "fetch_if_empty": 0,
"fieldname": "other_item_code",
"fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Item Code",
- "length": 0,
- "no_copy": 0,
- "options": "Item",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "options": "Item"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"depends_on": "eval:doc.apply_rule_on_other == 'Item Group'",
- "fetch_if_empty": 0,
"fieldname": "other_item_group",
"fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Item Group",
- "length": 0,
- "no_copy": 0,
- "options": "Item Group",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "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,
"depends_on": "eval:doc.apply_rule_on_other == 'Brand'",
- "fetch_if_empty": 0,
"fieldname": "other_brand",
"fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Brand",
- "length": 0,
- "no_copy": 0,
- "options": "Brand",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "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": "Brand"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
"collapsible": 1,
- "columns": 0,
- "depends_on": "",
- "fetch_if_empty": 0,
"fieldname": "section_break_8",
"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 Information",
- "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": "Party Information"
},
{
- "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": "selling",
"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": "Selling",
- "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": "Selling"
},
{
- "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": "buying",
"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": "Buying",
- "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": "Buying"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
- "fetch_if_empty": 0,
"fieldname": "column_break_12",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "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.buying || doc.selling",
- "fetch_if_empty": 0,
"fieldname": "applicable_for",
"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": "Applicable For",
- "length": 0,
- "no_copy": 0,
- "options": "\nCustomer\nCustomer Group\nTerritory\nSales Partner\nCampaign\nSupplier\nSupplier Group",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "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": "\nCustomer\nCustomer Group\nTerritory\nSales Partner\nCampaign\nSupplier\nSupplier Group"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"depends_on": "eval:doc.applicable_for=='Customer'",
- "fetch_if_empty": 0,
"fieldname": "customer",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
+ "fieldtype": "Table MultiSelect",
"label": "Customer",
- "length": 0,
- "no_copy": 0,
- "options": "Customer",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "options": "Customer Item"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"depends_on": "eval:doc.applicable_for==\"Customer Group\"",
- "fetch_if_empty": 0,
"fieldname": "customer_group",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
+ "fieldtype": "Table MultiSelect",
"label": "Customer Group",
- "length": 0,
- "no_copy": 0,
- "options": "Customer Group",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "options": "Customer Group Item"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"depends_on": "eval:doc.applicable_for==\"Territory\"",
- "fetch_if_empty": 0,
"fieldname": "territory",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
+ "fieldtype": "Table MultiSelect",
"label": "Territory",
- "length": 0,
- "no_copy": 0,
- "options": "Territory",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "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": "Territory Item"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"depends_on": "eval:doc.applicable_for==\"Sales Partner\"",
- "fetch_if_empty": 0,
"fieldname": "sales_partner",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
+ "fieldtype": "Table MultiSelect",
"label": "Sales Partner",
- "length": 0,
- "no_copy": 0,
- "options": "Sales Partner",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "options": "Sales Partner Item"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"depends_on": "eval:doc.applicable_for==\"Campaign\"",
- "fetch_if_empty": 0,
"fieldname": "campaign",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
+ "fieldtype": "Table MultiSelect",
"label": "Campaign",
- "length": 0,
- "no_copy": 0,
- "options": "Campaign",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "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": "Campaign Item"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"depends_on": "eval:doc.applicable_for=='Supplier'",
- "fetch_if_empty": 0,
"fieldname": "supplier",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
+ "fieldtype": "Table MultiSelect",
"label": "Supplier",
- "length": 0,
- "no_copy": 0,
- "options": "Supplier",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "options": "Supplier Item"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"depends_on": "eval:doc.applicable_for==\"Supplier Group\"",
- "fetch_if_empty": 0,
"fieldname": "supplier_group",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
+ "fieldtype": "Table MultiSelect",
"label": "Supplier Group",
- "length": 0,
- "no_copy": 0,
- "options": "Supplier Group",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "options": "Supplier Group Item"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "period_settings_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": "Period Settings",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "label": "Period Settings"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"default": "Today",
- "fetch_if_empty": 0,
"fieldname": "valid_from",
"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": "Valid From",
- "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": "Valid From"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "valid_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": "Valid Upto",
- "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": "Valid 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": "column_break_26",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "fieldtype": "Column Break"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "company",
"fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
"in_list_view": 1,
- "in_standard_filter": 0,
"label": "Company",
- "length": 0,
- "no_copy": 0,
"options": "Company",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "reqd": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "currency",
"fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Currency",
- "length": 0,
- "no_copy": 0,
- "options": "Currency",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "options": "Currency"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
- "fetch_if_empty": 0,
"fieldname": "section_break_14",
"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": "Price Discount Slabs",
- "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": "Price Discount Slabs"
},
{
"allow_bulk_edit": 1,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "price_discount_slabs",
"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": "Promotional Scheme Price Discount",
- "length": 0,
- "no_copy": 0,
- "options": "Promotional Scheme Price Discount",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "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": "Promotional Scheme Price Discount"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
- "fetch_if_empty": 0,
"fieldname": "section_break_15",
"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": "Product Discount Slabs",
- "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": "Product Discount Slabs"
},
{
"allow_bulk_edit": 1,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "product_discount_slabs",
"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": "Promotional Scheme Product Discount",
- "length": 0,
- "no_copy": 0,
- "options": "Promotional Scheme Product Discount",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "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": "Promotional Scheme Product Discount"
}
],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2019-03-25 12:14:27.486586",
+ "links": [],
+ "modified": "2021-05-06 16:20:22.039078",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Promotional Scheme",
- "name_case": "",
"owner": "Administrator",
"permissions": [
{
- "amend": 0,
- "cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
- "set_user_permissions": 0,
"share": 1,
- "submit": 0,
"write": 1
},
{
- "amend": 0,
- "cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts Manager",
- "set_user_permissions": 0,
"share": 1,
- "submit": 0,
"write": 1
},
{
- "amend": 0,
- "cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Sales Manager",
- "set_user_permissions": 0,
"share": 1,
- "submit": 0,
"write": 1
},
{
- "amend": 0,
- "cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts User",
- "set_user_permissions": 0,
"share": 1,
- "submit": 0,
"write": 1
}
],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
- "track_changes": 1,
- "track_seen": 0,
- "track_views": 0
+ "track_changes": 1
}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/promotional_scheme/promotional_scheme.py b/erpnext/accounts/doctype/promotional_scheme/promotional_scheme.py
index 7d9302382f..ec42eda63a 100644
--- a/erpnext/accounts/doctype/promotional_scheme/promotional_scheme.py
+++ b/erpnext/accounts/doctype/promotional_scheme/promotional_scheme.py
@@ -30,17 +30,17 @@ class PromotionalScheme(Document):
frappe.throw(_("Price or product discount slabs are required"))
def on_update(self):
- data = frappe.get_all('Pricing Rule', fields = ["promotional_scheme_id", "name"],
- filters = {'promotional_scheme': self.name}) or {}
-
+ data = frappe.get_all('Pricing Rule', fields = ["promotional_scheme_id", "name", "creation"], order_by = 'creation asc',
+ filters = {'promotional_scheme': self.name, 'applicable_for': self.applicable_for}) or {}
self.update_pricing_rules(data)
def update_pricing_rules(self, data):
rules = {}
count = 0
-
+ names = []
for d in data:
- rules[d.get('promotional_scheme_id')] = d.get('name')
+ names.append(d.name)
+ rules[d.get('promotional_scheme_id')] = names
docs = get_pricing_rules(self, rules)
@@ -73,42 +73,73 @@ def get_pricing_rules(doc, rules = {}):
def _get_pricing_rules(doc, child_doc, discount_fields, rules = {}):
new_doc = []
args = get_args_for_pricing_rule(doc)
+ applicable_for = frappe.scrub(doc.get('applicable_for'))
for d in doc.get(child_doc):
if d.name in rules:
- pr = frappe.get_doc('Pricing Rule', rules.get(d.name))
+ for a in args.get(applicable_for):
+
+ temp_args = args.copy()
+ docname = frappe.get_all('Pricing Rule', fields = ["promotional_scheme_id", "name", applicable_for],
+ filters = {'promotional_scheme_id': d.name, applicable_for: a})
+
+ if docname:
+ pr = frappe.get_doc('Pricing Rule', docname[0].get('name'))
+ temp_args[applicable_for] = a
+ pr = set_args(temp_args,pr,doc,child_doc,discount_fields,d)
+ else:
+ pr = frappe.new_doc("Pricing Rule")
+ pr.title = make_autoname("{0}/.####".format(doc.name))
+ temp_args[applicable_for] = a
+ pr = set_args(temp_args,pr,doc,child_doc,discount_fields,d)
+
+ new_doc.append(pr)
+
else:
- pr = frappe.new_doc("Pricing Rule")
- pr.title = make_autoname("{0}/.####".format(doc.name))
+ for i in range(len(args.get(applicable_for))) :
- pr.update(args)
- for field in (other_fields + discount_fields):
- pr.set(field, d.get(field))
-
- pr.promotional_scheme_id = d.name
- pr.promotional_scheme = doc.name
- pr.disable = d.disable if d.disable else doc.disable
- pr.price_or_product_discount = ('Price'
- if child_doc == 'price_discount_slabs' else 'Product')
-
- for field in ['items', 'item_groups', 'brands']:
- if doc.get(field):
- pr.set(field, [])
-
- apply_on = frappe.scrub(doc.get('apply_on'))
- for d in doc.get(field):
- pr.append(field, {
- apply_on: d.get(apply_on),
- 'uom': d.uom
- })
-
- new_doc.append(pr)
+ pr = frappe.new_doc("Pricing Rule")
+ pr.title = make_autoname("{0}/.####".format(doc.name))
+ temp_args = args.copy()
+ temp_args[applicable_for] = args[applicable_for][i]
+ pr = set_args(temp_args,pr,doc,child_doc,discount_fields,d)
+ new_doc.append(pr)
return new_doc
+def set_args(args,pr,doc,child_doc,discount_fields,d):
+ pr.update(args)
+ for field in (other_fields + discount_fields):
+ pr.set(field, d.get(field))
+
+ pr.promotional_scheme_id = d.name
+ pr.promotional_scheme = doc.name
+ pr.disable = d.disable if d.disable else doc.disable
+ pr.price_or_product_discount = ('Price'
+ if child_doc == 'price_discount_slabs' else 'Product')
+
+ for field in ['items', 'item_groups', 'brands']:
+ if doc.get(field):
+ pr.set(field, [])
+
+ apply_on = frappe.scrub(doc.get('apply_on'))
+ for d in doc.get(field):
+ pr.append(field, {
+ apply_on: d.get(apply_on),
+ 'uom': d.uom
+ })
+ return pr
+
def get_args_for_pricing_rule(doc):
args = { 'promotional_scheme': doc.name }
-
+ applicable_for = frappe.scrub(doc.get('applicable_for'))
+
for d in pricing_rule_fields:
- args[d] = doc.get(d)
-
+ if d == applicable_for:
+ items = []
+ for i in doc.get(applicable_for):
+ items.append(i.get(applicable_for))
+ args[d] = items
+
+ else:
+ args[d] = doc.get(d)
return args
diff --git a/erpnext/accounts/doctype/sales_partner_item/__init__.py b/erpnext/accounts/doctype/sales_partner_item/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/accounts/doctype/sales_partner_item/sales_partner_item.json b/erpnext/accounts/doctype/sales_partner_item/sales_partner_item.json
new file mode 100644
index 0000000000..c176e4d173
--- /dev/null
+++ b/erpnext/accounts/doctype/sales_partner_item/sales_partner_item.json
@@ -0,0 +1,31 @@
+{
+ "actions": [],
+ "creation": "2021-05-06 16:17:44.329943",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "sales_partner"
+ ],
+ "fields": [
+ {
+ "fieldname": "sales_partner",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Sales Partner ",
+ "options": "Sales Partner"
+ }
+ ],
+ "index_web_pages_for_search": 1,
+ "istable": 1,
+ "links": [],
+ "modified": "2021-05-07 10:43:37.532095",
+ "modified_by": "Administrator",
+ "module": "Accounts",
+ "name": "Sales Partner Item",
+ "owner": "Administrator",
+ "permissions": [],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/sales_partner_item/sales_partner_item.py b/erpnext/accounts/doctype/sales_partner_item/sales_partner_item.py
new file mode 100644
index 0000000000..9e6564845b
--- /dev/null
+++ b/erpnext/accounts/doctype/sales_partner_item/sales_partner_item.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+# import frappe
+from frappe.model.document import Document
+
+class SalesPartnerItem(Document):
+ pass
diff --git a/erpnext/accounts/doctype/supplier_group_item/__init__.py b/erpnext/accounts/doctype/supplier_group_item/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/accounts/doctype/supplier_group_item/supplier_group_item.json b/erpnext/accounts/doctype/supplier_group_item/supplier_group_item.json
new file mode 100644
index 0000000000..67fac45845
--- /dev/null
+++ b/erpnext/accounts/doctype/supplier_group_item/supplier_group_item.json
@@ -0,0 +1,31 @@
+{
+ "actions": [],
+ "creation": "2021-05-06 16:19:22.040795",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "supplier_group"
+ ],
+ "fields": [
+ {
+ "fieldname": "supplier_group",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Supplier Group",
+ "options": "Supplier Group"
+ }
+ ],
+ "index_web_pages_for_search": 1,
+ "istable": 1,
+ "links": [],
+ "modified": "2021-05-07 10:43:59.877938",
+ "modified_by": "Administrator",
+ "module": "Accounts",
+ "name": "Supplier Group Item",
+ "owner": "Administrator",
+ "permissions": [],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/supplier_group_item/supplier_group_item.py b/erpnext/accounts/doctype/supplier_group_item/supplier_group_item.py
new file mode 100644
index 0000000000..5ea2635482
--- /dev/null
+++ b/erpnext/accounts/doctype/supplier_group_item/supplier_group_item.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+# import frappe
+from frappe.model.document import Document
+
+class SupplierGroupItem(Document):
+ pass
diff --git a/erpnext/accounts/doctype/supplier_item/__init__.py b/erpnext/accounts/doctype/supplier_item/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/accounts/doctype/supplier_item/supplier_item.json b/erpnext/accounts/doctype/supplier_item/supplier_item.json
new file mode 100644
index 0000000000..95c4dc6db3
--- /dev/null
+++ b/erpnext/accounts/doctype/supplier_item/supplier_item.json
@@ -0,0 +1,31 @@
+{
+ "actions": [],
+ "creation": "2021-05-06 16:18:54.758468",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "supplier"
+ ],
+ "fields": [
+ {
+ "fieldname": "supplier",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Supplier",
+ "options": "Supplier"
+ }
+ ],
+ "index_web_pages_for_search": 1,
+ "istable": 1,
+ "links": [],
+ "modified": "2021-05-07 10:44:09.707778",
+ "modified_by": "Administrator",
+ "module": "Accounts",
+ "name": "Supplier Item",
+ "owner": "Administrator",
+ "permissions": [],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/supplier_item/supplier_item.py b/erpnext/accounts/doctype/supplier_item/supplier_item.py
new file mode 100644
index 0000000000..b58b5dc057
--- /dev/null
+++ b/erpnext/accounts/doctype/supplier_item/supplier_item.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+# import frappe
+from frappe.model.document import Document
+
+class SupplierItem(Document):
+ pass
diff --git a/erpnext/accounts/doctype/territory_item/__init__.py b/erpnext/accounts/doctype/territory_item/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/accounts/doctype/territory_item/territory_item.json b/erpnext/accounts/doctype/territory_item/territory_item.json
new file mode 100644
index 0000000000..0f0fdea8c0
--- /dev/null
+++ b/erpnext/accounts/doctype/territory_item/territory_item.json
@@ -0,0 +1,31 @@
+{
+ "actions": [],
+ "creation": "2021-05-06 16:16:51.885441",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "territory"
+ ],
+ "fields": [
+ {
+ "fieldname": "territory",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Territory",
+ "options": "Territory"
+ }
+ ],
+ "index_web_pages_for_search": 1,
+ "istable": 1,
+ "links": [],
+ "modified": "2021-05-07 10:43:26.641030",
+ "modified_by": "Administrator",
+ "module": "Accounts",
+ "name": "Territory Item",
+ "owner": "Administrator",
+ "permissions": [],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/territory_item/territory_item.py b/erpnext/accounts/doctype/territory_item/territory_item.py
new file mode 100644
index 0000000000..9adfc00572
--- /dev/null
+++ b/erpnext/accounts/doctype/territory_item/territory_item.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+# import frappe
+from frappe.model.document import Document
+
+class TerritoryItem(Document):
+ pass
From a9ef56a1077fcefd224b8382f892085f99eb2b5e Mon Sep 17 00:00:00 2001
From: noahjacob
Date: Fri, 7 May 2021 16:03:59 +0530
Subject: [PATCH 258/386] test: added test case for creating and updating
---
.../test_promotional_scheme.py | 57 ++++++++++++++++++-
1 file changed, 56 insertions(+), 1 deletion(-)
diff --git a/erpnext/accounts/doctype/promotional_scheme/test_promotional_scheme.py b/erpnext/accounts/doctype/promotional_scheme/test_promotional_scheme.py
index 8dc0499779..9c756258db 100644
--- a/erpnext/accounts/doctype/promotional_scheme/test_promotional_scheme.py
+++ b/erpnext/accounts/doctype/promotional_scheme/test_promotional_scheme.py
@@ -7,4 +7,59 @@ import frappe
import unittest
class TestPromotionalScheme(unittest.TestCase):
- pass
+ def test_promotional_scheme(self):
+ ps = make_promotional_scheme()
+ price_rules = frappe.get_all('Pricing Rule', fields = ["promotional_scheme_id", "name", "creation"],
+ filters = {'promotional_scheme': ps.name})
+ self.assertTrue(len(price_rules),1)
+ price_doc_details = frappe.db.get_value('Pricing Rule',price_rules[0].name,['customer','min_qty','discount_percentage'],as_dict = 1)
+ self.assertTrue(price_doc_details.customer,'_Test Customer')
+ self.assertTrue(price_doc_details.min_qty,4)
+ self.assertTrue(price_doc_details.discount_percentage,20)
+
+ ps.price_discount_slabs[0].min_qty = 6
+ ps.append('customer',{
+ 'customer': "_Test Customer 2"
+ })
+ ps.save()
+ price_rules = frappe.get_all('Pricing Rule', fields = ["promotional_scheme_id", "name"],
+ filters = {'promotional_scheme': ps.name})
+ self.assertTrue(len(price_rules),2)
+
+ price_doc_details = frappe.db.get_value('Pricing Rule',price_rules[1].name,['customer','min_qty','discount_percentage'],as_dict = 1)
+ self.assertTrue(price_doc_details.customer,'_Test Customer 2')
+ self.assertTrue(price_doc_details.min_qty,6)
+ self.assertTrue(price_doc_details.discount_percentage,20)
+
+ price_doc_details = frappe.db.get_value('Pricing Rule',price_rules[0].name,['customer','min_qty','discount_percentage'],as_dict = 1)
+ self.assertTrue(price_doc_details.customer,'_Test Customer')
+ self.assertTrue(price_doc_details.min_qty,6)
+
+ frappe.delete_doc('Promotional Scheme',ps.name)
+ price_rules = frappe.get_all('Pricing Rule', fields = ["promotional_scheme_id", "name"],
+ filters = {'promotional_scheme': ps.name})
+ self.assertEqual(price_rules,[])
+
+
+
+
+
+def make_promotional_scheme():
+ ps = frappe.new_doc('Promotional Scheme')
+ ps.name = '_Test Scheme'
+ ps.append('items',{
+ 'item_code': 'Test Production Item 1'
+ })
+ ps.selling = 1
+ ps.append('price_discount_slabs',{
+ 'min_qty': 4,
+ 'discount_percentage': 20,
+ 'rule_description': 'Test'
+ })
+ ps.applicable_for = 'Customer'
+ ps.append('customer',{
+ 'customer': "_Test Customer"
+ })
+ ps.save()
+
+ return ps
\ No newline at end of file
From c95d96e7ae7bd0a283e29d09346e590abb489640 Mon Sep 17 00:00:00 2001
From: noahjacob
Date: Fri, 7 May 2021 16:17:00 +0530
Subject: [PATCH 259/386] refactor: changed variable names
---
.../doctype/promotional_scheme/promotional_scheme.py | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/erpnext/accounts/doctype/promotional_scheme/promotional_scheme.py b/erpnext/accounts/doctype/promotional_scheme/promotional_scheme.py
index ec42eda63a..ff3f9c5638 100644
--- a/erpnext/accounts/doctype/promotional_scheme/promotional_scheme.py
+++ b/erpnext/accounts/doctype/promotional_scheme/promotional_scheme.py
@@ -76,20 +76,20 @@ def _get_pricing_rules(doc, child_doc, discount_fields, rules = {}):
applicable_for = frappe.scrub(doc.get('applicable_for'))
for d in doc.get(child_doc):
if d.name in rules:
- for a in args.get(applicable_for):
+ for applicable_for_value in args.get(applicable_for):
temp_args = args.copy()
docname = frappe.get_all('Pricing Rule', fields = ["promotional_scheme_id", "name", applicable_for],
- filters = {'promotional_scheme_id': d.name, applicable_for: a})
+ filters = {'promotional_scheme_id': d.name, applicable_for: applicable_for_value})
if docname:
pr = frappe.get_doc('Pricing Rule', docname[0].get('name'))
- temp_args[applicable_for] = a
+ temp_args[applicable_for] = applicable_for_value
pr = set_args(temp_args,pr,doc,child_doc,discount_fields,d)
else:
pr = frappe.new_doc("Pricing Rule")
pr.title = make_autoname("{0}/.####".format(doc.name))
- temp_args[applicable_for] = a
+ temp_args[applicable_for] = applicable_for_value
pr = set_args(temp_args,pr,doc,child_doc,discount_fields,d)
new_doc.append(pr)
@@ -136,8 +136,8 @@ def get_args_for_pricing_rule(doc):
for d in pricing_rule_fields:
if d == applicable_for:
items = []
- for i in doc.get(applicable_for):
- items.append(i.get(applicable_for))
+ for applicable_for_values in doc.get(applicable_for):
+ items.append(applicable_for_values.get(applicable_for))
args[d] = items
else:
From 3a663ac77fc89fd7e95f8fe7b1fee4ad044dac93 Mon Sep 17 00:00:00 2001
From: noahjacob
Date: Fri, 7 May 2021 17:39:26 +0530
Subject: [PATCH 260/386] test: changed test item name
---
.../doctype/promotional_scheme/test_promotional_scheme.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/accounts/doctype/promotional_scheme/test_promotional_scheme.py b/erpnext/accounts/doctype/promotional_scheme/test_promotional_scheme.py
index 9c756258db..940b76a9ad 100644
--- a/erpnext/accounts/doctype/promotional_scheme/test_promotional_scheme.py
+++ b/erpnext/accounts/doctype/promotional_scheme/test_promotional_scheme.py
@@ -48,7 +48,7 @@ def make_promotional_scheme():
ps = frappe.new_doc('Promotional Scheme')
ps.name = '_Test Scheme'
ps.append('items',{
- 'item_code': 'Test Production Item 1'
+ 'item_code': '_Test Item'
})
ps.selling = 1
ps.append('price_discount_slabs',{
From a4cea1e56d68dbb4139324629bba1730508b33a3 Mon Sep 17 00:00:00 2001
From: noahjacob
Date: Wed, 12 May 2021 16:50:41 +0530
Subject: [PATCH 261/386] refactor: variable names
---
.../doctype/promotional_scheme/promotional_scheme.py | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/erpnext/accounts/doctype/promotional_scheme/promotional_scheme.py b/erpnext/accounts/doctype/promotional_scheme/promotional_scheme.py
index ff3f9c5638..69ed94676d 100644
--- a/erpnext/accounts/doctype/promotional_scheme/promotional_scheme.py
+++ b/erpnext/accounts/doctype/promotional_scheme/promotional_scheme.py
@@ -106,14 +106,14 @@ def _get_pricing_rules(doc, child_doc, discount_fields, rules = {}):
return new_doc
-def set_args(args,pr,doc,child_doc,discount_fields,d):
+def set_args(args, pr, doc, child_doc, discount_fields, child_doc_fields):
pr.update(args)
for field in (other_fields + discount_fields):
- pr.set(field, d.get(field))
+ pr.set(field, child_doc_fields.get(field))
- pr.promotional_scheme_id = d.name
+ pr.promotional_scheme_id = child_doc_fields.name
pr.promotional_scheme = doc.name
- pr.disable = d.disable if d.disable else doc.disable
+ pr.disable = child_doc_fields.disable if child_doc_fields.disable else doc.disable
pr.price_or_product_discount = ('Price'
if child_doc == 'price_discount_slabs' else 'Product')
From 4fb1b6b80cb9ebeb249137eb7b24410547c745f9 Mon Sep 17 00:00:00 2001
From: noahjacob
Date: Wed, 12 May 2021 16:51:02 +0530
Subject: [PATCH 262/386] fix: Sider
---
.../promotional_scheme/test_promotional_scheme.py | 9 ++-------
1 file changed, 2 insertions(+), 7 deletions(-)
diff --git a/erpnext/accounts/doctype/promotional_scheme/test_promotional_scheme.py b/erpnext/accounts/doctype/promotional_scheme/test_promotional_scheme.py
index 940b76a9ad..99f9ed47e4 100644
--- a/erpnext/accounts/doctype/promotional_scheme/test_promotional_scheme.py
+++ b/erpnext/accounts/doctype/promotional_scheme/test_promotional_scheme.py
@@ -18,9 +18,8 @@ class TestPromotionalScheme(unittest.TestCase):
self.assertTrue(price_doc_details.discount_percentage,20)
ps.price_discount_slabs[0].min_qty = 6
- ps.append('customer',{
- 'customer': "_Test Customer 2"
- })
+ ps.append('customer', {
+ 'customer': "_Test Customer 2"})
ps.save()
price_rules = frappe.get_all('Pricing Rule', fields = ["promotional_scheme_id", "name"],
filters = {'promotional_scheme': ps.name})
@@ -39,11 +38,7 @@ class TestPromotionalScheme(unittest.TestCase):
price_rules = frappe.get_all('Pricing Rule', fields = ["promotional_scheme_id", "name"],
filters = {'promotional_scheme': ps.name})
self.assertEqual(price_rules,[])
-
-
-
-
def make_promotional_scheme():
ps = frappe.new_doc('Promotional Scheme')
ps.name = '_Test Scheme'
From 74bcb987f30dad26d66dd94caa6a3ca66eb00311 Mon Sep 17 00:00:00 2001
From: noahjacob
Date: Tue, 18 May 2021 14:52:50 +0530
Subject: [PATCH 263/386] style: fixed formatting
---
.../promotional_scheme/promotional_scheme.py | 6 ++--
.../test_promotional_scheme.py | 28 +++++++++----------
2 files changed, 17 insertions(+), 17 deletions(-)
diff --git a/erpnext/accounts/doctype/promotional_scheme/promotional_scheme.py b/erpnext/accounts/doctype/promotional_scheme/promotional_scheme.py
index 69ed94676d..2b7f156638 100644
--- a/erpnext/accounts/doctype/promotional_scheme/promotional_scheme.py
+++ b/erpnext/accounts/doctype/promotional_scheme/promotional_scheme.py
@@ -85,12 +85,12 @@ def _get_pricing_rules(doc, child_doc, discount_fields, rules = {}):
if docname:
pr = frappe.get_doc('Pricing Rule', docname[0].get('name'))
temp_args[applicable_for] = applicable_for_value
- pr = set_args(temp_args,pr,doc,child_doc,discount_fields,d)
+ pr = set_args(temp_args, pr, doc, child_doc, discount_fields, d)
else:
pr = frappe.new_doc("Pricing Rule")
pr.title = make_autoname("{0}/.####".format(doc.name))
temp_args[applicable_for] = applicable_for_value
- pr = set_args(temp_args,pr,doc,child_doc,discount_fields,d)
+ pr = set_args(temp_args, pr, doc, child_doc, discount_fields, d)
new_doc.append(pr)
@@ -101,7 +101,7 @@ def _get_pricing_rules(doc, child_doc, discount_fields, rules = {}):
pr.title = make_autoname("{0}/.####".format(doc.name))
temp_args = args.copy()
temp_args[applicable_for] = args[applicable_for][i]
- pr = set_args(temp_args,pr,doc,child_doc,discount_fields,d)
+ pr = set_args(temp_args, pr, doc, child_doc, discount_fields, d)
new_doc.append(pr)
return new_doc
diff --git a/erpnext/accounts/doctype/promotional_scheme/test_promotional_scheme.py b/erpnext/accounts/doctype/promotional_scheme/test_promotional_scheme.py
index 99f9ed47e4..7354ef036c 100644
--- a/erpnext/accounts/doctype/promotional_scheme/test_promotional_scheme.py
+++ b/erpnext/accounts/doctype/promotional_scheme/test_promotional_scheme.py
@@ -12,10 +12,10 @@ class TestPromotionalScheme(unittest.TestCase):
price_rules = frappe.get_all('Pricing Rule', fields = ["promotional_scheme_id", "name", "creation"],
filters = {'promotional_scheme': ps.name})
self.assertTrue(len(price_rules),1)
- price_doc_details = frappe.db.get_value('Pricing Rule',price_rules[0].name,['customer','min_qty','discount_percentage'],as_dict = 1)
- self.assertTrue(price_doc_details.customer,'_Test Customer')
- self.assertTrue(price_doc_details.min_qty,4)
- self.assertTrue(price_doc_details.discount_percentage,20)
+ price_doc_details = frappe.db.get_value('Pricing Rule', price_rules[0].name, ['customer', 'min_qty', 'discount_percentage'], as_dict = 1)
+ self.assertTrue(price_doc_details.customer, '_Test Customer')
+ self.assertTrue(price_doc_details.min_qty, 4)
+ self.assertTrue(price_doc_details.discount_percentage, 20)
ps.price_discount_slabs[0].min_qty = 6
ps.append('customer', {
@@ -23,21 +23,21 @@ class TestPromotionalScheme(unittest.TestCase):
ps.save()
price_rules = frappe.get_all('Pricing Rule', fields = ["promotional_scheme_id", "name"],
filters = {'promotional_scheme': ps.name})
- self.assertTrue(len(price_rules),2)
+ self.assertTrue(len(price_rules), 2)
- price_doc_details = frappe.db.get_value('Pricing Rule',price_rules[1].name,['customer','min_qty','discount_percentage'],as_dict = 1)
- self.assertTrue(price_doc_details.customer,'_Test Customer 2')
- self.assertTrue(price_doc_details.min_qty,6)
- self.assertTrue(price_doc_details.discount_percentage,20)
+ price_doc_details = frappe.db.get_value('Pricing Rule', price_rules[1].name, ['customer', 'min_qty', 'discount_percentage'], as_dict = 1)
+ self.assertTrue(price_doc_details.customer, '_Test Customer 2')
+ self.assertTrue(price_doc_details.min_qty, 6)
+ self.assertTrue(price_doc_details.discount_percentage, 20)
- price_doc_details = frappe.db.get_value('Pricing Rule',price_rules[0].name,['customer','min_qty','discount_percentage'],as_dict = 1)
- self.assertTrue(price_doc_details.customer,'_Test Customer')
- self.assertTrue(price_doc_details.min_qty,6)
+ price_doc_details = frappe.db.get_value('Pricing Rule', price_rules[0].name, ['customer', 'min_qty', 'discount_percentage'], as_dict = 1)
+ self.assertTrue(price_doc_details.customer, '_Test Customer')
+ self.assertTrue(price_doc_details.min_qty, 6)
- frappe.delete_doc('Promotional Scheme',ps.name)
+ frappe.delete_doc('Promotional Scheme', ps.name)
price_rules = frappe.get_all('Pricing Rule', fields = ["promotional_scheme_id", "name"],
filters = {'promotional_scheme': ps.name})
- self.assertEqual(price_rules,[])
+ self.assertEqual(price_rules, [])
def make_promotional_scheme():
ps = frappe.new_doc('Promotional Scheme')
From b214e624bb8dde5fb0713fa4920306d97ea2f178 Mon Sep 17 00:00:00 2001
From: noahjacob
Date: Wed, 19 May 2021 16:18:37 +0530
Subject: [PATCH 264/386] style: fixed formatting
---
.../promotional_scheme/promotional_scheme.py | 23 ++++++++++++++-----
1 file changed, 17 insertions(+), 6 deletions(-)
diff --git a/erpnext/accounts/doctype/promotional_scheme/promotional_scheme.py b/erpnext/accounts/doctype/promotional_scheme/promotional_scheme.py
index 2b7f156638..53239feb42 100644
--- a/erpnext/accounts/doctype/promotional_scheme/promotional_scheme.py
+++ b/erpnext/accounts/doctype/promotional_scheme/promotional_scheme.py
@@ -30,8 +30,15 @@ class PromotionalScheme(Document):
frappe.throw(_("Price or product discount slabs are required"))
def on_update(self):
- data = frappe.get_all('Pricing Rule', fields = ["promotional_scheme_id", "name", "creation"], order_by = 'creation asc',
- filters = {'promotional_scheme': self.name, 'applicable_for': self.applicable_for}) or {}
+ data = frappe.get_all(
+ 'Pricing Rule',
+ fields = ["promotional_scheme_id", "name", "creation"],
+ filters = {
+ 'promotional_scheme': self.name,
+ 'applicable_for': self.applicable_for
+ },
+ order_by = 'creation asc',
+ ) or {}
self.update_pricing_rules(data)
def update_pricing_rules(self, data):
@@ -77,10 +84,15 @@ def _get_pricing_rules(doc, child_doc, discount_fields, rules = {}):
for d in doc.get(child_doc):
if d.name in rules:
for applicable_for_value in args.get(applicable_for):
-
temp_args = args.copy()
- docname = frappe.get_all('Pricing Rule', fields = ["promotional_scheme_id", "name", applicable_for],
- filters = {'promotional_scheme_id': d.name, applicable_for: applicable_for_value})
+ docname = frappe.get_all(
+ 'Pricing Rule',
+ fields = ["promotional_scheme_id", "name", applicable_for],
+ filters = {
+ 'promotional_scheme_id': d.name,
+ applicable_for: applicable_for_value
+ }
+ )
if docname:
pr = frappe.get_doc('Pricing Rule', docname[0].get('name'))
@@ -139,7 +151,6 @@ def get_args_for_pricing_rule(doc):
for applicable_for_values in doc.get(applicable_for):
items.append(applicable_for_values.get(applicable_for))
args[d] = items
-
else:
args[d] = doc.get(d)
return args
From dd86642037cfff7efb52aadab57a6454175e5b67 Mon Sep 17 00:00:00 2001
From: noahjacob
Date: Mon, 24 May 2021 16:52:55 +0530
Subject: [PATCH 265/386] refactor: removed py2 code
---
erpnext/accounts/doctype/campaign_item/campaign_item.py | 2 --
.../accounts/doctype/customer_group_item/customer_group_item.py | 2 --
erpnext/accounts/doctype/customer_item/customer_item.py | 2 --
.../accounts/doctype/sales_partner_item/sales_partner_item.py | 2 --
.../accounts/doctype/supplier_group_item/supplier_group_item.py | 2 --
erpnext/accounts/doctype/supplier_item/supplier_item.py | 2 --
erpnext/accounts/doctype/territory_item/territory_item.py | 2 --
7 files changed, 14 deletions(-)
diff --git a/erpnext/accounts/doctype/campaign_item/campaign_item.py b/erpnext/accounts/doctype/campaign_item/campaign_item.py
index e5ca7e5368..4f5fd7f7d7 100644
--- a/erpnext/accounts/doctype/campaign_item/campaign_item.py
+++ b/erpnext/accounts/doctype/campaign_item/campaign_item.py
@@ -1,8 +1,6 @@
-# -*- coding: utf-8 -*-
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
-from __future__ import unicode_literals
# import frappe
from frappe.model.document import Document
diff --git a/erpnext/accounts/doctype/customer_group_item/customer_group_item.py b/erpnext/accounts/doctype/customer_group_item/customer_group_item.py
index ea24788ad5..df782ac9e0 100644
--- a/erpnext/accounts/doctype/customer_group_item/customer_group_item.py
+++ b/erpnext/accounts/doctype/customer_group_item/customer_group_item.py
@@ -1,8 +1,6 @@
-# -*- coding: utf-8 -*-
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
-from __future__ import unicode_literals
# import frappe
from frappe.model.document import Document
diff --git a/erpnext/accounts/doctype/customer_item/customer_item.py b/erpnext/accounts/doctype/customer_item/customer_item.py
index 4aad84ec14..a577145e4e 100644
--- a/erpnext/accounts/doctype/customer_item/customer_item.py
+++ b/erpnext/accounts/doctype/customer_item/customer_item.py
@@ -1,8 +1,6 @@
-# -*- coding: utf-8 -*-
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
-from __future__ import unicode_literals
# import frappe
from frappe.model.document import Document
diff --git a/erpnext/accounts/doctype/sales_partner_item/sales_partner_item.py b/erpnext/accounts/doctype/sales_partner_item/sales_partner_item.py
index 9e6564845b..9796c7b0cc 100644
--- a/erpnext/accounts/doctype/sales_partner_item/sales_partner_item.py
+++ b/erpnext/accounts/doctype/sales_partner_item/sales_partner_item.py
@@ -1,8 +1,6 @@
-# -*- coding: utf-8 -*-
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
-from __future__ import unicode_literals
# import frappe
from frappe.model.document import Document
diff --git a/erpnext/accounts/doctype/supplier_group_item/supplier_group_item.py b/erpnext/accounts/doctype/supplier_group_item/supplier_group_item.py
index 5ea2635482..de0444ee19 100644
--- a/erpnext/accounts/doctype/supplier_group_item/supplier_group_item.py
+++ b/erpnext/accounts/doctype/supplier_group_item/supplier_group_item.py
@@ -1,8 +1,6 @@
-# -*- coding: utf-8 -*-
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
-from __future__ import unicode_literals
# import frappe
from frappe.model.document import Document
diff --git a/erpnext/accounts/doctype/supplier_item/supplier_item.py b/erpnext/accounts/doctype/supplier_item/supplier_item.py
index b58b5dc057..ad66e230c8 100644
--- a/erpnext/accounts/doctype/supplier_item/supplier_item.py
+++ b/erpnext/accounts/doctype/supplier_item/supplier_item.py
@@ -1,8 +1,6 @@
-# -*- coding: utf-8 -*-
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
-from __future__ import unicode_literals
# import frappe
from frappe.model.document import Document
diff --git a/erpnext/accounts/doctype/territory_item/territory_item.py b/erpnext/accounts/doctype/territory_item/territory_item.py
index 9adfc00572..d46edc9dca 100644
--- a/erpnext/accounts/doctype/territory_item/territory_item.py
+++ b/erpnext/accounts/doctype/territory_item/territory_item.py
@@ -1,8 +1,6 @@
-# -*- coding: utf-8 -*-
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
-from __future__ import unicode_literals
# import frappe
from frappe.model.document import Document
From 10ce2f5d6ebcacf16604930e399659cb2eadb740 Mon Sep 17 00:00:00 2001
From: Noah Jacob
Date: Wed, 4 Aug 2021 21:10:25 +0530
Subject: [PATCH 266/386] refactor: added naming series for pricing rule
---
.../doctype/pricing_rule/pricing_rule.json | 18 +++++++++++++-----
.../promotional_scheme/promotional_scheme.py | 18 +++++++++---------
2 files changed, 22 insertions(+), 14 deletions(-)
diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.json b/erpnext/accounts/doctype/pricing_rule/pricing_rule.json
index 0be41b4063..99c5b34fa3 100644
--- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.json
+++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.json
@@ -2,12 +2,13 @@
"actions": [],
"allow_import": 1,
"allow_rename": 1,
- "autoname": "field:title",
+ "autoname": "naming_series:",
"creation": "2014-02-21 15:02:51",
"doctype": "DocType",
"engine": "InnoDB",
"field_order": [
"applicability_section",
+ "naming_series",
"title",
"disable",
"apply_on",
@@ -95,8 +96,7 @@
"fieldtype": "Data",
"label": "Title",
"no_copy": 1,
- "reqd": 1,
- "unique": 1
+ "reqd": 1
},
{
"default": "0",
@@ -571,6 +571,13 @@
"fieldname": "is_recursive",
"fieldtype": "Check",
"label": "Is Recursive"
+ },
+ {
+ "default": "PRLE-.####",
+ "fieldname": "naming_series",
+ "fieldtype": "Select",
+ "label": "Naming Series",
+ "options": "PRLE-.####"
}
],
"icon": "fa fa-gift",
@@ -634,5 +641,6 @@
],
"show_name_in_global_search": 1,
"sort_field": "modified",
- "sort_order": "DESC"
-}
\ No newline at end of file
+ "sort_order": "DESC",
+ "title_field": "title"
+}
diff --git a/erpnext/accounts/doctype/promotional_scheme/promotional_scheme.py b/erpnext/accounts/doctype/promotional_scheme/promotional_scheme.py
index 53239feb42..f4ee1887c4 100644
--- a/erpnext/accounts/doctype/promotional_scheme/promotional_scheme.py
+++ b/erpnext/accounts/doctype/promotional_scheme/promotional_scheme.py
@@ -81,7 +81,7 @@ def _get_pricing_rules(doc, child_doc, discount_fields, rules = {}):
new_doc = []
args = get_args_for_pricing_rule(doc)
applicable_for = frappe.scrub(doc.get('applicable_for'))
- for d in doc.get(child_doc):
+ for idx, d in enumerate(doc.get(child_doc)):
if d.name in rules:
for applicable_for_value in args.get(applicable_for):
temp_args = args.copy()
@@ -93,24 +93,24 @@ def _get_pricing_rules(doc, child_doc, discount_fields, rules = {}):
applicable_for: applicable_for_value
}
)
-
+
if docname:
pr = frappe.get_doc('Pricing Rule', docname[0].get('name'))
temp_args[applicable_for] = applicable_for_value
pr = set_args(temp_args, pr, doc, child_doc, discount_fields, d)
else:
pr = frappe.new_doc("Pricing Rule")
- pr.title = make_autoname("{0}/.####".format(doc.name))
+ pr.title = doc.name
temp_args[applicable_for] = applicable_for_value
pr = set_args(temp_args, pr, doc, child_doc, discount_fields, d)
-
+
new_doc.append(pr)
-
+
else:
for i in range(len(args.get(applicable_for))) :
pr = frappe.new_doc("Pricing Rule")
- pr.title = make_autoname("{0}/.####".format(doc.name))
+ pr.title = doc.name
temp_args = args.copy()
temp_args[applicable_for] = args[applicable_for][i]
pr = set_args(temp_args, pr, doc, child_doc, discount_fields, d)
@@ -144,13 +144,13 @@ def set_args(args, pr, doc, child_doc, discount_fields, child_doc_fields):
def get_args_for_pricing_rule(doc):
args = { 'promotional_scheme': doc.name }
applicable_for = frappe.scrub(doc.get('applicable_for'))
-
+
for d in pricing_rule_fields:
if d == applicable_for:
items = []
for applicable_for_values in doc.get(applicable_for):
- items.append(applicable_for_values.get(applicable_for))
- args[d] = items
+ items.append(applicable_for_values.get(applicable_for))
+ args[d] = items
else:
args[d] = doc.get(d)
return args
From 2ab62a44845d6d9dcda249759b3ad3131cc50f3a Mon Sep 17 00:00:00 2001
From: Subin Tom <36098155+nemesis189@users.noreply.github.com>
Date: Tue, 10 Aug 2021 11:43:59 +0530
Subject: [PATCH 267/386] fix: Missing method reset_issue_metrics added back to
Issue doctype (#26574)
---
erpnext/support/doctype/issue/issue.py | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/erpnext/support/doctype/issue/issue.py b/erpnext/support/doctype/issue/issue.py
index 9c69deb6a4..e4c4af0365 100644
--- a/erpnext/support/doctype/issue/issue.py
+++ b/erpnext/support/doctype/issue/issue.py
@@ -222,6 +222,10 @@ class Issue(Document):
}).insert(ignore_permissions=True)
return replicated_issue.name
+
+ def reset_issue_metrics(self):
+ self.db_set("resolution_time", None)
+ self.db_set("user_resolution_time", None)
def before_insert(self):
if frappe.db.get_single_value("Support Settings", "track_service_level_agreement"):
From 06b6b7e3cca968abc18e7136b8567ade9192003a Mon Sep 17 00:00:00 2001
From: marination
Date: Tue, 10 Aug 2021 13:10:46 +0530
Subject: [PATCH 268/386] fix: Set CWIP Account in company at the start to
avoid flaky test
---
.../doctype/landed_cost_voucher/test_landed_cost_voucher.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py b/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py
index 128a2ab62f..cb09d93380 100644
--- a/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py
+++ b/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py
@@ -253,6 +253,8 @@ class TestLandedCostVoucher(unittest.TestCase):
def test_asset_lcv(self):
"Check if LCV for an Asset updates the Assets Gross Purchase Amount correctly."
+ frappe.db.set_value("Company", "_Test Company", "capital_work_in_progress_account", "CWIP Account - _TC")
+
if not frappe.db.exists("Asset Category", "Computers"):
create_asset_category()
@@ -265,7 +267,6 @@ class TestLandedCostVoucher(unittest.TestCase):
assets = frappe.db.get_all('Asset', filters={'purchase_receipt': pr.name})
self.assertEqual(len(assets), 1)
- frappe.db.set_value("Company", pr.company, "capital_work_in_progress_account", "CWIP Account - _TC")
lcv = make_landed_cost_voucher(
company = pr.company,
receipt_document_type = "Purchase Receipt",
From 24da00cada12c20973c9ea3c6914b8fb60c5754f Mon Sep 17 00:00:00 2001
From: Anurag Mishra <32095923+Anurag810@users.noreply.github.com>
Date: Tue, 10 Aug 2021 13:17:41 +0530
Subject: [PATCH 269/386] fix: updating lead status while customer creation
(#26607)
* fix: updating lead status while customer creation
* fix: changes requested
---
erpnext/selling/doctype/customer/customer.py | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py
index 818888c0c1..9785f6c7a9 100644
--- a/erpnext/selling/doctype/customer/customer.py
+++ b/erpnext/selling/doctype/customer/customer.py
@@ -134,9 +134,7 @@ class Customer(TransactionBase):
'''If Customer created from Lead, update lead status to "Converted"
update Customer link in Quotation, Opportunity'''
if self.lead_name:
- lead = frappe.get_doc('Lead', self.lead_name)
- lead.status = 'Converted'
- lead.save()
+ frappe.db.set_value("Lead", self.lead_name, "status", "Converted")
def create_lead_address_contact(self):
if self.lead_name:
From 57191985761b6963cf2dd7c44c8300c0a86f1fe8 Mon Sep 17 00:00:00 2001
From: Saqib
Date: Tue, 10 Aug 2021 13:56:48 +0530
Subject: [PATCH 270/386] feat: dynamic conditions for applying SLA (#26806)
---
erpnext/support/doctype/issue/issue.py | 6 +--
.../service_level_agreement.json | 28 ++++++++++-
.../service_level_agreement.py | 48 +++++++++++++++----
3 files changed, 68 insertions(+), 14 deletions(-)
diff --git a/erpnext/support/doctype/issue/issue.py b/erpnext/support/doctype/issue/issue.py
index e4c4af0365..b48925d33a 100644
--- a/erpnext/support/doctype/issue/issue.py
+++ b/erpnext/support/doctype/issue/issue.py
@@ -235,8 +235,7 @@ class Issue(Document):
self.set_response_and_resolution_time()
def set_response_and_resolution_time(self, priority=None, service_level_agreement=None):
- service_level_agreement = get_active_service_level_agreement_for(priority=priority,
- customer=self.customer, service_level_agreement=service_level_agreement)
+ service_level_agreement = get_active_service_level_agreement_for(self)
if not service_level_agreement:
if frappe.db.get_value("Issue", self.name, "service_level_agreement"):
@@ -247,7 +246,8 @@ class Issue(Document):
frappe.throw(_("This Service Level Agreement is specific to Customer {0}").format(service_level_agreement.customer))
self.service_level_agreement = service_level_agreement.name
- self.priority = service_level_agreement.default_priority if not priority else priority
+ if not self.priority:
+ self.priority = service_level_agreement.default_priority
priority = get_priority(self)
diff --git a/erpnext/support/doctype/service_level_agreement/service_level_agreement.json b/erpnext/support/doctype/service_level_agreement/service_level_agreement.json
index 939c199982..1678f04def 100644
--- a/erpnext/support/doctype/service_level_agreement/service_level_agreement.json
+++ b/erpnext/support/doctype/service_level_agreement/service_level_agreement.json
@@ -18,6 +18,10 @@
"entity_type",
"column_break_10",
"entity",
+ "filters_section",
+ "condition",
+ "column_break_15",
+ "condition_description",
"agreement_details_section",
"start_date",
"active",
@@ -171,10 +175,30 @@
"fieldtype": "Table",
"label": "Pause SLA On",
"options": "Pause SLA On Status"
+ },
+ {
+ "fieldname": "filters_section",
+ "fieldtype": "Section Break",
+ "label": "Assignment Condition"
+ },
+ {
+ "fieldname": "column_break_15",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "condition",
+ "fieldtype": "Code",
+ "label": "Condition",
+ "options": "Python"
+ },
+ {
+ "fieldname": "condition_description",
+ "fieldtype": "HTML",
+ "options": "Condition Examples:
\ndoc.status==\"Open\" doc.due_date==nowdate() doc.total > 40000\n "
}
],
"links": [],
- "modified": "2020-06-10 12:30:15.050785",
+ "modified": "2021-07-27 11:16:45.596579",
"modified_by": "Administrator",
"module": "Support",
"name": "Service Level Agreement",
@@ -208,4 +232,4 @@
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
-}
\ No newline at end of file
+}
diff --git a/erpnext/support/doctype/service_level_agreement/service_level_agreement.py b/erpnext/support/doctype/service_level_agreement/service_level_agreement.py
index 70c469663b..ec0237e2ea 100644
--- a/erpnext/support/doctype/service_level_agreement/service_level_agreement.py
+++ b/erpnext/support/doctype/service_level_agreement/service_level_agreement.py
@@ -3,10 +3,12 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe.model.document import Document
from frappe import _
-from frappe.utils import getdate, get_weekdays, get_link_to_form
+from frappe.utils import getdate, get_weekdays, get_link_to_form, nowdate
+from frappe.utils.safe_exec import get_safe_globals
class ServiceLevelAgreement(Document):
@@ -14,6 +16,7 @@ class ServiceLevelAgreement(Document):
self.validate_doc()
self.check_priorities()
self.check_support_and_resolution()
+ self.validate_condition()
def check_priorities(self):
default_priority = []
@@ -92,6 +95,14 @@ class ServiceLevelAgreement(Document):
if frappe.db.exists("Service Level Agreement", {"entity_type": self.entity_type, "entity": self.entity, "name": ["!=", self.name]}):
frappe.throw(_("Service Level Agreement with Entity Type {0} and Entity {1} already exists.").format(self.entity_type, self.entity))
+ def validate_condition(self):
+ temp_doc = frappe.new_doc('Issue')
+ if self.condition:
+ try:
+ frappe.safe_eval(self.condition, None, get_context(temp_doc))
+ except Exception:
+ frappe.throw(_("The Condition '{0}' is invalid").format(self.condition))
+
def get_service_level_agreement_priority(self, priority):
priority = frappe.get_doc("Service Level Priority", {"priority": priority, "parent": self.name})
@@ -112,7 +123,7 @@ def check_agreement_status():
if doc.end_date and getdate(doc.end_date) < getdate(frappe.utils.getdate()):
frappe.db.set_value("Service Level Agreement", service_level_agreement.name, "active", 0)
-def get_active_service_level_agreement_for(priority, customer=None, service_level_agreement=None):
+def get_active_service_level_agreement_for(doc):
if not frappe.db.get_single_value("Support Settings", "track_service_level_agreement"):
return
@@ -121,23 +132,42 @@ def get_active_service_level_agreement_for(priority, customer=None, service_leve
["Service Level Agreement", "enable", "=", 1]
]
- if priority:
- filters.append(["Service Level Priority", "priority", "=", priority])
+ if doc.get('priority'):
+ filters.append(["Service Level Priority", "priority", "=", doc.get('priority')])
+ customer = doc.get('customer')
or_filters = [
["Service Level Agreement", "entity", "in", [customer, get_customer_group(customer), get_customer_territory(customer)]]
]
+
+ service_level_agreement = doc.get('service_level_agreement')
if service_level_agreement:
or_filters = [
- ["Service Level Agreement", "name", "=", service_level_agreement],
+ ["Service Level Agreement", "name", "=", doc.get('service_level_agreement')],
]
- or_filters.append(["Service Level Agreement", "default_service_level_agreement", "=", 1])
+ default_sla_filter = filters + [["Service Level Agreement", "default_service_level_agreement", "=", 1]]
+ default_sla = frappe.get_all("Service Level Agreement", filters=default_sla_filter,
+ fields=["name", "default_priority", "condition"])
- agreement = frappe.get_list("Service Level Agreement", filters=filters, or_filters=or_filters,
- fields=["name", "default_priority"])
+ filters += [["Service Level Agreement", "default_service_level_agreement", "=", 0]]
+ agreements = frappe.get_all("Service Level Agreement", filters=filters, or_filters=or_filters,
+ fields=["name", "default_priority", "condition"])
+
+ # check if the current document on which SLA is to be applied fulfills all the conditions
+ filtered_agreements = []
+ for agreement in agreements:
+ condition = agreement.get('condition')
+ if not condition or (condition and frappe.safe_eval(condition, None, get_context(doc))):
+ filtered_agreements.append(agreement)
- return agreement[0] if agreement else None
+ # if any default sla
+ filtered_agreements += default_sla
+
+ return filtered_agreements[0] if filtered_agreements else None
+
+def get_context(doc):
+ return {"doc": doc.as_dict(), "nowdate": nowdate, "frappe": frappe._dict(utils=get_safe_globals().get("frappe").get("utils"))}
def get_customer_group(customer):
if customer:
From f22b85825370fe75b8df694f3c8f86a572dc411b Mon Sep 17 00:00:00 2001
From: marination
Date: Thu, 22 Jul 2021 13:23:54 +0530
Subject: [PATCH 271/386] fix: Clean Serial No input on Server Side
---
erpnext/controllers/stock_controller.py | 7 +++++++
erpnext/public/js/controllers/transaction.js | 2 +-
erpnext/stock/doctype/serial_no/serial_no.py | 10 ++++++++--
erpnext/stock/doctype/stock_entry/stock_entry.py | 1 +
.../stock_reconciliation/stock_reconciliation.py | 1 +
5 files changed, 18 insertions(+), 3 deletions(-)
diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py
index 17bd7354f9..17707ecae7 100644
--- a/erpnext/controllers/stock_controller.py
+++ b/erpnext/controllers/stock_controller.py
@@ -27,6 +27,7 @@ class StockController(AccountsController):
if not self.get('is_return'):
self.validate_inspection()
self.validate_serialized_batch()
+ self.clean_serial_nos()
self.validate_customer_provided_item()
self.set_rate_of_stock_uom()
self.validate_internal_transfer()
@@ -72,6 +73,12 @@ class StockController(AccountsController):
frappe.throw(_("Row #{0}: The batch {1} has already expired.")
.format(d.idx, get_link_to_form("Batch", d.get("batch_no"))))
+ def clean_serial_nos(self):
+ for row in self.get("items"):
+ if hasattr(row, "serial_no") and row.serial_no:
+ # replace commas by linefeed and remove all spaces in string
+ row.serial_no = row.serial_no.replace(",", "\n").replace(" ", "")
+
def get_gl_entries(self, warehouse_account=None, default_expense_account=None,
default_cost_center=None):
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index 5475383759..b9fa9b7ebb 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -732,7 +732,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
this.frm.trigger("item_code", cdt, cdn);
}
else {
- // Replacing all occurences of comma with carriage return
+ // Replace all occurences of comma with line feed
item.serial_no = item.serial_no.replace(/,/g, '\n');
item.conversion_factor = item.conversion_factor || 1;
refresh_field("serial_no", item.name, item.parentfield);
diff --git a/erpnext/stock/doctype/serial_no/serial_no.py b/erpnext/stock/doctype/serial_no/serial_no.py
index bad7b608ac..70312bc543 100644
--- a/erpnext/stock/doctype/serial_no/serial_no.py
+++ b/erpnext/stock/doctype/serial_no/serial_no.py
@@ -165,8 +165,14 @@ class SerialNo(StockController):
)
ORDER BY
posting_date desc, posting_time desc, creation desc""",
- (self.item_code, self.company,
- serial_no, serial_no+'\n%', '%\n'+serial_no, '%\n'+serial_no+'\n%'), as_dict=1):
+ (
+ self.item_code, self.company,
+ serial_no,
+ serial_no+'\n%',
+ '%\n'+serial_no,
+ '%\n'+serial_no+'\n%'
+ ),
+ as_dict=1):
if serial_no.upper() in get_serial_nos(sle.serial_no):
if cint(sle.actual_qty) > 0:
sle_dict.setdefault("incoming", []).append(sle)
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py
index 654755ec2f..3ff42bf974 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.py
@@ -76,6 +76,7 @@ class StockEntry(StockController):
self.validate_difference_account()
self.set_job_card_data()
self.set_purpose_for_stock_entry()
+ self.clean_serial_nos()
self.validate_duplicate_serial_no()
if not self.from_bom:
diff --git a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
index 2e09286507..324bb7a62d 100644
--- a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
+++ b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
@@ -31,6 +31,7 @@ class StockReconciliation(StockController):
self.validate_expense_account()
self.validate_customer_provided_item()
self.set_zero_value_for_customer_provided_items()
+ self.clean_serial_nos()
self.set_total_qty_and_amount()
self.validate_putaway_capacity()
From 510e31952d8f557530ba83d05dad11509447875d Mon Sep 17 00:00:00 2001
From: marination
Date: Tue, 10 Aug 2021 14:00:55 +0530
Subject: [PATCH 272/386] test: Serial no sanitation
---
.../stock/doctype/serial_no/test_serial_no.py | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/erpnext/stock/doctype/serial_no/test_serial_no.py b/erpnext/stock/doctype/serial_no/test_serial_no.py
index cde7fe07c6..b9a58cf43e 100644
--- a/erpnext/stock/doctype/serial_no/test_serial_no.py
+++ b/erpnext/stock/doctype/serial_no/test_serial_no.py
@@ -174,5 +174,23 @@ class TestSerialNo(unittest.TestCase):
self.assertEqual(sn_doc.warehouse, "_Test Warehouse - _TC")
self.assertEqual(sn_doc.purchase_document_no, se.name)
+ def test_serial_no_sanitation(self):
+ "Test if Serial No input is sanitised before entering the DB."
+ item_code = "_Test Serialized Item"
+ test_records = frappe.get_test_records('Stock Entry')
+
+ se = frappe.copy_doc(test_records[0])
+ se.get("items")[0].item_code = item_code
+ se.get("items")[0].qty = 3
+ se.get("items")[0].serial_no = " _TS1, _TS2 , _TS3 "
+ se.get("items")[0].transfer_qty = 3
+ se.set_stock_entry_type()
+ se.insert()
+ se.submit()
+
+ self.assertEqual(se.get("items")[0].serial_no, "_TS1\n_TS2\n_TS3")
+
+ frappe.db.rollback()
+
def tearDown(self):
frappe.db.rollback()
\ No newline at end of file
From 1ba04fdfe542455bd703a56a48f4f65c1ac5f3e9 Mon Sep 17 00:00:00 2001
From: Frappe PR Bot
Date: Tue, 10 Aug 2021 15:47:36 +0530
Subject: [PATCH 273/386] fix: pos profile not mandatory for Sales Invoice
(#26876)
---
erpnext/accounts/doctype/sales_invoice/sales_invoice.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index 2539de7b12..eba8ba830f 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -480,7 +480,7 @@ class SalesInvoice(SellingController):
if not self.pos_profile:
pos_profile = get_pos_profile(self.company) or {}
if not pos_profile:
- frappe.throw(_("No POS Profile found. Please create a New POS Profile first"))
+ return
self.pos_profile = pos_profile.get('name')
pos = {}
From 793063bf4eb324d606be83e7424691148e4aa227 Mon Sep 17 00:00:00 2001
From: Subin Tom <36098155+nemesis189@users.noreply.github.com>
Date: Tue, 10 Aug 2021 15:57:30 +0530
Subject: [PATCH 274/386] fix: pos return payment mode issue (#26875)
---
erpnext/public/js/controllers/taxes_and_totals.js | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/erpnext/public/js/controllers/taxes_and_totals.js b/erpnext/public/js/controllers/taxes_and_totals.js
index 53d5278bbf..9d8fcb64f7 100644
--- a/erpnext/public/js/controllers/taxes_and_totals.js
+++ b/erpnext/public/js/controllers/taxes_and_totals.js
@@ -47,7 +47,10 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
if (in_list(["Sales Invoice", "POS Invoice"], this.frm.doc.doctype) && this.frm.doc.is_pos &&
this.frm.doc.is_return) {
- this.update_paid_amount_for_return();
+ if (this.frm.doc.doctype == "Sales Invoice") {
+ this.set_total_amount_to_default_mop();
+ }
+ this.calculate_paid_amount();
}
// Sales person's commission
@@ -730,7 +733,7 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
}
},
- update_paid_amount_for_return: function() {
+ set_total_amount_to_default_mop: function() {
var grand_total = this.frm.doc.rounded_total || this.frm.doc.grand_total;
if(this.frm.doc.party_account_currency == this.frm.doc.currency) {
@@ -743,17 +746,14 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
precision("base_grand_total")
);
}
-
this.frm.doc.payments.find(pay => {
if (pay.default) {
pay.amount = total_amount_to_pay;
} else {
- pay.amount = 0.0
+ pay.amount = 0.0;
}
});
this.frm.refresh_fields();
-
- this.calculate_paid_amount();
},
set_default_payment: function(total_amount_to_pay, update_paid_amount) {
From 363225d2ba4d411beeae1d68950412e5c15238ea Mon Sep 17 00:00:00 2001
From: Saqib
Date: Tue, 10 Aug 2021 16:37:23 +0530
Subject: [PATCH 275/386] fix(asset): incorrect date difference calculation
(#26805)
---
erpnext/assets/doctype/asset/test_asset.py | 10 +++++-----
erpnext/regional/india/utils.py | 2 +-
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/erpnext/assets/doctype/asset/test_asset.py b/erpnext/assets/doctype/asset/test_asset.py
index 59fbe3b030..e23a715452 100644
--- a/erpnext/assets/doctype/asset/test_asset.py
+++ b/erpnext/assets/doctype/asset/test_asset.py
@@ -639,7 +639,7 @@ class TestAsset(unittest.TestCase):
asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, 'name')
asset = frappe.get_doc('Asset', asset_name)
asset.calculate_depreciation = 1
- asset.available_for_use_date = '2030-06-12'
+ asset.available_for_use_date = '2030-07-12'
asset.purchase_date = '2030-01-01'
asset.append("finance_books", {
"expected_value_after_useful_life": 1000,
@@ -653,10 +653,10 @@ class TestAsset(unittest.TestCase):
self.assertEqual(asset.finance_books[0].rate_of_depreciation, 50.0)
expected_schedules = [
- ["2030-12-31", 1106.85, 1106.85],
- ["2031-12-31", 3446.58, 4553.43],
- ["2032-12-31", 1723.29, 6276.72],
- ["2033-06-12", 723.28, 7000.00]
+ ["2030-12-31", 942.47, 942.47],
+ ["2031-12-31", 3528.77, 4471.24],
+ ["2032-12-31", 1764.38, 6235.62],
+ ["2033-07-12", 764.38, 7000.00]
]
schedules = [[cstr(d.schedule_date), flt(d.depreciation_amount, 2), flt(d.accumulated_depreciation_amount, 2)]
diff --git a/erpnext/regional/india/utils.py b/erpnext/regional/india/utils.py
index 88c350ac89..a152797a5d 100644
--- a/erpnext/regional/india/utils.py
+++ b/erpnext/regional/india/utils.py
@@ -851,7 +851,7 @@ def get_depreciation_amount(asset, depreciable_value, row):
# if its the first depreciation
if depreciable_value == asset.gross_purchase_amount:
# as per IT act, if the asset is purchased in the 2nd half of fiscal year, then rate is divided by 2
- diff = date_diff(asset.available_for_use_date, row.depreciation_start_date)
+ diff = date_diff(row.depreciation_start_date, asset.available_for_use_date)
if diff <= 180:
rate_of_depreciation = rate_of_depreciation / 2
frappe.msgprint(
From a7e0805039c997caf15f777d8a0a12ae83c91243 Mon Sep 17 00:00:00 2001
From: Frappe PR Bot
Date: Tue, 10 Aug 2021 17:16:15 +0530
Subject: [PATCH 276/386] fix(e-invoicing): cannot cancel invoice if IRN
cancelled on portal (#26879)
---
erpnext/patches.txt | 1 +
.../v12_0/show_einvoice_irn_cancelled_field.py | 12 ++++++++++++
erpnext/regional/india/setup.py | 4 ++--
3 files changed, 15 insertions(+), 2 deletions(-)
create mode 100644 erpnext/patches/v12_0/show_einvoice_irn_cancelled_field.py
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index ada3badd7c..a2b99dc934 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -294,6 +294,7 @@ erpnext.patches.v13_0.update_level_in_bom #1234sswef
erpnext.patches.v13_0.add_missing_fg_item_for_stock_entry
erpnext.patches.v13_0.update_subscription_status_in_memberships
erpnext.patches.v13_0.update_amt_in_work_order_required_items
+erpnext.patches.v12_0.show_einvoice_irn_cancelled_field
erpnext.patches.v13_0.delete_orphaned_tables
erpnext.patches.v13_0.update_export_type_for_gst
erpnext.patches.v13_0.update_tds_check_field #3
diff --git a/erpnext/patches/v12_0/show_einvoice_irn_cancelled_field.py b/erpnext/patches/v12_0/show_einvoice_irn_cancelled_field.py
new file mode 100644
index 0000000000..2319c17b34
--- /dev/null
+++ b/erpnext/patches/v12_0/show_einvoice_irn_cancelled_field.py
@@ -0,0 +1,12 @@
+from __future__ import unicode_literals
+import frappe
+
+def execute():
+ company = frappe.get_all('Company', filters = {'country': 'India'})
+ if not company:
+ return
+
+ irn_cancelled_field = frappe.db.exists('Custom Field', {'dt': 'Sales Invoice', 'fieldname': 'irn_cancelled'})
+ if irn_cancelled_field:
+ frappe.db.set_value('Custom Field', irn_cancelled_field, 'depends_on', 'eval: doc.irn')
+ frappe.db.set_value('Custom Field', irn_cancelled_field, 'read_only', 0)
diff --git a/erpnext/regional/india/setup.py b/erpnext/regional/india/setup.py
index e9372f9b8f..b4f146ce57 100644
--- a/erpnext/regional/india/setup.py
+++ b/erpnext/regional/india/setup.py
@@ -457,7 +457,7 @@ def make_custom_fields(update=True):
depends_on='eval:in_list(["Registered Regular", "SEZ", "Overseas", "Deemed Export"], doc.gst_category) && doc.irn_cancelled === 0'),
dict(fieldname='irn_cancelled', label='IRN Cancelled', fieldtype='Check', no_copy=1, print_hide=1,
- depends_on='eval:(doc.irn_cancelled === 1)', read_only=1, allow_on_submit=1, insert_after='customer'),
+ depends_on='eval: doc.irn', allow_on_submit=1, insert_after='customer'),
dict(fieldname='eway_bill_validity', label='E-Way Bill Validity', fieldtype='Data', no_copy=1, print_hide=1,
depends_on='ewaybill', read_only=1, allow_on_submit=1, insert_after='ewaybill'),
@@ -985,4 +985,4 @@ def create_gratuity_rule():
def update_accounts_settings_for_taxes():
if frappe.db.count('Company') == 1:
- frappe.db.set_value('Accounts Settings', None, "add_taxes_from_item_tax_template", 0)
\ No newline at end of file
+ frappe.db.set_value('Accounts Settings', None, "add_taxes_from_item_tax_template", 0)
From 506ecb421676d53c90819df021131d715845dae5 Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Sun, 20 Jun 2021 12:42:06 +0530
Subject: [PATCH 277/386] feat: Organizational Chart
---
erpnext/hr/doctype/employee/employee.py | 5 +-
.../hr/page/organizational_chart/__init__.py | 0
.../page/organizational_chart/node_card.html | 27 ++
.../organizational_chart.js | 409 ++++++++++++++++++
.../organizational_chart.json | 26 ++
.../organizational_chart.py | 49 +++
erpnext/public/build.json | 3 +-
erpnext/public/scss/organizational_chart.scss | 209 +++++++++
8 files changed, 725 insertions(+), 3 deletions(-)
create mode 100644 erpnext/hr/page/organizational_chart/__init__.py
create mode 100644 erpnext/hr/page/organizational_chart/node_card.html
create mode 100644 erpnext/hr/page/organizational_chart/organizational_chart.js
create mode 100644 erpnext/hr/page/organizational_chart/organizational_chart.json
create mode 100644 erpnext/hr/page/organizational_chart/organizational_chart.py
create mode 100644 erpnext/public/scss/organizational_chart.scss
diff --git a/erpnext/hr/doctype/employee/employee.py b/erpnext/hr/doctype/employee/employee.py
index 5ca47560b1..96046fba81 100755
--- a/erpnext/hr/doctype/employee/employee.py
+++ b/erpnext/hr/doctype/employee/employee.py
@@ -477,13 +477,14 @@ def get_employee_emails(employee_list):
return employee_emails
@frappe.whitelist()
-def get_children(doctype, parent=None, company=None, is_root=False, is_tree=False):
+def get_children(doctype, parent=None, company=None, is_root=False, is_tree=False, fields=None):
filters = [['status', '=', 'Active']]
if company and company != 'All Companies':
filters.append(['company', '=', company])
- fields = ['name as value', 'employee_name as title']
+ if not fields:
+ fields = ['name as value', 'employee_name as title']
if is_root:
parent = ''
diff --git a/erpnext/hr/page/organizational_chart/__init__.py b/erpnext/hr/page/organizational_chart/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/hr/page/organizational_chart/node_card.html b/erpnext/hr/page/organizational_chart/node_card.html
new file mode 100644
index 0000000000..057c45ee86
--- /dev/null
+++ b/erpnext/hr/page/organizational_chart/node_card.html
@@ -0,0 +1,27 @@
+
\ No newline at end of file
diff --git a/erpnext/hr/page/organizational_chart/organizational_chart.js b/erpnext/hr/page/organizational_chart/organizational_chart.js
new file mode 100644
index 0000000000..04bd9422bd
--- /dev/null
+++ b/erpnext/hr/page/organizational_chart/organizational_chart.js
@@ -0,0 +1,409 @@
+frappe.pages['organizational-chart'].on_page_load = function(wrapper) {
+ frappe.ui.make_app_page({
+ parent: wrapper,
+ title: __('Organizational Chart'),
+ single_column: true
+ });
+
+ let organizational_chart = new OrganizationalChart(wrapper);
+ $(wrapper).bind('show', ()=> {
+ organizational_chart.show();
+ });
+};
+
+class OrganizationalChart {
+
+ constructor(wrapper) {
+ this.wrapper = $(wrapper);
+ this.page = wrapper.page;
+
+ this.page.main.css({
+ 'min-height': '300px',
+ 'max-height': '600px',
+ 'overflow': 'auto',
+ 'position': 'relative'
+ });
+ this.page.main.addClass('frappe-card');
+
+ this.nodes = {};
+ this.setup_node_class();
+ }
+
+ setup_node_class() {
+ let me = this;
+ this.Node = class {
+ constructor({
+ id, parent, parent_id, image, name, title, expandable, connections, is_root // eslint-disable-line
+ }) {
+ // to setup values passed via constructor
+ $.extend(this, arguments[0]);
+
+ this.expanded = 0;
+
+ me.nodes[this.id] = this;
+ me.make_node_element(this);
+ me.setup_node_click_action(this);
+ }
+ }
+ }
+
+ make_node_element(node) {
+ let node_card = frappe.render_template('node_card', {
+ id: node.id,
+ name: node.name,
+ title: node.title,
+ image: node.image,
+ parent: node.parent_id,
+ connections: node.connections
+ });
+
+ node.parent.append(node_card);
+ node.$link = $(`#${node.id}`);
+ }
+
+ show() {
+ frappe.breadcrumbs.add('HR');
+
+ let me = this;
+ let company = this.page.add_field({
+ fieldtype: 'Link',
+ options: 'Company',
+ fieldname: 'company',
+ placeholder: __('Select Company'),
+ default: frappe.defaults.get_default('company'),
+ only_select: true,
+ reqd: 1,
+ change: () => {
+ me.company = undefined;
+
+ if (company.get_value() && me.company != company.get_value()) {
+ me.company = company.get_value();
+
+ // svg for connectors
+ me.make_svg_markers()
+
+ if (me.$hierarchy)
+ me.$hierarchy.remove();
+
+ // setup hierarchy
+ me.$hierarchy = $(
+ ``);
+
+ me.page.main.append(me.$hierarchy);
+ me.render_root_node();
+ }
+ }
+ });
+
+ company.refresh();
+ $(`[data-fieldname="company"]`).trigger('change');
+ }
+
+ make_svg_markers() {
+ $('#arrows').remove();
+
+ this.page.main.prepend(`
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `);
+ }
+
+ render_root_node() {
+ this.method = 'erpnext.hr.page.organizational_chart.organizational_chart.get_children';
+
+ let me = this;
+
+ frappe.call({
+ method: me.method,
+ args: {
+ company: me.company
+ },
+ callback: function(r) {
+ if (r.message.length) {
+ let data = r.message[0];
+
+ let root_node = new me.Node({
+ id: data.name,
+ parent: me.$hierarchy.find('.root-level'),
+ parent_id: undefined,
+ image: data.image,
+ name: data.employee_name,
+ title: data.designation,
+ expandable: true,
+ connections: data.connections,
+ is_root: true,
+ });
+
+ me.expand_node(root_node);
+ }
+ }
+ })
+ }
+
+ expand_node(node) {
+ let is_sibling = this.selected_node && this.selected_node.parent_id === node.parent_id;
+ this.set_selected_node(node);
+ this.show_active_path(node);
+ this.collapse_previous_level_nodes(node);
+
+ // since the previous node collapses, all connections to that node need to be rebuilt
+ // if a sibling node is clicked, connections don't need to be rebuilt
+ if (!is_sibling) {
+ // rebuild outgoing connections
+ this.refresh_connectors(node.parent_id);
+
+ // rebuild incoming connections
+ let grandparent = $(`#${node.parent_id}`).attr('data-parent');
+ this.refresh_connectors(grandparent)
+ }
+
+ if (node.expandable && !node.expanded) {
+ return this.load_children(node);
+ }
+ }
+
+ collapse_node() {
+ if (this.selected_node.expandable) {
+ this.selected_node.$children.hide();
+ $(`path[data-parent="${this.selected_node.id}"]`).hide();
+ this.selected_node.expanded = false;
+ }
+ }
+
+ show_active_path(node) {
+ // mark node parent on active path
+ $(`#${node.parent_id}`).addClass('active-path');
+ }
+
+ load_children(node) {
+ frappe.run_serially([
+ () => this.get_child_nodes(node.id),
+ (child_nodes) => this.render_child_nodes(node, child_nodes)
+ ]);
+ }
+
+ get_child_nodes(node_id) {
+ let me = this;
+ return new Promise(resolve => {
+ frappe.call({
+ method: this.method,
+ args: {
+ parent: node_id,
+ company: me.company
+ },
+ callback: (r) => {
+ resolve(r.message);
+ }
+ });
+ });
+ }
+
+ render_child_nodes(node, child_nodes) {
+ const last_level = this.$hierarchy.find('.level:last').index();
+ const current_level = $(`#${node.id}`).parent().parent().parent().index();
+
+ if (last_level === current_level) {
+ this.$hierarchy.append(`
+
+ `);
+ }
+
+ if (!node.$children) {
+ node.$children = $('')
+ .hide()
+ .appendTo(this.$hierarchy.find('.level:last'));
+
+ node.$children.empty();
+
+ if (child_nodes) {
+ $.each(child_nodes, (_i, data) => {
+ this.add_node(node, data);
+
+ setTimeout(() => {
+ this.add_connector(node.id, data.name);
+ }, 250);
+ });
+ }
+ }
+
+ node.$children.show();
+ $(`path[data-parent="${node.id}"]`).show();
+ node.expanded = true;
+ }
+
+ add_node(node, data) {
+ var $li = $(' ');
+
+ return new this.Node({
+ id: data.name,
+ parent: $li.appendTo(node.$children),
+ parent_id: node.id,
+ image: data.image,
+ name: data.employee_name,
+ title: data.designation,
+ expandable: data.expandable,
+ connections: data.connections,
+ children: undefined
+ });
+ }
+
+ add_connector(parent_id, child_id) {
+ let parent_node = document.querySelector(`#${parent_id}`);
+ let child_node = document.querySelector(`#${child_id}`);
+
+ // variable for the namespace
+ const svgns = 'http://www.w3.org/2000/svg';
+ let path = document.createElementNS(svgns, 'path');
+
+ // we need to connect right side of the parent to the left side of the child node
+ let pos_parent_right = {
+ x: parent_node.offsetLeft + parent_node.offsetWidth,
+ y: parent_node.offsetTop + parent_node.offsetHeight / 2
+ };
+ let pos_child_left = {
+ x: child_node.offsetLeft - 5,
+ y: child_node.offsetTop + child_node.offsetHeight / 2
+ };
+
+ let connector =
+ "M" +
+ (pos_parent_right.x) + "," + (pos_parent_right.y) + " " +
+ "C" +
+ (pos_parent_right.x + 100) + "," + (pos_parent_right.y) + " " +
+ (pos_child_left.x - 100) + "," + (pos_child_left.y) + " " +
+ (pos_child_left.x) + "," + (pos_child_left.y);
+
+ path.setAttribute("d", connector);
+ path.setAttribute("data-parent", parent_id);
+ path.setAttribute("data-child", child_id);
+
+ if ($(`#${parent_id}`).hasClass('active')) {
+ path.setAttribute("class", "active-connector");
+ path.setAttribute("marker-start", "url(#arrowstart-active)");
+ path.setAttribute("marker-end", "url(#arrowhead-active)");
+ } else if ($(`#${parent_id}`).hasClass('active-path')) {
+ path.setAttribute("class", "collapsed-connector");
+ path.setAttribute("marker-start", "url(#arrowstart-collapsed)");
+ path.setAttribute("marker-end", "url(#arrowhead-collapsed)");
+ }
+
+ $('#connectors').append(path);
+ }
+
+ set_selected_node(node) {
+ // remove .active class from the current node
+ $('.active').removeClass('active');
+
+ // add active class to the newly selected node
+ this.selected_node = node;
+ node.$link.addClass('active');
+ }
+
+ collapse_previous_level_nodes(node) {
+ let node_parent = $(`#${node.parent_id}`);
+
+ let previous_level_nodes = node_parent.parent().parent().children('li');
+ if (node_parent.parent().hasClass('root-level')) {
+ previous_level_nodes = node_parent.parent().children('li');
+ }
+
+ let node_card = undefined;
+
+ previous_level_nodes.each(function() {
+ node_card = $(this).find('.node-card');
+
+ if (!node_card.hasClass('active-path')) {
+ node_card.addClass('collapsed');
+ }
+ });
+ }
+
+ refresh_connectors(node_parent) {
+ if (!node_parent) return;
+
+ $(`path[data-parent="${node_parent}"]`).remove();
+
+ frappe.run_serially([
+ () => this.get_child_nodes(node_parent),
+ (child_nodes) => {
+ if (child_nodes) {
+ $.each(child_nodes, (_i, data) => {
+ this.add_connector(node_parent, data.name);
+ });
+ }
+ }
+ ]);
+ }
+
+ setup_node_click_action(node) {
+ let me = this;
+ let node_element = $(`#${node.id}`);
+
+ node_element.click(function() {
+ let is_sibling = me.selected_node.parent_id === node.parent_id;
+
+ if (is_sibling) {
+ me.collapse_node();
+ } else if (node_element.is(':visible')
+ && (node_element.hasClass('collapsed') || node_element.hasClass('active-path'))) {
+ me.remove_levels_after_node(node);
+ me.remove_orphaned_connectors();
+ }
+
+ me.expand_node(node);
+ });
+ }
+
+ remove_levels_after_node(node) {
+ let level = $(`#${node.id}`).parent().parent().parent();
+
+ if ($(`#${node.id}`).parent().hasClass('root-level')) {
+ level = $(`#${node.id}`).parent();
+ }
+
+ level = $('.hierarchy > li:eq('+ level.index() + ')');
+ level.nextAll('li').remove();
+
+ let nodes = level.find('.node-card');
+ let node_object = undefined;
+
+ $.each(nodes, (_i, element) => {
+ node_object = this.nodes[element.id];
+ node_object.expanded = 0;
+ node_object.$children = undefined;
+ });
+
+ nodes.removeClass('collapsed active-path');
+ }
+
+ remove_orphaned_connectors() {
+ let paths = $('#connectors > path');
+ $.each(paths, (_i, path) => {
+ let parent = $(path).data('parent');
+ let child = $(path).data('child');
+
+ if ($(parent).length || $(child).length)
+ return;
+
+ $(path).remove();
+ })
+ }
+}
diff --git a/erpnext/hr/page/organizational_chart/organizational_chart.json b/erpnext/hr/page/organizational_chart/organizational_chart.json
new file mode 100644
index 0000000000..d802781320
--- /dev/null
+++ b/erpnext/hr/page/organizational_chart/organizational_chart.json
@@ -0,0 +1,26 @@
+{
+ "content": null,
+ "creation": "2021-05-25 10:53:10.107241",
+ "docstatus": 0,
+ "doctype": "Page",
+ "idx": 0,
+ "modified": "2021-05-25 10:53:18.201931",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "organizational-chart",
+ "owner": "Administrator",
+ "page_name": "Organizational Chart",
+ "roles": [
+ {
+ "role": "HR User"
+ },
+ {
+ "role": "HR Manager"
+ }
+ ],
+ "script": null,
+ "standard": "Yes",
+ "style": null,
+ "system_page": 0,
+ "title": "Organizational Chart"
+}
\ No newline at end of file
diff --git a/erpnext/hr/page/organizational_chart/organizational_chart.py b/erpnext/hr/page/organizational_chart/organizational_chart.py
new file mode 100644
index 0000000000..be2964530b
--- /dev/null
+++ b/erpnext/hr/page/organizational_chart/organizational_chart.py
@@ -0,0 +1,49 @@
+from __future__ import unicode_literals
+import frappe
+
+@frappe.whitelist()
+def get_children(parent=None, company=None, is_root=False, is_tree=False, fields=None):
+
+ filters = [['status', '!=', 'Left']]
+ if company and company != 'All Companies':
+ filters.append(['company', '=', company])
+
+ if not fields:
+ fields = ['employee_name', 'name', 'reports_to', 'image', 'designation']
+
+ if is_root:
+ parent = ''
+ if parent and company and parent!=company:
+ filters.append(['reports_to', '=', parent])
+ else:
+ filters.append(['reports_to', '=', ''])
+
+ employees = frappe.get_list('Employee', fields=fields,
+ filters=filters, order_by='name')
+
+ for employee in employees:
+ is_expandable = frappe.get_all('Employee', filters=[
+ ['reports_to', '=', employee.get('name')]
+ ])
+ employee.connections = get_connections(employee.name)
+ employee.expandable = 1 if is_expandable else 0
+
+ return employees
+
+
+def get_connections(employee):
+ num_connections = 0
+
+ connections = frappe.get_list('Employee', filters=[
+ ['reports_to', '=', employee]
+ ])
+ num_connections += len(connections)
+
+ while connections:
+ for entry in connections:
+ connections = frappe.get_list('Employee', filters=[
+ ['reports_to', '=', entry.name]
+ ])
+ num_connections += len(connections)
+
+ return num_connections
\ No newline at end of file
diff --git a/erpnext/public/build.json b/erpnext/public/build.json
index 7a3cb838a9..d3ebcdf7e7 100644
--- a/erpnext/public/build.json
+++ b/erpnext/public/build.json
@@ -3,7 +3,8 @@
"public/less/erpnext.less",
"public/less/hub.less",
"public/scss/call_popup.scss",
- "public/scss/point-of-sale.scss"
+ "public/scss/point-of-sale.scss",
+ "public/scss/organizational_chart.scss"
],
"css/marketplace.css": [
"public/less/hub.less"
diff --git a/erpnext/public/scss/organizational_chart.scss b/erpnext/public/scss/organizational_chart.scss
new file mode 100644
index 0000000000..62f6ddcb6e
--- /dev/null
+++ b/erpnext/public/scss/organizational_chart.scss
@@ -0,0 +1,209 @@
+.node-card {
+ background: white;
+ stroke: 1px solid var(--gray-200);
+ box-shadow: var(--shadow-base);
+ border-radius: 0.5rem;
+ padding: 0.75rem;
+ margin-left: 3rem;
+ width: 18rem;
+
+ .btn-edit-node {
+ display: none;
+ }
+
+ .edit-chart-node {
+ display: none;
+ }
+
+ .node-edit-icon {
+ display: none;
+ }
+}
+
+.node-image {
+ width: 3.0rem;
+ height: 3.0rem;
+}
+
+.node-name {
+ font-size: 1rem;
+ line-height: 1.72;
+}
+
+.node-title {
+ font-size: 0.75rem;
+ line-height: 1.35;
+}
+
+.node-connections {
+ font-size: 0.75rem;
+ line-height: 1.35;
+}
+
+.node-card.active {
+ background: var(--blue-50);
+ border: 1px solid var(--blue-500);
+ box-shadow: var(--shadow-md);
+ border-radius: 0.5rem;
+ padding: 0.75rem;
+ width: 18rem;
+ height: 5rem;
+
+ .btn-edit-node {
+ display: flex;
+ background: var(--blue-100);
+ color: var(--blue-500);
+ padding: .25rem .5rem;
+ font-size: .75rem;
+ justify-content: center;
+ box-shadow: var(--shadow-sm);
+ }
+
+ .edit-chart-node {
+ display: block;
+ }
+
+ .node-edit-icon {
+ display: block;
+ }
+
+ .edit-chart-node {
+ margin-right: 0.25rem;
+ }
+
+ .node-edit-icon > .icon{
+ stroke: var(--blue-500);
+ }
+
+ .node-name {
+ align-items: center;
+ justify-content: space-between;
+ margin-bottom: 2px;
+ }
+}
+
+.node-card.active-path {
+ background: var(--blue-100);
+ border: 1px solid var(--blue-300);
+ box-shadow: var(--shadow-sm);
+ border-radius: 0.5rem;
+ padding: 0.75rem;
+ width: 15rem;
+ height: 3.0rem;
+
+ .btn-edit-node {
+ display: none !important;
+ }
+
+ .edit-chart-node {
+ display: none;
+ }
+
+ .node-edit-icon {
+ display: none;
+ }
+
+ .node-info {
+ display: none;
+ }
+
+ .node-title {
+ display: none;
+ }
+
+ .node-connections {
+ display: none;
+ }
+
+ .node-name {
+ font-size: 0.85rem;
+ line-height: 1.35;
+ }
+
+ .node-image {
+ width: 1.5rem;
+ height: 1.5rem;
+ }
+
+ .node-meta {
+ align-items: baseline;
+ }
+}
+
+.node-card.collapsed {
+ background: white;
+ stroke: 1px solid var(--gray-200);
+ box-shadow: var(--shadow-sm);
+ border-radius: 0.5rem;
+ padding: 0.75rem;
+ width: 15rem;
+ height: 3.0rem;
+
+ .btn-edit-node {
+ display: none !important;
+ }
+
+ .edit-chart-node {
+ display: none;
+ }
+
+ .node-edit-icon {
+ display: none;
+ }
+
+ .node-info {
+ display: none;
+ }
+
+ .node-title {
+ display: none;
+ }
+
+ .node-connections {
+ display: none;
+ }
+
+ .node-name {
+ font-size: 0.85rem;
+ line-height: 1.35;
+ }
+
+ .node-image {
+ width: 1.5rem;
+ height: 1.5rem;
+ }
+
+ .node-meta {
+ align-items: baseline;
+ }
+}
+
+// horizontal hierarchy tree view
+.hierarchy {
+ display: flex;
+ padding-top: 30px;
+}
+
+.hierarchy li {
+ list-style-type: none;
+}
+
+.child-node {
+ margin: 0px 0px 16px 0px;
+}
+
+.level {
+ margin-right: 8px;
+}
+
+#arrows {
+ position: absolute;
+}
+
+.active-connector {
+ stroke: var(--blue-500);
+}
+
+.collapsed-connector {
+ stroke: var(--blue-300);
+}
From 8a33a039f7723b7adb8aa5e2c489e5410192df03 Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Mon, 21 Jun 2021 21:55:50 +0530
Subject: [PATCH 278/386] feat: org chart mobile interactions
---
.../page/organizational_chart/node_card.html | 4 +-
.../organizational_chart.js | 329 +++++++++++++++++-
.../organizational_chart.py | 6 +-
erpnext/public/scss/organizational_chart.scss | 70 ++++
4 files changed, 404 insertions(+), 5 deletions(-)
diff --git a/erpnext/hr/page/organizational_chart/node_card.html b/erpnext/hr/page/organizational_chart/node_card.html
index 057c45ee86..e42e54f690 100644
--- a/erpnext/hr/page/organizational_chart/node_card.html
+++ b/erpnext/hr/page/organizational_chart/node_card.html
@@ -17,9 +17,9 @@
{{ title }}
{% if connections == 1 %}
- · {{ connections }} {{ __("Connection") }}
+ · {{ connections }}
{% else %}
- · {{ connections }} {{ __("Connections") }}
+ · {{ connections }}
{% endif %}
diff --git a/erpnext/hr/page/organizational_chart/organizational_chart.js b/erpnext/hr/page/organizational_chart/organizational_chart.js
index 04bd9422bd..5739a112de 100644
--- a/erpnext/hr/page/organizational_chart/organizational_chart.js
+++ b/erpnext/hr/page/organizational_chart/organizational_chart.js
@@ -5,13 +5,20 @@ frappe.pages['organizational-chart'].on_page_load = function(wrapper) {
single_column: true
});
- let organizational_chart = new OrganizationalChart(wrapper);
+ // let organizational_chart = undefined;
+ // if (frappe.is_mobile()) {
+ // organizational_chart = new OrgChartMobile(wrapper);
+ // } else {
+ // organizational_chart = new OrgChart(wrapper);
+ // }
+
+ let organizational_chart = new OrgChartMobile(wrapper);
$(wrapper).bind('show', ()=> {
organizational_chart.show();
});
};
-class OrganizationalChart {
+class OrgChart {
constructor(wrapper) {
this.wrapper = $(wrapper);
@@ -407,3 +414,321 @@ class OrganizationalChart {
})
}
}
+
+
+class OrgChartMobile {
+
+ constructor(wrapper) {
+ this.wrapper = $(wrapper);
+ this.page = wrapper.page;
+
+ this.page.main.css({
+ 'min-height': '300px',
+ 'max-height': '600px',
+ 'overflow': 'auto',
+ 'position': 'relative'
+ });
+ this.page.main.addClass('frappe-card');
+
+ this.nodes = {};
+ this.setup_node_class();
+ }
+
+ setup_node_class() {
+ let me = this;
+ this.Node = class {
+ constructor({
+ id, parent, parent_id, image, name, title, expandable, connections, is_root // eslint-disable-line
+ }) {
+ // to setup values passed via constructor
+ $.extend(this, arguments[0]);
+
+ this.expanded = 0;
+
+ me.nodes[this.id] = this;
+ me.make_node_element(this);
+ me.setup_node_click_action(this);
+ }
+ }
+ }
+
+ make_node_element(node) {
+ let node_card = frappe.render_template('node_card', {
+ id: node.id,
+ name: node.name,
+ title: node.title,
+ image: node.image,
+ parent: node.parent_id,
+ connections: node.connections,
+ is_mobile: 1
+ });
+
+ node.parent.append(node_card);
+ node.$link = $(`#${node.id}`);
+ node.$link.addClass('mobile-node');
+ }
+
+ show() {
+ frappe.breadcrumbs.add('HR');
+
+ let me = this;
+ let company = this.page.add_field({
+ fieldtype: 'Link',
+ options: 'Company',
+ fieldname: 'company',
+ placeholder: __('Select Company'),
+ default: frappe.defaults.get_default('company'),
+ only_select: true,
+ reqd: 1,
+ change: () => {
+ me.company = undefined;
+
+ if (company.get_value() && me.company != company.get_value()) {
+ me.company = company.get_value();
+
+ if (me.$hierarchy)
+ me.$hierarchy.remove();
+
+ // setup hierarchy
+ me.$hierarchy = $(
+ `
`);
+
+ me.page.main.append(me.$hierarchy);
+ me.render_root_node();
+ }
+ }
+ });
+
+ company.refresh();
+ $(`[data-fieldname="company"]`).trigger('change');
+ }
+
+ render_root_node() {
+ this.method = 'erpnext.hr.page.organizational_chart.organizational_chart.get_children';
+
+ let me = this;
+
+ frappe.call({
+ method: me.method,
+ args: {
+ company: me.company
+ },
+ callback: function(r) {
+ if (r.message.length) {
+ let data = r.message[0];
+
+ let root_node = new me.Node({
+ id: data.name,
+ parent: me.$hierarchy.find('.root-level'),
+ parent_id: undefined,
+ image: data.image,
+ name: data.employee_name,
+ title: data.designation,
+ expandable: true,
+ connections: data.connections,
+ is_root: true,
+ });
+
+ me.expand_node(root_node);
+ }
+ }
+ })
+ }
+
+ expand_node(node) {
+ this.set_selected_node(node);
+ this.show_active_path(node);
+
+ if (node.expandable && !node.expanded) {
+ return this.load_children(node);
+ }
+ }
+
+ collapse_node() {
+ let node = this.selected_node;
+ if (node.expandable) {
+ node.$children.hide();
+ node.expanded = false;
+
+ // add a collapsed level to show the collapsed parent
+ // and a button beside it to move to that level
+ let node_parent = node.$link.parent();
+ node_parent.prepend(
+ `
`
+ );
+
+ node_parent
+ .find('.collapsed-level')
+ .append(node.$link);
+
+ frappe.run_serially([
+ () => this.get_child_nodes(node.parent_id, node.id),
+ (child_nodes) => this.get_node_group(child_nodes, node.id),
+ (node_group) => {
+ node_parent.find('.collapsed-level')
+ .append(node_group);
+ }
+ ]);
+ }
+ }
+
+ show_active_path(node) {
+ // mark node parent on active path
+ $(`#${node.parent_id}`).addClass('active-path');
+ }
+
+ load_children(node) {
+ frappe.run_serially([
+ () => this.get_child_nodes(node.id),
+ (child_nodes) => this.render_child_nodes(node, child_nodes)
+ ]);
+ }
+
+ get_child_nodes(node_id, exclude_node=null) {
+ let me = this;
+ return new Promise(resolve => {
+ frappe.call({
+ method: this.method,
+ args: {
+ parent: node_id,
+ company: me.company,
+ exclude_node: exclude_node
+ },
+ callback: (r) => {
+ resolve(r.message);
+ }
+ });
+ });
+ }
+
+ render_child_nodes(node, child_nodes) {
+ if (!node.$children) {
+ node.$children = $('
')
+ .hide()
+ .appendTo(node.$link.parent());
+
+ node.$children.empty();
+
+ if (child_nodes) {
+ $.each(child_nodes, (_i, data) => {
+ this.add_node(node, data);
+ $(`#${data.name}`).addClass('active-child');
+ });
+ }
+ }
+
+ node.$children.show();
+ node.expanded = true;
+ }
+
+ add_node(node, data) {
+ var $li = $('
');
+
+ return new this.Node({
+ id: data.name,
+ parent: $li.appendTo(node.$children),
+ parent_id: node.id,
+ image: data.image,
+ name: data.employee_name,
+ title: data.designation,
+ expandable: data.expandable,
+ connections: data.connections,
+ children: undefined
+ });
+ }
+
+ set_selected_node(node) {
+ // remove .active class from the current node
+ $('.active').removeClass('active');
+
+ // add active class to the newly selected node
+ this.selected_node = node;
+ node.$link.addClass('active');
+ }
+
+ setup_node_click_action(node) {
+ let me = this;
+ let node_element = $(`#${node.id}`);
+ let node_object = null;
+
+ node_element.click(function() {
+ if (node_element.is(':visible') && node_element.hasClass('active-path')) {
+ me.remove_levels_after_node(node);
+ } else {
+ me.add_node_to_hierarchy(node, true);
+ me.collapse_node();
+ }
+
+ me.expand_node(node);
+ });
+ }
+
+ add_node_to_hierarchy(node) {
+ this.$hierarchy.append(`
+
+
+
+
+ `);
+
+ node.$link.appendTo(this.$hierarchy.find('.level:last'));
+ }
+
+ get_node_group(nodes, sibling) {
+ let limit = 2;
+ const display_nodes = nodes.slice(0, limit);
+ const extra_nodes = nodes.slice(limit);
+
+ let html = display_nodes.map(node =>
+ this.get_avatar(node)
+ ).join('');
+
+ if (extra_nodes.length === 1) {
+ let node = extra_nodes[0];
+ html += this.get_avatar(node);
+ } else if (extra_nodes.length > 1) {
+ html = `
+ ${html}
+
+
+ +${extra_nodes.length}
+
+
+ `;
+ }
+
+ const $node_group =
+ $(`
`);
+
+ return $node_group;
+ }
+
+ get_avatar(node) {
+ return `
+
+ `
+ }
+
+ remove_levels_after_node(node) {
+ let level = $(`#${node.id}`).parent().parent();
+
+ level = $('.hierarchy-mobile > li:eq('+ (level.index()) + ')');
+ level.nextAll('li').remove();
+
+ let current_node = level.find(`#${node.id}`);
+ let node_object = this.nodes[node.id];
+
+ current_node.removeClass('active-child active-path');
+ node_object.expanded = 0;
+ node_object.$children = undefined;
+
+ level.empty().append(current_node);
+ }
+}
\ No newline at end of file
diff --git a/erpnext/hr/page/organizational_chart/organizational_chart.py b/erpnext/hr/page/organizational_chart/organizational_chart.py
index be2964530b..ae91a919b2 100644
--- a/erpnext/hr/page/organizational_chart/organizational_chart.py
+++ b/erpnext/hr/page/organizational_chart/organizational_chart.py
@@ -2,7 +2,7 @@ from __future__ import unicode_literals
import frappe
@frappe.whitelist()
-def get_children(parent=None, company=None, is_root=False, is_tree=False, fields=None):
+def get_children(parent=None, company=None, exclude_node=None, is_root=False, is_tree=False, fields=None):
filters = [['status', '!=', 'Left']]
if company and company != 'All Companies':
@@ -13,6 +13,10 @@ def get_children(parent=None, company=None, is_root=False, is_tree=False, fields
if is_root:
parent = ''
+
+ if exclude_node:
+ filters.append(['name', '!=', exclude_node])
+
if parent and company and parent!=company:
filters.append(['reports_to', '=', parent])
else:
diff --git a/erpnext/public/scss/organizational_chart.scss b/erpnext/public/scss/organizational_chart.scss
index 62f6ddcb6e..02446be11a 100644
--- a/erpnext/public/scss/organizational_chart.scss
+++ b/erpnext/public/scss/organizational_chart.scss
@@ -6,6 +6,7 @@
padding: 0.75rem;
margin-left: 3rem;
width: 18rem;
+ overflow: hidden;
.btn-edit-node {
display: none;
@@ -207,3 +208,72 @@
.collapsed-connector {
stroke: var(--blue-300);
}
+
+// mobile
+
+.hierarchy-mobile {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ padding-top: 30px;
+ padding-left: 0px;
+}
+
+.hierarchy-mobile li {
+ list-style-type: none;
+ display: flex;
+ flex-direction: column;
+ align-items: flex-end;
+}
+
+.mobile-node {
+ margin-left: 0;
+}
+
+.mobile-node.active-path {
+ width: 12.25rem;
+}
+
+.active-child {
+ width: 15.5rem;
+}
+
+.mobile-node .node-connections {
+ max-width: 80px;
+}
+
+.hierarchy-mobile .node-children {
+ margin-top: 16px;
+}
+
+// node group
+
+.collapsed-level {
+ margin-bottom: 16px;
+}
+
+.node-group {
+ background: white;
+ border: 1px solid var(--gray-300);
+ box-shadow: var(--shadow-sm);
+ border-radius: 0.5rem;
+ padding: 0.75rem;
+ margin-left: 12px;
+ width: 5rem;
+ height: 3rem;
+ overflow: hidden;
+}
+
+.node-group .avatar-group {
+ margin-left: 0px;
+}
+
+.node-group .avatar-extra-count {
+ background-color: var(--blue-100);
+ color: var(--blue-500);
+}
+
+.node-group .avatar-frame {
+ width: 1.5rem;
+ height: 1.5rem;
+}
\ No newline at end of file
From 5046cb09d82a487b91cdd4dd7e4b2631690dc56d Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Tue, 29 Jun 2021 11:12:47 +0530
Subject: [PATCH 279/386] feat(mobile): sibling node group expansion and
rendering
---
.../organizational_chart.js | 64 +++++++++++++++----
erpnext/public/scss/organizational_chart.scss | 9 ++-
2 files changed, 60 insertions(+), 13 deletions(-)
diff --git a/erpnext/hr/page/organizational_chart/organizational_chart.js b/erpnext/hr/page/organizational_chart/organizational_chart.js
index 5739a112de..edaf46162e 100644
--- a/erpnext/hr/page/organizational_chart/organizational_chart.js
+++ b/erpnext/hr/page/organizational_chart/organizational_chart.js
@@ -565,11 +565,12 @@ class OrgChartMobile {
frappe.run_serially([
() => this.get_child_nodes(node.parent_id, node.id),
- (child_nodes) => this.get_node_group(child_nodes, node.id),
+ (child_nodes) => this.get_node_group(child_nodes, node.parent_id),
(node_group) => {
node_parent.find('.collapsed-level')
.append(node_group);
- }
+ },
+ () => this.setup_node_group_action()
]);
}
}
@@ -651,7 +652,6 @@ class OrgChartMobile {
setup_node_click_action(node) {
let me = this;
let node_element = $(`#${node.id}`);
- let node_object = null;
node_element.click(function() {
if (node_element.is(':visible') && node_element.hasClass('active-path')) {
@@ -665,6 +665,15 @@ class OrgChartMobile {
});
}
+ setup_node_group_action() {
+ let me = this;
+
+ $('.node-group').on('click', function() {
+ let parent = $(this).attr('data-parent');
+ me.expand_sibling_group_node(parent);
+ });
+ }
+
add_node_to_hierarchy(node) {
this.$hierarchy.append(`
@@ -676,7 +685,7 @@ class OrgChartMobile {
node.$link.appendTo(this.$hierarchy.find('.level:last'));
}
- get_node_group(nodes, sibling) {
+ get_node_group(nodes, parent, collapsed=true) {
let limit = 2;
const display_nodes = nodes.slice(0, limit);
const extra_nodes = nodes.slice(limit);
@@ -700,14 +709,23 @@ class OrgChartMobile {
`;
}
- const $node_group =
- $(``);
+ if (html) {
+ const $node_group =
+ $(``);
- return $node_group;
+ if (collapsed)
+ $node_group.addClass('collapsed');
+ else
+ $node_group.addClass('mb-4');
+
+ return $node_group;
+ }
+
+ return null;
}
get_avatar(node) {
@@ -716,6 +734,30 @@ class OrgChartMobile {
`
}
+ expand_sibling_group_node(parent) {
+ let node_object = this.nodes[parent];
+ let node = node_object.$link;
+ node.removeClass('active-child active-path');
+ node_object.expanded = 0;
+ node_object.$children = undefined;
+
+ // show parent's siblings and expand parent node
+ frappe.run_serially([
+ () => this.get_child_nodes(node_object.parent_id, node_object.id),
+ (child_nodes) => this.get_node_group(child_nodes, node_object.parent_id, false),
+ (node_group) => {
+ this.$hierarchy.empty().append(node_group) },
+ () => this.setup_node_group_action(),
+ () => {
+ this.$hierarchy.append(`
+
+ `);
+ this.$hierarchy.append(node);
+ this.expand_node(node_object);
+ }
+ ]);
+ }
+
remove_levels_after_node(node) {
let level = $(`#${node.id}`).parent().parent();
diff --git a/erpnext/public/scss/organizational_chart.scss b/erpnext/public/scss/organizational_chart.scss
index 02446be11a..b6d50a0470 100644
--- a/erpnext/public/scss/organizational_chart.scss
+++ b/erpnext/public/scss/organizational_chart.scss
@@ -258,10 +258,10 @@
box-shadow: var(--shadow-sm);
border-radius: 0.5rem;
padding: 0.75rem;
- margin-left: 12px;
- width: 5rem;
+ width: 18rem;
height: 3rem;
overflow: hidden;
+ align-items: center;
}
.node-group .avatar-group {
@@ -276,4 +276,9 @@
.node-group .avatar-frame {
width: 1.5rem;
height: 1.5rem;
+}
+
+.node-group.collapsed {
+ width: 5rem;
+ margin-left: 12px;
}
\ No newline at end of file
From 25c5cff3defed353b59f1096c00c0e8715ff377d Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Tue, 29 Jun 2021 15:06:09 +0530
Subject: [PATCH 280/386] fix: expanded node group interactions and visibility
---
.../organizational_chart.js | 23 +++++++++++++++----
erpnext/public/scss/organizational_chart.scss | 9 +++++++-
2 files changed, 26 insertions(+), 6 deletions(-)
diff --git a/erpnext/hr/page/organizational_chart/organizational_chart.js b/erpnext/hr/page/organizational_chart/organizational_chart.js
index edaf46162e..f693cf6ba6 100644
--- a/erpnext/hr/page/organizational_chart/organizational_chart.js
+++ b/erpnext/hr/page/organizational_chart/organizational_chart.js
@@ -486,6 +486,13 @@ class OrgChartMobile {
if (company.get_value() && me.company != company.get_value()) {
me.company = company.get_value();
+ if (me.$sibling_group)
+ me.$sibling_group.remove();
+
+ // setup sibling group wrapper
+ me.$sibling_group = $(`
`);
+ me.page.main.append(me.$sibling_group);
+
if (me.$hierarchy)
me.$hierarchy.remove();
@@ -541,6 +548,12 @@ class OrgChartMobile {
this.set_selected_node(node);
this.show_active_path(node);
+ if (this.$sibling_group) {
+ const sibling_parent = this.$sibling_group.find('.node-group').attr('data-parent');
+ if (node.parent_id !== sibling_parent)
+ this.$sibling_group.empty();
+ }
+
if (node.expandable && !node.expanded) {
return this.load_children(node);
}
@@ -719,8 +732,6 @@ class OrgChartMobile {
if (collapsed)
$node_group.addClass('collapsed');
- else
- $node_group.addClass('mb-4');
return $node_group;
}
@@ -746,13 +757,15 @@ class OrgChartMobile {
() => this.get_child_nodes(node_object.parent_id, node_object.id),
(child_nodes) => this.get_node_group(child_nodes, node_object.parent_id, false),
(node_group) => {
- this.$hierarchy.empty().append(node_group) },
+ if (node_group)
+ this.$sibling_group.empty().append(node_group);
+ },
() => this.setup_node_group_action(),
() => {
- this.$hierarchy.append(`
+ this.$hierarchy.empty().append(`
`);
- this.$hierarchy.append(node);
+ this.$hierarchy.find('.level').append(node);
this.expand_node(node_object);
}
]);
diff --git a/erpnext/public/scss/organizational_chart.scss b/erpnext/public/scss/organizational_chart.scss
index b6d50a0470..6012c01573 100644
--- a/erpnext/public/scss/organizational_chart.scss
+++ b/erpnext/public/scss/organizational_chart.scss
@@ -215,7 +215,7 @@
display: flex;
flex-direction: column;
align-items: center;
- padding-top: 30px;
+ padding-top: 10px;
padding-left: 0px;
}
@@ -250,6 +250,7 @@
.collapsed-level {
margin-bottom: 16px;
+ width: 18rem;
}
.node-group {
@@ -281,4 +282,10 @@
.node-group.collapsed {
width: 5rem;
margin-left: 12px;
+}
+
+.sibling-group {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
}
\ No newline at end of file
From fb9b628b8942c72f966abd5aa36a80a4a7df904d Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Tue, 29 Jun 2021 17:48:44 +0530
Subject: [PATCH 281/386] feat: connectors for mobile node cards
---
.../organizational_chart.js | 138 ++++++++++++++++++
erpnext/public/scss/organizational_chart.scss | 1 +
2 files changed, 139 insertions(+)
diff --git a/erpnext/hr/page/organizational_chart/organizational_chart.js b/erpnext/hr/page/organizational_chart/organizational_chart.js
index f693cf6ba6..15334bd4ca 100644
--- a/erpnext/hr/page/organizational_chart/organizational_chart.js
+++ b/erpnext/hr/page/organizational_chart/organizational_chart.js
@@ -486,6 +486,9 @@ class OrgChartMobile {
if (company.get_value() && me.company != company.get_value()) {
me.company = company.get_value();
+ // svg for connectors
+ me.make_svg_markers()
+
if (me.$sibling_group)
me.$sibling_group.remove();
@@ -512,6 +515,31 @@ class OrgChartMobile {
$(`[data-fieldname="company"]`).trigger('change');
}
+ make_svg_markers() {
+ $('#arrows').remove();
+
+ this.page.main.prepend(`
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `);
+ }
+
render_root_node() {
this.method = 'erpnext.hr.page.organizational_chart.organizational_chart.get_children';
@@ -554,6 +582,14 @@ class OrgChartMobile {
this.$sibling_group.empty();
}
+ // since the previous/parent node collapses, all connections to that node need to be rebuilt
+ // rebuild outgoing connections of parent
+ this.refresh_connectors(node.parent_id, node.id);
+
+ // rebuild incoming connections of parent
+ let grandparent = $(`#${node.parent_id}`).attr('data-parent');
+ this.refresh_connectors(grandparent, node.parent_id);
+
if (node.expandable && !node.expanded) {
return this.load_children(node);
}
@@ -629,6 +665,10 @@ class OrgChartMobile {
$.each(child_nodes, (_i, data) => {
this.add_node(node, data);
$(`#${data.name}`).addClass('active-child');
+
+ setTimeout(() => {
+ this.add_connector(node.id, data.name);
+ }, 250);
});
}
}
@@ -653,6 +693,83 @@ class OrgChartMobile {
});
}
+ add_connector(parent_id, child_id) {
+ let parent_node = document.querySelector(`#${parent_id}`);
+ let child_node = document.querySelector(`#${child_id}`);
+
+ // variable for the namespace
+ const svgns = 'http://www.w3.org/2000/svg';
+ let path = document.createElementNS(svgns, 'path');
+
+ let connector = undefined;
+
+ if ($(`#${parent_id}`).hasClass('active')) {
+ connector = this.get_connector_for_active_node(parent_node, child_node);
+ } else if ($(`#${parent_id}`).hasClass('active-path')) {
+ connector = this.get_connector_for_collapsed_node(parent_node, child_node);
+ }
+
+ path.setAttribute("d", connector);
+ this.set_path_attributes(path, parent_id, child_id);
+
+ $('#connectors').append(path);
+ }
+
+ get_connector_for_active_node(parent_node, child_node) {
+ // we need to connect the bottom left of the parent to the left side of the child node
+ let pos_parent_bottom = {
+ x: parent_node.offsetLeft + 20,
+ y: parent_node.offsetTop + parent_node.offsetHeight
+ };
+ let pos_child_left = {
+ x: child_node.offsetLeft - 5,
+ y: child_node.offsetTop + child_node.offsetHeight / 2
+ };
+
+ let connector =
+ "M" +
+ (pos_parent_bottom.x) + "," + (pos_parent_bottom.y) + " " +
+ "L" +
+ (pos_parent_bottom.x) + "," + (pos_child_left.y) + " " +
+ "L" +
+ (pos_child_left.x) + "," + (pos_child_left.y);
+
+ return connector;
+ }
+
+ get_connector_for_collapsed_node(parent_node, child_node) {
+ // we need to connect the bottom left of the parent to the top left of the child node
+ let pos_parent_bottom = {
+ x: parent_node.offsetLeft + 20,
+ y: parent_node.offsetTop + parent_node.offsetHeight
+ };
+ let pos_child_top = {
+ x: child_node.offsetLeft + 20,
+ y: child_node.offsetTop
+ };
+
+ let connector =
+ "M" +
+ (pos_parent_bottom.x) + "," + (pos_parent_bottom.y) + " " +
+ "L" +
+ (pos_child_top.x) + "," + (pos_child_top.y);
+
+ return connector;
+ }
+
+ set_path_attributes(path, parent_id, child_id) {
+ path.setAttribute("data-parent", parent_id);
+ path.setAttribute("data-child", child_id);
+
+ if ($(`#${parent_id}`).hasClass('active')) {
+ path.setAttribute("class", "active-connector");
+ path.setAttribute("marker-start", "url(#arrowstart-active)");
+ path.setAttribute("marker-end", "url(#arrowhead-active)");
+ } else if ($(`#${parent_id}`).hasClass('active-path')) {
+ path.setAttribute("class", "collapsed-connector");
+ }
+ }
+
set_selected_node(node) {
// remove .active class from the current node
$('.active').removeClass('active');
@@ -669,6 +786,7 @@ class OrgChartMobile {
node_element.click(function() {
if (node_element.is(':visible') && node_element.hasClass('active-path')) {
me.remove_levels_after_node(node);
+ me.remove_orphaned_connectors();
} else {
me.add_node_to_hierarchy(node, true);
me.collapse_node();
@@ -786,4 +904,24 @@ class OrgChartMobile {
level.empty().append(current_node);
}
+
+ remove_orphaned_connectors() {
+ let paths = $('#connectors > path');
+ $.each(paths, (_i, path) => {
+ let parent = $(path).data('parent');
+ let child = $(path).data('child');
+
+ if ($(parent).length || $(child).length)
+ return;
+
+ $(path).remove();
+ })
+ }
+
+ refresh_connectors(node_parent, node_id) {
+ if (!node_parent) return;
+
+ $(`path[data-parent="${node_parent}"]`).remove();
+ this.add_connector(node_parent, node_id);
+ }
}
\ No newline at end of file
diff --git a/erpnext/public/scss/organizational_chart.scss b/erpnext/public/scss/organizational_chart.scss
index 6012c01573..16b8792432 100644
--- a/erpnext/public/scss/organizational_chart.scss
+++ b/erpnext/public/scss/organizational_chart.scss
@@ -199,6 +199,7 @@
#arrows {
position: absolute;
+ overflow: visible;
}
.active-connector {
From e9c6ea077f4d6db5d980c58f2d5da1fadb87164b Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Tue, 29 Jun 2021 18:21:42 +0530
Subject: [PATCH 282/386] fix: don't refresh connections for same node
- remove all connectors while expanding a group node
---
.../organizational_chart/organizational_chart.js | 16 ++++++++++------
1 file changed, 10 insertions(+), 6 deletions(-)
diff --git a/erpnext/hr/page/organizational_chart/organizational_chart.js b/erpnext/hr/page/organizational_chart/organizational_chart.js
index 15334bd4ca..efb367ad44 100644
--- a/erpnext/hr/page/organizational_chart/organizational_chart.js
+++ b/erpnext/hr/page/organizational_chart/organizational_chart.js
@@ -573,6 +573,7 @@ class OrgChartMobile {
}
expand_node(node) {
+ const is_same_node = (this.selected_node && this.selected_node.id === node.id);
this.set_selected_node(node);
this.show_active_path(node);
@@ -582,13 +583,15 @@ class OrgChartMobile {
this.$sibling_group.empty();
}
- // since the previous/parent node collapses, all connections to that node need to be rebuilt
- // rebuild outgoing connections of parent
- this.refresh_connectors(node.parent_id, node.id);
+ if (!is_same_node) {
+ // since the previous/parent node collapses, all connections to that node need to be rebuilt
+ // rebuild outgoing connections of parent
+ this.refresh_connectors(node.parent_id, node.id);
- // rebuild incoming connections of parent
- let grandparent = $(`#${node.parent_id}`).attr('data-parent');
- this.refresh_connectors(grandparent, node.parent_id);
+ // rebuild incoming connections of parent
+ let grandparent = $(`#${node.parent_id}`).attr('data-parent');
+ this.refresh_connectors(grandparent, node.parent_id);
+ }
if (node.expandable && !node.expanded) {
return this.load_children(node);
@@ -884,6 +887,7 @@ class OrgChartMobile {
`);
this.$hierarchy.find('.level').append(node);
+ $(`#connectors`).empty();
this.expand_node(node_object);
}
]);
From 281241dc249799b78e86afb812e02e38bc1456e0 Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Tue, 29 Jun 2021 19:15:08 +0530
Subject: [PATCH 283/386] chore: create separate files for Desktop and Mobile
view and bundle assets
---
.../organizational_chart.js | 930 +-----------------
erpnext/public/build.json | 9 +-
.../hierarchy_chart_desktop.js | 396 ++++++++
.../hierarchy_chart/hierarchy_chart_mobile.js | 513 ++++++++++
.../js/templates}/node_card.html | 0
...tional_chart.scss => hierarchy_chart.scss} | 0
6 files changed, 925 insertions(+), 923 deletions(-)
create mode 100644 erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
create mode 100644 erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
rename erpnext/{hr/page/organizational_chart => public/js/templates}/node_card.html (100%)
rename erpnext/public/scss/{organizational_chart.scss => hierarchy_chart.scss} (100%)
diff --git a/erpnext/hr/page/organizational_chart/organizational_chart.js b/erpnext/hr/page/organizational_chart/organizational_chart.js
index efb367ad44..0fe724c78e 100644
--- a/erpnext/hr/page/organizational_chart/organizational_chart.js
+++ b/erpnext/hr/page/organizational_chart/organizational_chart.js
@@ -5,927 +5,15 @@ frappe.pages['organizational-chart'].on_page_load = function(wrapper) {
single_column: true
});
- // let organizational_chart = undefined;
- // if (frappe.is_mobile()) {
- // organizational_chart = new OrgChartMobile(wrapper);
- // } else {
- // organizational_chart = new OrgChart(wrapper);
- // }
-
- let organizational_chart = new OrgChartMobile(wrapper);
- $(wrapper).bind('show', ()=> {
- organizational_chart.show();
- });
-};
-
-class OrgChart {
-
- constructor(wrapper) {
- this.wrapper = $(wrapper);
- this.page = wrapper.page;
-
- this.page.main.css({
- 'min-height': '300px',
- 'max-height': '600px',
- 'overflow': 'auto',
- 'position': 'relative'
- });
- this.page.main.addClass('frappe-card');
-
- this.nodes = {};
- this.setup_node_class();
- }
-
- setup_node_class() {
- let me = this;
- this.Node = class {
- constructor({
- id, parent, parent_id, image, name, title, expandable, connections, is_root // eslint-disable-line
- }) {
- // to setup values passed via constructor
- $.extend(this, arguments[0]);
-
- this.expanded = 0;
-
- me.nodes[this.id] = this;
- me.make_node_element(this);
- me.setup_node_click_action(this);
- }
- }
- }
-
- make_node_element(node) {
- let node_card = frappe.render_template('node_card', {
- id: node.id,
- name: node.name,
- title: node.title,
- image: node.image,
- parent: node.parent_id,
- connections: node.connections
- });
-
- node.parent.append(node_card);
- node.$link = $(`#${node.id}`);
- }
-
- show() {
- frappe.breadcrumbs.add('HR');
-
- let me = this;
- let company = this.page.add_field({
- fieldtype: 'Link',
- options: 'Company',
- fieldname: 'company',
- placeholder: __('Select Company'),
- default: frappe.defaults.get_default('company'),
- only_select: true,
- reqd: 1,
- change: () => {
- me.company = undefined;
-
- if (company.get_value() && me.company != company.get_value()) {
- me.company = company.get_value();
-
- // svg for connectors
- me.make_svg_markers()
-
- if (me.$hierarchy)
- me.$hierarchy.remove();
-
- // setup hierarchy
- me.$hierarchy = $(
- ``);
-
- me.page.main.append(me.$hierarchy);
- me.render_root_node();
- }
- }
- });
-
- company.refresh();
- $(`[data-fieldname="company"]`).trigger('change');
- }
-
- make_svg_markers() {
- $('#arrows').remove();
-
- this.page.main.prepend(`
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- `);
- }
-
- render_root_node() {
- this.method = 'erpnext.hr.page.organizational_chart.organizational_chart.get_children';
-
- let me = this;
-
- frappe.call({
- method: me.method,
- args: {
- company: me.company
- },
- callback: function(r) {
- if (r.message.length) {
- let data = r.message[0];
-
- let root_node = new me.Node({
- id: data.name,
- parent: me.$hierarchy.find('.root-level'),
- parent_id: undefined,
- image: data.image,
- name: data.employee_name,
- title: data.designation,
- expandable: true,
- connections: data.connections,
- is_root: true,
- });
-
- me.expand_node(root_node);
- }
- }
- })
- }
-
- expand_node(node) {
- let is_sibling = this.selected_node && this.selected_node.parent_id === node.parent_id;
- this.set_selected_node(node);
- this.show_active_path(node);
- this.collapse_previous_level_nodes(node);
-
- // since the previous node collapses, all connections to that node need to be rebuilt
- // if a sibling node is clicked, connections don't need to be rebuilt
- if (!is_sibling) {
- // rebuild outgoing connections
- this.refresh_connectors(node.parent_id);
-
- // rebuild incoming connections
- let grandparent = $(`#${node.parent_id}`).attr('data-parent');
- this.refresh_connectors(grandparent)
- }
-
- if (node.expandable && !node.expanded) {
- return this.load_children(node);
- }
- }
-
- collapse_node() {
- if (this.selected_node.expandable) {
- this.selected_node.$children.hide();
- $(`path[data-parent="${this.selected_node.id}"]`).hide();
- this.selected_node.expanded = false;
- }
- }
-
- show_active_path(node) {
- // mark node parent on active path
- $(`#${node.parent_id}`).addClass('active-path');
- }
-
- load_children(node) {
- frappe.run_serially([
- () => this.get_child_nodes(node.id),
- (child_nodes) => this.render_child_nodes(node, child_nodes)
- ]);
- }
-
- get_child_nodes(node_id) {
- let me = this;
- return new Promise(resolve => {
- frappe.call({
- method: this.method,
- args: {
- parent: node_id,
- company: me.company
- },
- callback: (r) => {
- resolve(r.message);
- }
- });
- });
- }
-
- render_child_nodes(node, child_nodes) {
- const last_level = this.$hierarchy.find('.level:last').index();
- const current_level = $(`#${node.id}`).parent().parent().parent().index();
-
- if (last_level === current_level) {
- this.$hierarchy.append(`
-
- `);
- }
-
- if (!node.$children) {
- node.$children = $('')
- .hide()
- .appendTo(this.$hierarchy.find('.level:last'));
-
- node.$children.empty();
-
- if (child_nodes) {
- $.each(child_nodes, (_i, data) => {
- this.add_node(node, data);
-
- setTimeout(() => {
- this.add_connector(node.id, data.name);
- }, 250);
- });
- }
- }
-
- node.$children.show();
- $(`path[data-parent="${node.id}"]`).show();
- node.expanded = true;
- }
-
- add_node(node, data) {
- var $li = $(' ');
-
- return new this.Node({
- id: data.name,
- parent: $li.appendTo(node.$children),
- parent_id: node.id,
- image: data.image,
- name: data.employee_name,
- title: data.designation,
- expandable: data.expandable,
- connections: data.connections,
- children: undefined
- });
- }
-
- add_connector(parent_id, child_id) {
- let parent_node = document.querySelector(`#${parent_id}`);
- let child_node = document.querySelector(`#${child_id}`);
-
- // variable for the namespace
- const svgns = 'http://www.w3.org/2000/svg';
- let path = document.createElementNS(svgns, 'path');
-
- // we need to connect right side of the parent to the left side of the child node
- let pos_parent_right = {
- x: parent_node.offsetLeft + parent_node.offsetWidth,
- y: parent_node.offsetTop + parent_node.offsetHeight / 2
- };
- let pos_child_left = {
- x: child_node.offsetLeft - 5,
- y: child_node.offsetTop + child_node.offsetHeight / 2
- };
-
- let connector =
- "M" +
- (pos_parent_right.x) + "," + (pos_parent_right.y) + " " +
- "C" +
- (pos_parent_right.x + 100) + "," + (pos_parent_right.y) + " " +
- (pos_child_left.x - 100) + "," + (pos_child_left.y) + " " +
- (pos_child_left.x) + "," + (pos_child_left.y);
-
- path.setAttribute("d", connector);
- path.setAttribute("data-parent", parent_id);
- path.setAttribute("data-child", child_id);
-
- if ($(`#${parent_id}`).hasClass('active')) {
- path.setAttribute("class", "active-connector");
- path.setAttribute("marker-start", "url(#arrowstart-active)");
- path.setAttribute("marker-end", "url(#arrowhead-active)");
- } else if ($(`#${parent_id}`).hasClass('active-path')) {
- path.setAttribute("class", "collapsed-connector");
- path.setAttribute("marker-start", "url(#arrowstart-collapsed)");
- path.setAttribute("marker-end", "url(#arrowhead-collapsed)");
- }
-
- $('#connectors').append(path);
- }
-
- set_selected_node(node) {
- // remove .active class from the current node
- $('.active').removeClass('active');
-
- // add active class to the newly selected node
- this.selected_node = node;
- node.$link.addClass('active');
- }
-
- collapse_previous_level_nodes(node) {
- let node_parent = $(`#${node.parent_id}`);
-
- let previous_level_nodes = node_parent.parent().parent().children('li');
- if (node_parent.parent().hasClass('root-level')) {
- previous_level_nodes = node_parent.parent().children('li');
- }
-
- let node_card = undefined;
-
- previous_level_nodes.each(function() {
- node_card = $(this).find('.node-card');
-
- if (!node_card.hasClass('active-path')) {
- node_card.addClass('collapsed');
- }
- });
- }
-
- refresh_connectors(node_parent) {
- if (!node_parent) return;
-
- $(`path[data-parent="${node_parent}"]`).remove();
-
- frappe.run_serially([
- () => this.get_child_nodes(node_parent),
- (child_nodes) => {
- if (child_nodes) {
- $.each(child_nodes, (_i, data) => {
- this.add_connector(node_parent, data.name);
- });
- }
- }
- ]);
- }
-
- setup_node_click_action(node) {
- let me = this;
- let node_element = $(`#${node.id}`);
-
- node_element.click(function() {
- let is_sibling = me.selected_node.parent_id === node.parent_id;
-
- if (is_sibling) {
- me.collapse_node();
- } else if (node_element.is(':visible')
- && (node_element.hasClass('collapsed') || node_element.hasClass('active-path'))) {
- me.remove_levels_after_node(node);
- me.remove_orphaned_connectors();
- }
-
- me.expand_node(node);
- });
- }
-
- remove_levels_after_node(node) {
- let level = $(`#${node.id}`).parent().parent().parent();
-
- if ($(`#${node.id}`).parent().hasClass('root-level')) {
- level = $(`#${node.id}`).parent();
- }
-
- level = $('.hierarchy > li:eq('+ level.index() + ')');
- level.nextAll('li').remove();
-
- let nodes = level.find('.node-card');
- let node_object = undefined;
-
- $.each(nodes, (_i, element) => {
- node_object = this.nodes[element.id];
- node_object.expanded = 0;
- node_object.$children = undefined;
- });
-
- nodes.removeClass('collapsed active-path');
- }
-
- remove_orphaned_connectors() {
- let paths = $('#connectors > path');
- $.each(paths, (_i, path) => {
- let parent = $(path).data('parent');
- let child = $(path).data('child');
-
- if ($(parent).length || $(child).length)
- return;
-
- $(path).remove();
- })
- }
-}
-
-
-class OrgChartMobile {
-
- constructor(wrapper) {
- this.wrapper = $(wrapper);
- this.page = wrapper.page;
-
- this.page.main.css({
- 'min-height': '300px',
- 'max-height': '600px',
- 'overflow': 'auto',
- 'position': 'relative'
- });
- this.page.main.addClass('frappe-card');
-
- this.nodes = {};
- this.setup_node_class();
- }
-
- setup_node_class() {
- let me = this;
- this.Node = class {
- constructor({
- id, parent, parent_id, image, name, title, expandable, connections, is_root // eslint-disable-line
- }) {
- // to setup values passed via constructor
- $.extend(this, arguments[0]);
-
- this.expanded = 0;
-
- me.nodes[this.id] = this;
- me.make_node_element(this);
- me.setup_node_click_action(this);
- }
- }
- }
-
- make_node_element(node) {
- let node_card = frappe.render_template('node_card', {
- id: node.id,
- name: node.name,
- title: node.title,
- image: node.image,
- parent: node.parent_id,
- connections: node.connections,
- is_mobile: 1
- });
-
- node.parent.append(node_card);
- node.$link = $(`#${node.id}`);
- node.$link.addClass('mobile-node');
- }
-
- show() {
- frappe.breadcrumbs.add('HR');
-
- let me = this;
- let company = this.page.add_field({
- fieldtype: 'Link',
- options: 'Company',
- fieldname: 'company',
- placeholder: __('Select Company'),
- default: frappe.defaults.get_default('company'),
- only_select: true,
- reqd: 1,
- change: () => {
- me.company = undefined;
-
- if (company.get_value() && me.company != company.get_value()) {
- me.company = company.get_value();
-
- // svg for connectors
- me.make_svg_markers()
-
- if (me.$sibling_group)
- me.$sibling_group.remove();
-
- // setup sibling group wrapper
- me.$sibling_group = $(`
`);
- me.page.main.append(me.$sibling_group);
-
- if (me.$hierarchy)
- me.$hierarchy.remove();
-
- // setup hierarchy
- me.$hierarchy = $(
- ``);
-
- me.page.main.append(me.$hierarchy);
- me.render_root_node();
- }
- }
- });
-
- company.refresh();
- $(`[data-fieldname="company"]`).trigger('change');
- }
-
- make_svg_markers() {
- $('#arrows').remove();
-
- this.page.main.prepend(`
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- `);
- }
-
- render_root_node() {
- this.method = 'erpnext.hr.page.organizational_chart.organizational_chart.get_children';
-
- let me = this;
-
- frappe.call({
- method: me.method,
- args: {
- company: me.company
- },
- callback: function(r) {
- if (r.message.length) {
- let data = r.message[0];
-
- let root_node = new me.Node({
- id: data.name,
- parent: me.$hierarchy.find('.root-level'),
- parent_id: undefined,
- image: data.image,
- name: data.employee_name,
- title: data.designation,
- expandable: true,
- connections: data.connections,
- is_root: true,
- });
-
- me.expand_node(root_node);
- }
- }
- })
- }
-
- expand_node(node) {
- const is_same_node = (this.selected_node && this.selected_node.id === node.id);
- this.set_selected_node(node);
- this.show_active_path(node);
-
- if (this.$sibling_group) {
- const sibling_parent = this.$sibling_group.find('.node-group').attr('data-parent');
- if (node.parent_id !== sibling_parent)
- this.$sibling_group.empty();
- }
-
- if (!is_same_node) {
- // since the previous/parent node collapses, all connections to that node need to be rebuilt
- // rebuild outgoing connections of parent
- this.refresh_connectors(node.parent_id, node.id);
-
- // rebuild incoming connections of parent
- let grandparent = $(`#${node.parent_id}`).attr('data-parent');
- this.refresh_connectors(grandparent, node.parent_id);
- }
-
- if (node.expandable && !node.expanded) {
- return this.load_children(node);
- }
- }
-
- collapse_node() {
- let node = this.selected_node;
- if (node.expandable) {
- node.$children.hide();
- node.expanded = false;
-
- // add a collapsed level to show the collapsed parent
- // and a button beside it to move to that level
- let node_parent = node.$link.parent();
- node_parent.prepend(
- `
`
- );
-
- node_parent
- .find('.collapsed-level')
- .append(node.$link);
-
- frappe.run_serially([
- () => this.get_child_nodes(node.parent_id, node.id),
- (child_nodes) => this.get_node_group(child_nodes, node.parent_id),
- (node_group) => {
- node_parent.find('.collapsed-level')
- .append(node_group);
- },
- () => this.setup_node_group_action()
- ]);
- }
- }
-
- show_active_path(node) {
- // mark node parent on active path
- $(`#${node.parent_id}`).addClass('active-path');
- }
-
- load_children(node) {
- frappe.run_serially([
- () => this.get_child_nodes(node.id),
- (child_nodes) => this.render_child_nodes(node, child_nodes)
- ]);
- }
-
- get_child_nodes(node_id, exclude_node=null) {
- let me = this;
- return new Promise(resolve => {
- frappe.call({
- method: this.method,
- args: {
- parent: node_id,
- company: me.company,
- exclude_node: exclude_node
- },
- callback: (r) => {
- resolve(r.message);
- }
- });
- });
- }
-
- render_child_nodes(node, child_nodes) {
- if (!node.$children) {
- node.$children = $('')
- .hide()
- .appendTo(node.$link.parent());
-
- node.$children.empty();
-
- if (child_nodes) {
- $.each(child_nodes, (_i, data) => {
- this.add_node(node, data);
- $(`#${data.name}`).addClass('active-child');
-
- setTimeout(() => {
- this.add_connector(node.id, data.name);
- }, 250);
- });
- }
- }
-
- node.$children.show();
- node.expanded = true;
- }
-
- add_node(node, data) {
- var $li = $(' ');
-
- return new this.Node({
- id: data.name,
- parent: $li.appendTo(node.$children),
- parent_id: node.id,
- image: data.image,
- name: data.employee_name,
- title: data.designation,
- expandable: data.expandable,
- connections: data.connections,
- children: undefined
- });
- }
-
- add_connector(parent_id, child_id) {
- let parent_node = document.querySelector(`#${parent_id}`);
- let child_node = document.querySelector(`#${child_id}`);
-
- // variable for the namespace
- const svgns = 'http://www.w3.org/2000/svg';
- let path = document.createElementNS(svgns, 'path');
-
- let connector = undefined;
-
- if ($(`#${parent_id}`).hasClass('active')) {
- connector = this.get_connector_for_active_node(parent_node, child_node);
- } else if ($(`#${parent_id}`).hasClass('active-path')) {
- connector = this.get_connector_for_collapsed_node(parent_node, child_node);
- }
-
- path.setAttribute("d", connector);
- this.set_path_attributes(path, parent_id, child_id);
-
- $('#connectors').append(path);
- }
-
- get_connector_for_active_node(parent_node, child_node) {
- // we need to connect the bottom left of the parent to the left side of the child node
- let pos_parent_bottom = {
- x: parent_node.offsetLeft + 20,
- y: parent_node.offsetTop + parent_node.offsetHeight
- };
- let pos_child_left = {
- x: child_node.offsetLeft - 5,
- y: child_node.offsetTop + child_node.offsetHeight / 2
- };
-
- let connector =
- "M" +
- (pos_parent_bottom.x) + "," + (pos_parent_bottom.y) + " " +
- "L" +
- (pos_parent_bottom.x) + "," + (pos_child_left.y) + " " +
- "L" +
- (pos_child_left.x) + "," + (pos_child_left.y);
-
- return connector;
- }
-
- get_connector_for_collapsed_node(parent_node, child_node) {
- // we need to connect the bottom left of the parent to the top left of the child node
- let pos_parent_bottom = {
- x: parent_node.offsetLeft + 20,
- y: parent_node.offsetTop + parent_node.offsetHeight
- };
- let pos_child_top = {
- x: child_node.offsetLeft + 20,
- y: child_node.offsetTop
- };
-
- let connector =
- "M" +
- (pos_parent_bottom.x) + "," + (pos_parent_bottom.y) + " " +
- "L" +
- (pos_child_top.x) + "," + (pos_child_top.y);
-
- return connector;
- }
-
- set_path_attributes(path, parent_id, child_id) {
- path.setAttribute("data-parent", parent_id);
- path.setAttribute("data-child", child_id);
-
- if ($(`#${parent_id}`).hasClass('active')) {
- path.setAttribute("class", "active-connector");
- path.setAttribute("marker-start", "url(#arrowstart-active)");
- path.setAttribute("marker-end", "url(#arrowhead-active)");
- } else if ($(`#${parent_id}`).hasClass('active-path')) {
- path.setAttribute("class", "collapsed-connector");
- }
- }
-
- set_selected_node(node) {
- // remove .active class from the current node
- $('.active').removeClass('active');
-
- // add active class to the newly selected node
- this.selected_node = node;
- node.$link.addClass('active');
- }
-
- setup_node_click_action(node) {
- let me = this;
- let node_element = $(`#${node.id}`);
-
- node_element.click(function() {
- if (node_element.is(':visible') && node_element.hasClass('active-path')) {
- me.remove_levels_after_node(node);
- me.remove_orphaned_connectors();
+ $(wrapper).bind('show', () => {
+ frappe.require('/assets/js/hierarchy-chart.min.js', () => {
+ let organizational_chart = undefined;
+ if (frappe.is_mobile()) {
+ organizational_chart = new erpnext.HierarchyChartMobile(wrapper);
} else {
- me.add_node_to_hierarchy(node, true);
- me.collapse_node();
+ organizational_chart = new erpnext.HierarchyChart(wrapper);
}
-
- me.expand_node(node);
+ organizational_chart.show();
});
- }
-
- setup_node_group_action() {
- let me = this;
-
- $('.node-group').on('click', function() {
- let parent = $(this).attr('data-parent');
- me.expand_sibling_group_node(parent);
- });
- }
-
- add_node_to_hierarchy(node) {
- this.$hierarchy.append(`
-
-
-
-
- `);
-
- node.$link.appendTo(this.$hierarchy.find('.level:last'));
- }
-
- get_node_group(nodes, parent, collapsed=true) {
- let limit = 2;
- const display_nodes = nodes.slice(0, limit);
- const extra_nodes = nodes.slice(limit);
-
- let html = display_nodes.map(node =>
- this.get_avatar(node)
- ).join('');
-
- if (extra_nodes.length === 1) {
- let node = extra_nodes[0];
- html += this.get_avatar(node);
- } else if (extra_nodes.length > 1) {
- html = `
- ${html}
-
-
- +${extra_nodes.length}
-
-
- `;
- }
-
- if (html) {
- const $node_group =
- $(``);
-
- if (collapsed)
- $node_group.addClass('collapsed');
-
- return $node_group;
- }
-
- return null;
- }
-
- get_avatar(node) {
- return `
-
- `
- }
-
- expand_sibling_group_node(parent) {
- let node_object = this.nodes[parent];
- let node = node_object.$link;
- node.removeClass('active-child active-path');
- node_object.expanded = 0;
- node_object.$children = undefined;
-
- // show parent's siblings and expand parent node
- frappe.run_serially([
- () => this.get_child_nodes(node_object.parent_id, node_object.id),
- (child_nodes) => this.get_node_group(child_nodes, node_object.parent_id, false),
- (node_group) => {
- if (node_group)
- this.$sibling_group.empty().append(node_group);
- },
- () => this.setup_node_group_action(),
- () => {
- this.$hierarchy.empty().append(`
-
- `);
- this.$hierarchy.find('.level').append(node);
- $(`#connectors`).empty();
- this.expand_node(node_object);
- }
- ]);
- }
-
- remove_levels_after_node(node) {
- let level = $(`#${node.id}`).parent().parent();
-
- level = $('.hierarchy-mobile > li:eq('+ (level.index()) + ')');
- level.nextAll('li').remove();
-
- let current_node = level.find(`#${node.id}`);
- let node_object = this.nodes[node.id];
-
- current_node.removeClass('active-child active-path');
- node_object.expanded = 0;
- node_object.$children = undefined;
-
- level.empty().append(current_node);
- }
-
- remove_orphaned_connectors() {
- let paths = $('#connectors > path');
- $.each(paths, (_i, path) => {
- let parent = $(path).data('parent');
- let child = $(path).data('child');
-
- if ($(parent).length || $(child).length)
- return;
-
- $(path).remove();
- })
- }
-
- refresh_connectors(node_parent, node_id) {
- if (!node_parent) return;
-
- $(`path[data-parent="${node_parent}"]`).remove();
- this.add_connector(node_parent, node_id);
- }
-}
\ No newline at end of file
+ });
+};
\ No newline at end of file
diff --git a/erpnext/public/build.json b/erpnext/public/build.json
index d3ebcdf7e7..3c60e3ee50 100644
--- a/erpnext/public/build.json
+++ b/erpnext/public/build.json
@@ -4,7 +4,7 @@
"public/less/hub.less",
"public/scss/call_popup.scss",
"public/scss/point-of-sale.scss",
- "public/scss/organizational_chart.scss"
+ "public/scss/hierarchy_chart.scss"
],
"css/marketplace.css": [
"public/less/hub.less"
@@ -44,7 +44,8 @@
"public/js/call_popup/call_popup.js",
"public/js/utils/dimension_tree_filter.js",
"public/js/telephony.js",
- "public/js/templates/call_link.html"
+ "public/js/templates/call_link.html",
+ "public/js/templates/node_card.html"
],
"js/item-dashboard.min.js": [
"stock/dashboard/item_dashboard.html",
@@ -67,5 +68,9 @@
"public/js/bank_reconciliation_tool/data_table_manager.js",
"public/js/bank_reconciliation_tool/number_card.js",
"public/js/bank_reconciliation_tool/dialog_manager.js"
+ ],
+ "js/hierarchy-chart.min.js": [
+ "public/js/hierarchy_chart/hierarchy_chart_desktop.js",
+ "public/js/hierarchy_chart/hierarchy_chart_mobile.js"
]
}
diff --git a/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js b/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
new file mode 100644
index 0000000000..fd84d4ea5c
--- /dev/null
+++ b/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
@@ -0,0 +1,396 @@
+erpnext.HierarchyChart = class {
+
+ constructor(wrapper) {
+ this.wrapper = $(wrapper);
+ this.page = wrapper.page;
+
+ this.page.main.css({
+ 'min-height': '300px',
+ 'max-height': '600px',
+ 'overflow': 'auto',
+ 'position': 'relative'
+ });
+ this.page.main.addClass('frappe-card');
+
+ this.nodes = {};
+ this.setup_node_class();
+ }
+
+ setup_node_class() {
+ let me = this;
+ this.Node = class {
+ constructor({
+ id, parent, parent_id, image, name, title, expandable, connections, is_root // eslint-disable-line
+ }) {
+ // to setup values passed via constructor
+ $.extend(this, arguments[0]);
+
+ this.expanded = 0;
+
+ me.nodes[this.id] = this;
+ me.make_node_element(this);
+ me.setup_node_click_action(this);
+ }
+ }
+ }
+
+ make_node_element(node) {
+ let node_card = frappe.render_template('node_card', {
+ id: node.id,
+ name: node.name,
+ title: node.title,
+ image: node.image,
+ parent: node.parent_id,
+ connections: node.connections
+ });
+
+ node.parent.append(node_card);
+ node.$link = $(`#${node.id}`);
+ }
+
+ show() {
+ frappe.breadcrumbs.add('HR');
+
+ let me = this;
+ let company = this.page.add_field({
+ fieldtype: 'Link',
+ options: 'Company',
+ fieldname: 'company',
+ placeholder: __('Select Company'),
+ default: frappe.defaults.get_default('company'),
+ only_select: true,
+ reqd: 1,
+ change: () => {
+ me.company = undefined;
+
+ if (company.get_value() && me.company != company.get_value()) {
+ me.company = company.get_value();
+
+ // svg for connectors
+ me.make_svg_markers()
+
+ if (me.$hierarchy)
+ me.$hierarchy.remove();
+
+ // setup hierarchy
+ me.$hierarchy = $(
+ ``);
+
+ me.page.main.append(me.$hierarchy);
+ me.render_root_node();
+ }
+ }
+ });
+
+ company.refresh();
+ $(`[data-fieldname="company"]`).trigger('change');
+ }
+
+ make_svg_markers() {
+ $('#arrows').remove();
+
+ this.page.main.prepend(`
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `);
+ }
+
+ render_root_node() {
+ this.method = 'erpnext.hr.page.organizational_chart.organizational_chart.get_children';
+
+ let me = this;
+
+ frappe.call({
+ method: me.method,
+ args: {
+ company: me.company
+ },
+ callback: function(r) {
+ if (r.message.length) {
+ let data = r.message[0];
+
+ let root_node = new me.Node({
+ id: data.name,
+ parent: me.$hierarchy.find('.root-level'),
+ parent_id: undefined,
+ image: data.image,
+ name: data.employee_name,
+ title: data.designation,
+ expandable: true,
+ connections: data.connections,
+ is_root: true,
+ });
+
+ me.expand_node(root_node);
+ }
+ }
+ })
+ }
+
+ expand_node(node) {
+ let is_sibling = this.selected_node && this.selected_node.parent_id === node.parent_id;
+ this.set_selected_node(node);
+ this.show_active_path(node);
+ this.collapse_previous_level_nodes(node);
+
+ // since the previous node collapses, all connections to that node need to be rebuilt
+ // if a sibling node is clicked, connections don't need to be rebuilt
+ if (!is_sibling) {
+ // rebuild outgoing connections
+ this.refresh_connectors(node.parent_id);
+
+ // rebuild incoming connections
+ let grandparent = $(`#${node.parent_id}`).attr('data-parent');
+ this.refresh_connectors(grandparent)
+ }
+
+ if (node.expandable && !node.expanded) {
+ return this.load_children(node);
+ }
+ }
+
+ collapse_node() {
+ if (this.selected_node.expandable) {
+ this.selected_node.$children.hide();
+ $(`path[data-parent="${this.selected_node.id}"]`).hide();
+ this.selected_node.expanded = false;
+ }
+ }
+
+ show_active_path(node) {
+ // mark node parent on active path
+ $(`#${node.parent_id}`).addClass('active-path');
+ }
+
+ load_children(node) {
+ frappe.run_serially([
+ () => this.get_child_nodes(node.id),
+ (child_nodes) => this.render_child_nodes(node, child_nodes)
+ ]);
+ }
+
+ get_child_nodes(node_id) {
+ let me = this;
+ return new Promise(resolve => {
+ frappe.call({
+ method: this.method,
+ args: {
+ parent: node_id,
+ company: me.company
+ },
+ callback: (r) => {
+ resolve(r.message);
+ }
+ });
+ });
+ }
+
+ render_child_nodes(node, child_nodes) {
+ const last_level = this.$hierarchy.find('.level:last').index();
+ const current_level = $(`#${node.id}`).parent().parent().parent().index();
+
+ if (last_level === current_level) {
+ this.$hierarchy.append(`
+
+ `);
+ }
+
+ if (!node.$children) {
+ node.$children = $('')
+ .hide()
+ .appendTo(this.$hierarchy.find('.level:last'));
+
+ node.$children.empty();
+
+ if (child_nodes) {
+ $.each(child_nodes, (_i, data) => {
+ this.add_node(node, data);
+
+ setTimeout(() => {
+ this.add_connector(node.id, data.name);
+ }, 250);
+ });
+ }
+ }
+
+ node.$children.show();
+ $(`path[data-parent="${node.id}"]`).show();
+ node.expanded = true;
+ }
+
+ add_node(node, data) {
+ var $li = $(' ');
+
+ return new this.Node({
+ id: data.name,
+ parent: $li.appendTo(node.$children),
+ parent_id: node.id,
+ image: data.image,
+ name: data.employee_name,
+ title: data.designation,
+ expandable: data.expandable,
+ connections: data.connections,
+ children: undefined
+ });
+ }
+
+ add_connector(parent_id, child_id) {
+ let parent_node = document.querySelector(`#${parent_id}`);
+ let child_node = document.querySelector(`#${child_id}`);
+
+ // variable for the namespace
+ const svgns = 'http://www.w3.org/2000/svg';
+ let path = document.createElementNS(svgns, 'path');
+
+ // we need to connect right side of the parent to the left side of the child node
+ let pos_parent_right = {
+ x: parent_node.offsetLeft + parent_node.offsetWidth,
+ y: parent_node.offsetTop + parent_node.offsetHeight / 2
+ };
+ let pos_child_left = {
+ x: child_node.offsetLeft - 5,
+ y: child_node.offsetTop + child_node.offsetHeight / 2
+ };
+
+ let connector =
+ "M" +
+ (pos_parent_right.x) + "," + (pos_parent_right.y) + " " +
+ "C" +
+ (pos_parent_right.x + 100) + "," + (pos_parent_right.y) + " " +
+ (pos_child_left.x - 100) + "," + (pos_child_left.y) + " " +
+ (pos_child_left.x) + "," + (pos_child_left.y);
+
+ path.setAttribute("d", connector);
+ path.setAttribute("data-parent", parent_id);
+ path.setAttribute("data-child", child_id);
+
+ if ($(`#${parent_id}`).hasClass('active')) {
+ path.setAttribute("class", "active-connector");
+ path.setAttribute("marker-start", "url(#arrowstart-active)");
+ path.setAttribute("marker-end", "url(#arrowhead-active)");
+ } else if ($(`#${parent_id}`).hasClass('active-path')) {
+ path.setAttribute("class", "collapsed-connector");
+ path.setAttribute("marker-start", "url(#arrowstart-collapsed)");
+ path.setAttribute("marker-end", "url(#arrowhead-collapsed)");
+ }
+
+ $('#connectors').append(path);
+ }
+
+ set_selected_node(node) {
+ // remove .active class from the current node
+ $('.active').removeClass('active');
+
+ // add active class to the newly selected node
+ this.selected_node = node;
+ node.$link.addClass('active');
+ }
+
+ collapse_previous_level_nodes(node) {
+ let node_parent = $(`#${node.parent_id}`);
+
+ let previous_level_nodes = node_parent.parent().parent().children('li');
+ if (node_parent.parent().hasClass('root-level')) {
+ previous_level_nodes = node_parent.parent().children('li');
+ }
+
+ let node_card = undefined;
+
+ previous_level_nodes.each(function() {
+ node_card = $(this).find('.node-card');
+
+ if (!node_card.hasClass('active-path')) {
+ node_card.addClass('collapsed');
+ }
+ });
+ }
+
+ refresh_connectors(node_parent) {
+ if (!node_parent) return;
+
+ $(`path[data-parent="${node_parent}"]`).remove();
+
+ frappe.run_serially([
+ () => this.get_child_nodes(node_parent),
+ (child_nodes) => {
+ if (child_nodes) {
+ $.each(child_nodes, (_i, data) => {
+ this.add_connector(node_parent, data.name);
+ });
+ }
+ }
+ ]);
+ }
+
+ setup_node_click_action(node) {
+ let me = this;
+ let node_element = $(`#${node.id}`);
+
+ node_element.click(function() {
+ let is_sibling = me.selected_node.parent_id === node.parent_id;
+
+ if (is_sibling) {
+ me.collapse_node();
+ } else if (node_element.is(':visible')
+ && (node_element.hasClass('collapsed') || node_element.hasClass('active-path'))) {
+ me.remove_levels_after_node(node);
+ me.remove_orphaned_connectors();
+ }
+
+ me.expand_node(node);
+ });
+ }
+
+ remove_levels_after_node(node) {
+ let level = $(`#${node.id}`).parent().parent().parent();
+
+ if ($(`#${node.id}`).parent().hasClass('root-level')) {
+ level = $(`#${node.id}`).parent();
+ }
+
+ level = $('.hierarchy > li:eq('+ level.index() + ')');
+ level.nextAll('li').remove();
+
+ let nodes = level.find('.node-card');
+ let node_object = undefined;
+
+ $.each(nodes, (_i, element) => {
+ node_object = this.nodes[element.id];
+ node_object.expanded = 0;
+ node_object.$children = undefined;
+ });
+
+ nodes.removeClass('collapsed active-path');
+ }
+
+ remove_orphaned_connectors() {
+ let paths = $('#connectors > path');
+ $.each(paths, (_i, path) => {
+ let parent = $(path).data('parent');
+ let child = $(path).data('child');
+
+ if ($(parent).length || $(child).length)
+ return;
+
+ $(path).remove();
+ })
+ }
+}
\ No newline at end of file
diff --git a/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js b/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
new file mode 100644
index 0000000000..c705681438
--- /dev/null
+++ b/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
@@ -0,0 +1,513 @@
+erpnext.HierarchyChartMobile = class {
+
+ constructor(wrapper) {
+ this.wrapper = $(wrapper);
+ this.page = wrapper.page;
+
+ this.page.main.css({
+ 'min-height': '300px',
+ 'max-height': '600px',
+ 'overflow': 'auto',
+ 'position': 'relative'
+ });
+ this.page.main.addClass('frappe-card');
+
+ this.nodes = {};
+ this.setup_node_class();
+ }
+
+ setup_node_class() {
+ let me = this;
+ this.Node = class {
+ constructor({
+ id, parent, parent_id, image, name, title, expandable, connections, is_root // eslint-disable-line
+ }) {
+ // to setup values passed via constructor
+ $.extend(this, arguments[0]);
+
+ this.expanded = 0;
+
+ me.nodes[this.id] = this;
+ me.make_node_element(this);
+ me.setup_node_click_action(this);
+ }
+ }
+ }
+
+ make_node_element(node) {
+ let node_card = frappe.render_template('node_card', {
+ id: node.id,
+ name: node.name,
+ title: node.title,
+ image: node.image,
+ parent: node.parent_id,
+ connections: node.connections,
+ is_mobile: 1
+ });
+
+ node.parent.append(node_card);
+ node.$link = $(`#${node.id}`);
+ node.$link.addClass('mobile-node');
+ }
+
+ show() {
+ frappe.breadcrumbs.add('HR');
+
+ let me = this;
+ let company = this.page.add_field({
+ fieldtype: 'Link',
+ options: 'Company',
+ fieldname: 'company',
+ placeholder: __('Select Company'),
+ default: frappe.defaults.get_default('company'),
+ only_select: true,
+ reqd: 1,
+ change: () => {
+ me.company = undefined;
+
+ if (company.get_value() && me.company != company.get_value()) {
+ me.company = company.get_value();
+
+ // svg for connectors
+ me.make_svg_markers()
+
+ if (me.$sibling_group)
+ me.$sibling_group.remove();
+
+ // setup sibling group wrapper
+ me.$sibling_group = $(`
`);
+ me.page.main.append(me.$sibling_group);
+
+ if (me.$hierarchy)
+ me.$hierarchy.remove();
+
+ // setup hierarchy
+ me.$hierarchy = $(
+ ``);
+
+ me.page.main.append(me.$hierarchy);
+ me.render_root_node();
+ }
+ }
+ });
+
+ company.refresh();
+ $(`[data-fieldname="company"]`).trigger('change');
+ }
+
+ make_svg_markers() {
+ $('#arrows').remove();
+
+ this.page.main.prepend(`
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `);
+ }
+
+ render_root_node() {
+ this.method = 'erpnext.hr.page.organizational_chart.organizational_chart.get_children';
+
+ let me = this;
+
+ frappe.call({
+ method: me.method,
+ args: {
+ company: me.company
+ },
+ callback: function(r) {
+ if (r.message.length) {
+ let data = r.message[0];
+
+ let root_node = new me.Node({
+ id: data.name,
+ parent: me.$hierarchy.find('.root-level'),
+ parent_id: undefined,
+ image: data.image,
+ name: data.employee_name,
+ title: data.designation,
+ expandable: true,
+ connections: data.connections,
+ is_root: true,
+ });
+
+ me.expand_node(root_node);
+ }
+ }
+ })
+ }
+
+ expand_node(node) {
+ const is_same_node = (this.selected_node && this.selected_node.id === node.id);
+ this.set_selected_node(node);
+ this.show_active_path(node);
+
+ if (this.$sibling_group) {
+ const sibling_parent = this.$sibling_group.find('.node-group').attr('data-parent');
+ if (node.parent_id !== sibling_parent)
+ this.$sibling_group.empty();
+ }
+
+ if (!is_same_node) {
+ // since the previous/parent node collapses, all connections to that node need to be rebuilt
+ // rebuild outgoing connections of parent
+ this.refresh_connectors(node.parent_id, node.id);
+
+ // rebuild incoming connections of parent
+ let grandparent = $(`#${node.parent_id}`).attr('data-parent');
+ this.refresh_connectors(grandparent, node.parent_id);
+ }
+
+ if (node.expandable && !node.expanded) {
+ return this.load_children(node);
+ }
+ }
+
+ collapse_node() {
+ let node = this.selected_node;
+ if (node.expandable) {
+ node.$children.hide();
+ node.expanded = false;
+
+ // add a collapsed level to show the collapsed parent
+ // and a button beside it to move to that level
+ let node_parent = node.$link.parent();
+ node_parent.prepend(
+ `
`
+ );
+
+ node_parent
+ .find('.collapsed-level')
+ .append(node.$link);
+
+ frappe.run_serially([
+ () => this.get_child_nodes(node.parent_id, node.id),
+ (child_nodes) => this.get_node_group(child_nodes, node.parent_id),
+ (node_group) => {
+ node_parent.find('.collapsed-level')
+ .append(node_group);
+ },
+ () => this.setup_node_group_action()
+ ]);
+ }
+ }
+
+ show_active_path(node) {
+ // mark node parent on active path
+ $(`#${node.parent_id}`).addClass('active-path');
+ }
+
+ load_children(node) {
+ frappe.run_serially([
+ () => this.get_child_nodes(node.id),
+ (child_nodes) => this.render_child_nodes(node, child_nodes)
+ ]);
+ }
+
+ get_child_nodes(node_id, exclude_node=null) {
+ let me = this;
+ return new Promise(resolve => {
+ frappe.call({
+ method: this.method,
+ args: {
+ parent: node_id,
+ company: me.company,
+ exclude_node: exclude_node
+ },
+ callback: (r) => {
+ resolve(r.message);
+ }
+ });
+ });
+ }
+
+ render_child_nodes(node, child_nodes) {
+ if (!node.$children) {
+ node.$children = $('')
+ .hide()
+ .appendTo(node.$link.parent());
+
+ node.$children.empty();
+
+ if (child_nodes) {
+ $.each(child_nodes, (_i, data) => {
+ this.add_node(node, data);
+ $(`#${data.name}`).addClass('active-child');
+
+ setTimeout(() => {
+ this.add_connector(node.id, data.name);
+ }, 250);
+ });
+ }
+ }
+
+ node.$children.show();
+ node.expanded = true;
+ }
+
+ add_node(node, data) {
+ var $li = $(' ');
+
+ return new this.Node({
+ id: data.name,
+ parent: $li.appendTo(node.$children),
+ parent_id: node.id,
+ image: data.image,
+ name: data.employee_name,
+ title: data.designation,
+ expandable: data.expandable,
+ connections: data.connections,
+ children: undefined
+ });
+ }
+
+ add_connector(parent_id, child_id) {
+ let parent_node = document.querySelector(`#${parent_id}`);
+ let child_node = document.querySelector(`#${child_id}`);
+
+ // variable for the namespace
+ const svgns = 'http://www.w3.org/2000/svg';
+ let path = document.createElementNS(svgns, 'path');
+
+ let connector = undefined;
+
+ if ($(`#${parent_id}`).hasClass('active')) {
+ connector = this.get_connector_for_active_node(parent_node, child_node);
+ } else if ($(`#${parent_id}`).hasClass('active-path')) {
+ connector = this.get_connector_for_collapsed_node(parent_node, child_node);
+ }
+
+ path.setAttribute("d", connector);
+ this.set_path_attributes(path, parent_id, child_id);
+
+ $('#connectors').append(path);
+ }
+
+ get_connector_for_active_node(parent_node, child_node) {
+ // we need to connect the bottom left of the parent to the left side of the child node
+ let pos_parent_bottom = {
+ x: parent_node.offsetLeft + 20,
+ y: parent_node.offsetTop + parent_node.offsetHeight
+ };
+ let pos_child_left = {
+ x: child_node.offsetLeft - 5,
+ y: child_node.offsetTop + child_node.offsetHeight / 2
+ };
+
+ let connector =
+ "M" +
+ (pos_parent_bottom.x) + "," + (pos_parent_bottom.y) + " " +
+ "L" +
+ (pos_parent_bottom.x) + "," + (pos_child_left.y) + " " +
+ "L" +
+ (pos_child_left.x) + "," + (pos_child_left.y);
+
+ return connector;
+ }
+
+ get_connector_for_collapsed_node(parent_node, child_node) {
+ // we need to connect the bottom left of the parent to the top left of the child node
+ let pos_parent_bottom = {
+ x: parent_node.offsetLeft + 20,
+ y: parent_node.offsetTop + parent_node.offsetHeight
+ };
+ let pos_child_top = {
+ x: child_node.offsetLeft + 20,
+ y: child_node.offsetTop
+ };
+
+ let connector =
+ "M" +
+ (pos_parent_bottom.x) + "," + (pos_parent_bottom.y) + " " +
+ "L" +
+ (pos_child_top.x) + "," + (pos_child_top.y);
+
+ return connector;
+ }
+
+ set_path_attributes(path, parent_id, child_id) {
+ path.setAttribute("data-parent", parent_id);
+ path.setAttribute("data-child", child_id);
+
+ if ($(`#${parent_id}`).hasClass('active')) {
+ path.setAttribute("class", "active-connector");
+ path.setAttribute("marker-start", "url(#arrowstart-active)");
+ path.setAttribute("marker-end", "url(#arrowhead-active)");
+ } else if ($(`#${parent_id}`).hasClass('active-path')) {
+ path.setAttribute("class", "collapsed-connector");
+ }
+ }
+
+ set_selected_node(node) {
+ // remove .active class from the current node
+ $('.active').removeClass('active');
+
+ // add active class to the newly selected node
+ this.selected_node = node;
+ node.$link.addClass('active');
+ }
+
+ setup_node_click_action(node) {
+ let me = this;
+ let node_element = $(`#${node.id}`);
+
+ node_element.click(function() {
+ if (node_element.is(':visible') && node_element.hasClass('active-path')) {
+ me.remove_levels_after_node(node);
+ me.remove_orphaned_connectors();
+ } else {
+ me.add_node_to_hierarchy(node, true);
+ me.collapse_node();
+ }
+
+ me.expand_node(node);
+ });
+ }
+
+ setup_node_group_action() {
+ let me = this;
+
+ $('.node-group').on('click', function() {
+ let parent = $(this).attr('data-parent');
+ me.expand_sibling_group_node(parent);
+ });
+ }
+
+ add_node_to_hierarchy(node) {
+ this.$hierarchy.append(`
+
+
+
+
+ `);
+
+ node.$link.appendTo(this.$hierarchy.find('.level:last'));
+ }
+
+ get_node_group(nodes, parent, collapsed=true) {
+ let limit = 2;
+ const display_nodes = nodes.slice(0, limit);
+ const extra_nodes = nodes.slice(limit);
+
+ let html = display_nodes.map(node =>
+ this.get_avatar(node)
+ ).join('');
+
+ if (extra_nodes.length === 1) {
+ let node = extra_nodes[0];
+ html += this.get_avatar(node);
+ } else if (extra_nodes.length > 1) {
+ html = `
+ ${html}
+
+
+ +${extra_nodes.length}
+
+
+ `;
+ }
+
+ if (html) {
+ const $node_group =
+ $(``);
+
+ if (collapsed)
+ $node_group.addClass('collapsed');
+
+ return $node_group;
+ }
+
+ return null;
+ }
+
+ get_avatar(node) {
+ return `
+
+ `
+ }
+
+ expand_sibling_group_node(parent) {
+ let node_object = this.nodes[parent];
+ let node = node_object.$link;
+ node.removeClass('active-child active-path');
+ node_object.expanded = 0;
+ node_object.$children = undefined;
+
+ // show parent's siblings and expand parent node
+ frappe.run_serially([
+ () => this.get_child_nodes(node_object.parent_id, node_object.id),
+ (child_nodes) => this.get_node_group(child_nodes, node_object.parent_id, false),
+ (node_group) => {
+ if (node_group)
+ this.$sibling_group.empty().append(node_group);
+ },
+ () => this.setup_node_group_action(),
+ () => {
+ this.$hierarchy.empty().append(`
+
+ `);
+ this.$hierarchy.find('.level').append(node);
+ $(`#connectors`).empty();
+ this.expand_node(node_object);
+ }
+ ]);
+ }
+
+ remove_levels_after_node(node) {
+ let level = $(`#${node.id}`).parent().parent();
+
+ level = $('.hierarchy-mobile > li:eq('+ (level.index()) + ')');
+ level.nextAll('li').remove();
+
+ let current_node = level.find(`#${node.id}`);
+ let node_object = this.nodes[node.id];
+
+ current_node.removeClass('active-child active-path');
+ node_object.expanded = 0;
+ node_object.$children = undefined;
+
+ level.empty().append(current_node);
+ }
+
+ remove_orphaned_connectors() {
+ let paths = $('#connectors > path');
+ $.each(paths, (_i, path) => {
+ let parent = $(path).data('parent');
+ let child = $(path).data('child');
+
+ if ($(parent).length || $(child).length)
+ return;
+
+ $(path).remove();
+ })
+ }
+
+ refresh_connectors(node_parent, node_id) {
+ if (!node_parent) return;
+
+ $(`path[data-parent="${node_parent}"]`).remove();
+ this.add_connector(node_parent, node_id);
+ }
+}
\ No newline at end of file
diff --git a/erpnext/hr/page/organizational_chart/node_card.html b/erpnext/public/js/templates/node_card.html
similarity index 100%
rename from erpnext/hr/page/organizational_chart/node_card.html
rename to erpnext/public/js/templates/node_card.html
diff --git a/erpnext/public/scss/organizational_chart.scss b/erpnext/public/scss/hierarchy_chart.scss
similarity index 100%
rename from erpnext/public/scss/organizational_chart.scss
rename to erpnext/public/scss/hierarchy_chart.scss
From 249621af1b25ee356dd7337b93461ccacbbad906 Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Tue, 29 Jun 2021 21:26:47 +0530
Subject: [PATCH 284/386] refactor: add options to chart
- method to return the node data
- wrapper for showing the hierarchy
---
.../organizational_chart.js | 6 ++--
.../organizational_chart.py | 6 ++--
.../hierarchy_chart_desktop.js | 28 +++++++++-------
.../hierarchy_chart/hierarchy_chart_mobile.js | 32 +++++++++++--------
4 files changed, 41 insertions(+), 31 deletions(-)
diff --git a/erpnext/hr/page/organizational_chart/organizational_chart.js b/erpnext/hr/page/organizational_chart/organizational_chart.js
index 0fe724c78e..ca9855286c 100644
--- a/erpnext/hr/page/organizational_chart/organizational_chart.js
+++ b/erpnext/hr/page/organizational_chart/organizational_chart.js
@@ -8,10 +8,12 @@ frappe.pages['organizational-chart'].on_page_load = function(wrapper) {
$(wrapper).bind('show', () => {
frappe.require('/assets/js/hierarchy-chart.min.js', () => {
let organizational_chart = undefined;
+ let method = 'erpnext.hr.page.organizational_chart.organizational_chart.get_children';
+
if (frappe.is_mobile()) {
- organizational_chart = new erpnext.HierarchyChartMobile(wrapper);
+ organizational_chart = new erpnext.HierarchyChartMobile(wrapper, method);
} else {
- organizational_chart = new erpnext.HierarchyChart(wrapper);
+ organizational_chart = new erpnext.HierarchyChart(wrapper, method);
}
organizational_chart.show();
});
diff --git a/erpnext/hr/page/organizational_chart/organizational_chart.py b/erpnext/hr/page/organizational_chart/organizational_chart.py
index ae91a919b2..f3aa13897d 100644
--- a/erpnext/hr/page/organizational_chart/organizational_chart.py
+++ b/erpnext/hr/page/organizational_chart/organizational_chart.py
@@ -9,7 +9,7 @@ def get_children(parent=None, company=None, exclude_node=None, is_root=False, is
filters.append(['company', '=', company])
if not fields:
- fields = ['employee_name', 'name', 'reports_to', 'image', 'designation']
+ fields = ['employee_name as name', 'name as id', 'reports_to', 'image', 'designation as title']
if is_root:
parent = ''
@@ -27,9 +27,9 @@ def get_children(parent=None, company=None, exclude_node=None, is_root=False, is
for employee in employees:
is_expandable = frappe.get_all('Employee', filters=[
- ['reports_to', '=', employee.get('name')]
+ ['reports_to', '=', employee.get('id')]
])
- employee.connections = get_connections(employee.name)
+ employee.connections = get_connections(employee.id)
employee.expandable = 1 if is_expandable else 0
return employees
diff --git a/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js b/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
index fd84d4ea5c..052f140c13 100644
--- a/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
+++ b/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
@@ -1,8 +1,14 @@
erpnext.HierarchyChart = class {
-
- constructor(wrapper) {
+ /* Options:
+ - wrapper: wrapper for the hierarchy view
+ - method:
+ - to get the data for each node
+ - this method should return id, name, title, image, and connections for each node
+ */
+ constructor(wrapper, method) {
this.wrapper = $(wrapper);
this.page = wrapper.page;
+ this.method = method;
this.page.main.css({
'min-height': '300px',
@@ -114,8 +120,6 @@ erpnext.HierarchyChart = class {
}
render_root_node() {
- this.method = 'erpnext.hr.page.organizational_chart.organizational_chart.get_children';
-
let me = this;
frappe.call({
@@ -128,12 +132,12 @@ erpnext.HierarchyChart = class {
let data = r.message[0];
let root_node = new me.Node({
- id: data.name,
+ id: data.id,
parent: me.$hierarchy.find('.root-level'),
parent_id: undefined,
image: data.image,
- name: data.employee_name,
- title: data.designation,
+ name: data.name,
+ title: data.title,
expandable: true,
connections: data.connections,
is_root: true,
@@ -225,7 +229,7 @@ erpnext.HierarchyChart = class {
this.add_node(node, data);
setTimeout(() => {
- this.add_connector(node.id, data.name);
+ this.add_connector(node.id, data.id);
}, 250);
});
}
@@ -240,12 +244,12 @@ erpnext.HierarchyChart = class {
var $li = $(' ');
return new this.Node({
- id: data.name,
+ id: data.id,
parent: $li.appendTo(node.$children),
parent_id: node.id,
image: data.image,
- name: data.employee_name,
- title: data.designation,
+ name: data.name,
+ title: data.title,
expandable: data.expandable,
connections: data.connections,
children: undefined
@@ -333,7 +337,7 @@ erpnext.HierarchyChart = class {
(child_nodes) => {
if (child_nodes) {
$.each(child_nodes, (_i, data) => {
- this.add_connector(node_parent, data.name);
+ this.add_connector(node_parent, data.id);
});
}
}
diff --git a/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js b/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
index c705681438..1b8bc2e8e0 100644
--- a/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
+++ b/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
@@ -1,8 +1,14 @@
erpnext.HierarchyChartMobile = class {
-
- constructor(wrapper) {
+ /* Options:
+ - wrapper: wrapper for the hierarchy view
+ - method:
+ - to get the data for each node
+ - this method should return id, name, title, image, and connections for each node
+ */
+ constructor(wrapper, method) {
this.wrapper = $(wrapper);
this.page = wrapper.page;
+ this.method = method;
this.page.main.css({
'min-height': '300px',
@@ -123,8 +129,6 @@ erpnext.HierarchyChartMobile = class {
}
render_root_node() {
- this.method = 'erpnext.hr.page.organizational_chart.organizational_chart.get_children';
-
let me = this;
frappe.call({
@@ -137,12 +141,12 @@ erpnext.HierarchyChartMobile = class {
let data = r.message[0];
let root_node = new me.Node({
- id: data.name,
+ id: data.id,
parent: me.$hierarchy.find('.root-level'),
parent_id: undefined,
image: data.image,
- name: data.employee_name,
- title: data.designation,
+ name: data.name,
+ title: data.title,
expandable: true,
connections: data.connections,
is_root: true,
@@ -249,10 +253,10 @@ erpnext.HierarchyChartMobile = class {
if (child_nodes) {
$.each(child_nodes, (_i, data) => {
this.add_node(node, data);
- $(`#${data.name}`).addClass('active-child');
+ $(`#${data.id}`).addClass('active-child');
setTimeout(() => {
- this.add_connector(node.id, data.name);
+ this.add_connector(node.id, data.id);
}, 250);
});
}
@@ -266,12 +270,12 @@ erpnext.HierarchyChartMobile = class {
var $li = $(' ');
return new this.Node({
- id: data.name,
+ id: data.id,
parent: $li.appendTo(node.$children),
parent_id: node.id,
image: data.image,
- name: data.employee_name,
- title: data.designation,
+ name: data.name,
+ title: data.title,
expandable: data.expandable,
connections: data.connections,
children: undefined
@@ -418,7 +422,7 @@ erpnext.HierarchyChartMobile = class {
${html}
+ title="${extra_nodes.map(node => node.name).join(', ')}">
+${extra_nodes.length}
@@ -443,7 +447,7 @@ erpnext.HierarchyChartMobile = class {
}
get_avatar(node) {
- return `
+ return `
`
}
From aacb649050431472812b2355dff6bab9be458adb Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Tue, 29 Jun 2021 21:51:21 +0530
Subject: [PATCH 285/386] feat: setup node edit action
---
.../organizational_chart/organizational_chart.js | 4 ++--
.../js/hierarchy_chart/hierarchy_chart_desktop.js | 14 +++++++++++++-
.../js/hierarchy_chart/hierarchy_chart_mobile.js | 14 +++++++++++++-
erpnext/public/js/templates/node_card.html | 4 ++--
4 files changed, 30 insertions(+), 6 deletions(-)
diff --git a/erpnext/hr/page/organizational_chart/organizational_chart.js b/erpnext/hr/page/organizational_chart/organizational_chart.js
index ca9855286c..a138886768 100644
--- a/erpnext/hr/page/organizational_chart/organizational_chart.js
+++ b/erpnext/hr/page/organizational_chart/organizational_chart.js
@@ -11,9 +11,9 @@ frappe.pages['organizational-chart'].on_page_load = function(wrapper) {
let method = 'erpnext.hr.page.organizational_chart.organizational_chart.get_children';
if (frappe.is_mobile()) {
- organizational_chart = new erpnext.HierarchyChartMobile(wrapper, method);
+ organizational_chart = new erpnext.HierarchyChartMobile('Employee', wrapper, method);
} else {
- organizational_chart = new erpnext.HierarchyChart(wrapper, method);
+ organizational_chart = new erpnext.HierarchyChart('Employee', wrapper, method);
}
organizational_chart.show();
});
diff --git a/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js b/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
index 052f140c13..0823ec77a8 100644
--- a/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
+++ b/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
@@ -1,14 +1,16 @@
erpnext.HierarchyChart = class {
/* Options:
+ - doctype
- wrapper: wrapper for the hierarchy view
- method:
- to get the data for each node
- this method should return id, name, title, image, and connections for each node
*/
- constructor(wrapper, method) {
+ constructor(doctype, wrapper, method) {
this.wrapper = $(wrapper);
this.page = wrapper.page;
this.method = method;
+ this.doctype = doctype;
this.page.main.css({
'min-height': '300px',
@@ -36,6 +38,7 @@ erpnext.HierarchyChart = class {
me.nodes[this.id] = this;
me.make_node_element(this);
me.setup_node_click_action(this);
+ me.setup_edit_node_action(this);
}
}
}
@@ -363,6 +366,15 @@ erpnext.HierarchyChart = class {
});
}
+ setup_edit_node_action(node) {
+ let node_element = $(`#${node.id}`);
+ let me = this;
+
+ node_element.find('.btn-edit-node').click(function() {
+ frappe.set_route('Form', me.doctype, node.id);
+ });
+ }
+
remove_levels_after_node(node) {
let level = $(`#${node.id}`).parent().parent().parent();
diff --git a/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js b/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
index 1b8bc2e8e0..4b09714d0a 100644
--- a/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
+++ b/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
@@ -1,14 +1,16 @@
erpnext.HierarchyChartMobile = class {
/* Options:
+ - doctype
- wrapper: wrapper for the hierarchy view
- method:
- to get the data for each node
- this method should return id, name, title, image, and connections for each node
*/
- constructor(wrapper, method) {
+ constructor(doctype, wrapper, method) {
this.wrapper = $(wrapper);
this.page = wrapper.page;
this.method = method;
+ this.doctype = doctype
this.page.main.css({
'min-height': '300px',
@@ -36,6 +38,7 @@ erpnext.HierarchyChartMobile = class {
me.nodes[this.id] = this;
me.make_node_element(this);
me.setup_node_click_action(this);
+ me.setup_edit_node_action(this);
}
}
}
@@ -385,6 +388,15 @@ erpnext.HierarchyChartMobile = class {
});
}
+ setup_edit_node_action(node) {
+ let node_element = $(`#${node.id}`);
+ let me = this;
+
+ node_element.find('.btn-edit-node').click(function() {
+ frappe.set_route('Form', me.doctype, node.id);
+ });
+ }
+
setup_node_group_action() {
let me = this;
diff --git a/erpnext/public/js/templates/node_card.html b/erpnext/public/js/templates/node_card.html
index e42e54f690..30aedab4bb 100644
--- a/erpnext/public/js/templates/node_card.html
+++ b/erpnext/public/js/templates/node_card.html
@@ -17,9 +17,9 @@
{{ title }}
{% if connections == 1 %}
- · {{ connections }}
+ · {{ connections }} Connection
{% else %}
- · {{ connections }}
+ · {{ connections }} Connections
{% endif %}
From e179cd9841fa26727edbc534a7a0cd2a7378893b Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Tue, 29 Jun 2021 21:57:27 +0530
Subject: [PATCH 286/386] fix: revert changes in employee descendants query
---
erpnext/hr/doctype/employee/employee.py | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/erpnext/hr/doctype/employee/employee.py b/erpnext/hr/doctype/employee/employee.py
index 96046fba81..5ca47560b1 100755
--- a/erpnext/hr/doctype/employee/employee.py
+++ b/erpnext/hr/doctype/employee/employee.py
@@ -477,14 +477,13 @@ def get_employee_emails(employee_list):
return employee_emails
@frappe.whitelist()
-def get_children(doctype, parent=None, company=None, is_root=False, is_tree=False, fields=None):
+def get_children(doctype, parent=None, company=None, is_root=False, is_tree=False):
filters = [['status', '=', 'Active']]
if company and company != 'All Companies':
filters.append(['company', '=', company])
- if not fields:
- fields = ['name as value', 'employee_name as title']
+ fields = ['name as value', 'employee_name as title']
if is_root:
parent = ''
From 4e7cda6e65ece422cfbd5ddd631f55e86582eb0f Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Wed, 30 Jun 2021 01:46:10 +0530
Subject: [PATCH 287/386] refactor: use arcs instead of bezier curves for
cleaner connectors
---
.../hierarchy_chart_desktop.js | 54 +++++++++++++++----
erpnext/public/scss/hierarchy_chart.scss | 2 +-
2 files changed, 46 insertions(+), 10 deletions(-)
diff --git a/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js b/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
index 0823ec77a8..ba811be586 100644
--- a/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
+++ b/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
@@ -277,15 +277,53 @@ erpnext.HierarchyChart = class {
y: child_node.offsetTop + child_node.offsetHeight / 2
};
- let connector =
- "M" +
- (pos_parent_right.x) + "," + (pos_parent_right.y) + " " +
- "C" +
- (pos_parent_right.x + 100) + "," + (pos_parent_right.y) + " " +
- (pos_child_left.x - 100) + "," + (pos_child_left.y) + " " +
- (pos_child_left.x) + "," + (pos_child_left.y);
+ let connector = this.get_connector(pos_parent_right, pos_child_left);
path.setAttribute("d", connector);
+ this.set_path_attributes(path, parent_id, child_id);
+
+ $('#connectors').append(path);
+ }
+
+ get_connector(pos_parent_right, pos_child_left) {
+ if (pos_parent_right.y === pos_child_left.y) {
+ // don't add arcs if it's a straight line
+ return "M" +
+ (pos_parent_right.x) + "," + (pos_parent_right.y) + " " +
+ "L"+
+ (pos_child_left.x) + "," + (pos_child_left.y);
+ } else {
+ let arc_1 = "";
+ let arc_2 = "";
+ let offset = 0;
+
+ if (pos_parent_right.y > pos_child_left.y) {
+ // if child is above parent on Y axis 1st arc is anticlocwise
+ // second arc is clockwise
+ arc_1 = "a10,10 1 0 0 10,-10 ";
+ arc_2 = "a10,10 0 0 1 10,-10 ";
+ offset = 10;
+ } else {
+ // if child is below parent on Y axis 1st arc is clockwise
+ // second arc is anticlockwise
+ arc_1 = "a10,10 0 0 1 10,10 ";
+ arc_2 = "a10,10 1 0 0 10,10 ";
+ offset = -10;
+ }
+
+ return "M" + (pos_parent_right.x) + "," + (pos_parent_right.y) + " " +
+ "L" +
+ (pos_parent_right.x + 40) + "," + (pos_parent_right.y) + " " +
+ arc_1 +
+ "L" +
+ (pos_parent_right.x + 50) + "," + (pos_child_left.y + offset) + " " +
+ arc_2 +
+ "L"+
+ (pos_child_left.x) + "," + (pos_child_left.y);
+ }
+ }
+
+ set_path_attributes(path, parent_id, child_id) {
path.setAttribute("data-parent", parent_id);
path.setAttribute("data-child", child_id);
@@ -298,8 +336,6 @@ erpnext.HierarchyChart = class {
path.setAttribute("marker-start", "url(#arrowstart-collapsed)");
path.setAttribute("marker-end", "url(#arrowhead-collapsed)");
}
-
- $('#connectors').append(path);
}
set_selected_node(node) {
diff --git a/erpnext/public/scss/hierarchy_chart.scss b/erpnext/public/scss/hierarchy_chart.scss
index 16b8792432..16137fdb5f 100644
--- a/erpnext/public/scss/hierarchy_chart.scss
+++ b/erpnext/public/scss/hierarchy_chart.scss
@@ -48,7 +48,6 @@
border-radius: 0.5rem;
padding: 0.75rem;
width: 18rem;
- height: 5rem;
.btn-edit-node {
display: flex;
@@ -195,6 +194,7 @@
.level {
margin-right: 8px;
+ align-items: flex-start;
}
#arrows {
From 6d06d8c207afabd5f1c60ef0f9b9d357ec109897 Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Wed, 30 Jun 2021 01:57:43 +0530
Subject: [PATCH 288/386] feat: add arc to connectors in mobile view
---
erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js b/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
index 4b09714d0a..b09b428b30 100644
--- a/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
+++ b/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
@@ -322,7 +322,8 @@ erpnext.HierarchyChartMobile = class {
"M" +
(pos_parent_bottom.x) + "," + (pos_parent_bottom.y) + " " +
"L" +
- (pos_parent_bottom.x) + "," + (pos_child_left.y) + " " +
+ (pos_parent_bottom.x) + "," + (pos_child_left.y - 10) + " " +
+ "a10,10 1 0 0 10,10 " +
"L" +
(pos_child_left.x) + "," + (pos_child_left.y);
From d363f9db3d19cd01188cc4516f461d14dd0eb72c Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Wed, 30 Jun 2021 02:29:16 +0530
Subject: [PATCH 289/386] fix: edit node button overflowing
---
erpnext/public/js/templates/node_card.html | 2 +-
erpnext/public/scss/hierarchy_chart.scss | 2 ++
2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/erpnext/public/js/templates/node_card.html b/erpnext/public/js/templates/node_card.html
index 30aedab4bb..c3d8e010b5 100644
--- a/erpnext/public/js/templates/node_card.html
+++ b/erpnext/public/js/templates/node_card.html
@@ -8,7 +8,7 @@
{{ name }}
-
+
diff --git a/erpnext/public/scss/hierarchy_chart.scss b/erpnext/public/scss/hierarchy_chart.scss
index 16137fdb5f..eefc14d679 100644
--- a/erpnext/public/scss/hierarchy_chart.scss
+++ b/erpnext/public/scss/hierarchy_chart.scss
@@ -57,6 +57,7 @@
font-size: .75rem;
justify-content: center;
box-shadow: var(--shadow-sm);
+ margin-left: auto;
}
.edit-chart-node {
@@ -79,6 +80,7 @@
align-items: center;
justify-content: space-between;
margin-bottom: 2px;
+ width: 12.2rem;
}
}
From 781d1bf28d7cc30c9b7fbf11d7a580af1b55286f Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Fri, 2 Jul 2021 18:15:18 +0530
Subject: [PATCH 290/386] fix: sider
---
.../hierarchy_chart_desktop.js | 25 +++++++++----------
.../hierarchy_chart/hierarchy_chart_mobile.js | 18 ++++++-------
erpnext/public/scss/hierarchy_chart.scss | 5 +---
3 files changed, 22 insertions(+), 26 deletions(-)
diff --git a/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js b/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
index ba811be586..9e82fb2002 100644
--- a/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
+++ b/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
@@ -40,7 +40,7 @@ erpnext.HierarchyChart = class {
me.setup_node_click_action(this);
me.setup_edit_node_action(this);
}
- }
+ };
}
make_node_element(node) {
@@ -76,7 +76,7 @@ erpnext.HierarchyChart = class {
me.company = company.get_value();
// svg for connectors
- me.make_svg_markers()
+ me.make_svg_markers();
if (me.$hierarchy)
me.$hierarchy.remove();
@@ -149,7 +149,7 @@ erpnext.HierarchyChart = class {
me.expand_node(root_node);
}
}
- })
+ });
}
expand_node(node) {
@@ -166,7 +166,7 @@ erpnext.HierarchyChart = class {
// rebuild incoming connections
let grandparent = $(`#${node.parent_id}`).attr('data-parent');
- this.refresh_connectors(grandparent)
+ this.refresh_connectors(grandparent);
}
if (node.expandable && !node.expanded) {
@@ -176,8 +176,8 @@ erpnext.HierarchyChart = class {
collapse_node() {
if (this.selected_node.expandable) {
- this.selected_node.$children.hide();
- $(`path[data-parent="${this.selected_node.id}"]`).hide();
+ this.selected_node.$children.hide('fast');
+ $(`path[data-parent="${this.selected_node.id}"]`).hide('fast');
this.selected_node.expanded = false;
}
}
@@ -222,15 +222,14 @@ erpnext.HierarchyChart = class {
if (!node.$children) {
node.$children = $('')
- .hide()
- .appendTo(this.$hierarchy.find('.level:last'));
+ .hide()
+ .appendTo(this.$hierarchy.find('.level:last'));
node.$children.empty();
if (child_nodes) {
$.each(child_nodes, (_i, data) => {
this.add_node(node, data);
-
setTimeout(() => {
this.add_connector(node.id, data.id);
}, 250);
@@ -238,8 +237,8 @@ erpnext.HierarchyChart = class {
}
}
- node.$children.show();
- $(`path[data-parent="${node.id}"]`).show();
+ node.$children.show('fast');
+ $(`path[data-parent="${node.id}"]`).show('fast');
node.expanded = true;
}
@@ -443,6 +442,6 @@ erpnext.HierarchyChart = class {
return;
$(path).remove();
- })
+ });
}
-}
\ No newline at end of file
+};
\ No newline at end of file
diff --git a/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js b/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
index b09b428b30..2ff00baa7c 100644
--- a/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
+++ b/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
@@ -10,7 +10,7 @@ erpnext.HierarchyChartMobile = class {
this.wrapper = $(wrapper);
this.page = wrapper.page;
this.method = method;
- this.doctype = doctype
+ this.doctype = doctype;
this.page.main.css({
'min-height': '300px',
@@ -40,7 +40,7 @@ erpnext.HierarchyChartMobile = class {
me.setup_node_click_action(this);
me.setup_edit_node_action(this);
}
- }
+ };
}
make_node_element(node) {
@@ -78,7 +78,7 @@ erpnext.HierarchyChartMobile = class {
me.company = company.get_value();
// svg for connectors
- me.make_svg_markers()
+ me.make_svg_markers();
if (me.$sibling_group)
me.$sibling_group.remove();
@@ -158,7 +158,7 @@ erpnext.HierarchyChartMobile = class {
me.expand_node(root_node);
}
}
- })
+ });
}
expand_node(node) {
@@ -248,8 +248,8 @@ erpnext.HierarchyChartMobile = class {
render_child_nodes(node, child_nodes) {
if (!node.$children) {
node.$children = $('')
- .hide()
- .appendTo(node.$link.parent());
+ .hide()
+ .appendTo(node.$link.parent());
node.$children.empty();
@@ -462,7 +462,7 @@ erpnext.HierarchyChartMobile = class {
get_avatar(node) {
return `
- `
+ `;
}
expand_sibling_group_node(parent) {
@@ -518,7 +518,7 @@ erpnext.HierarchyChartMobile = class {
return;
$(path).remove();
- })
+ });
}
refresh_connectors(node_parent, node_id) {
@@ -527,4 +527,4 @@ erpnext.HierarchyChartMobile = class {
$(`path[data-parent="${node_parent}"]`).remove();
this.add_connector(node_parent, node_id);
}
-}
\ No newline at end of file
+};
\ No newline at end of file
diff --git a/erpnext/public/scss/hierarchy_chart.scss b/erpnext/public/scss/hierarchy_chart.scss
index eefc14d679..a54bf6f332 100644
--- a/erpnext/public/scss/hierarchy_chart.scss
+++ b/erpnext/public/scss/hierarchy_chart.scss
@@ -62,16 +62,13 @@
.edit-chart-node {
display: block;
+ margin-right: 0.25rem;
}
.node-edit-icon {
display: block;
}
- .edit-chart-node {
- margin-right: 0.25rem;
- }
-
.node-edit-icon > .icon{
stroke: var(--blue-500);
}
From 6a4cce2431c5408788fd19a1297b64b0791cdeae Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Tue, 6 Jul 2021 18:16:49 +0530
Subject: [PATCH 291/386] fix: removing orphaned connectors
---
.../js/hierarchy_chart/hierarchy_chart_desktop.js | 14 ++++++--------
.../js/hierarchy_chart/hierarchy_chart_mobile.js | 6 ++----
2 files changed, 8 insertions(+), 12 deletions(-)
diff --git a/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js b/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
index 9e82fb2002..1896ac7c39 100644
--- a/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
+++ b/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
@@ -176,8 +176,8 @@ erpnext.HierarchyChart = class {
collapse_node() {
if (this.selected_node.expandable) {
- this.selected_node.$children.hide('fast');
- $(`path[data-parent="${this.selected_node.id}"]`).hide('fast');
+ this.selected_node.$children.hide();
+ $(`path[data-parent="${this.selected_node.id}"]`).hide();
this.selected_node.expanded = false;
}
}
@@ -237,8 +237,8 @@ erpnext.HierarchyChart = class {
}
}
- node.$children.show('fast');
- $(`path[data-parent="${node.id}"]`).show('fast');
+ node.$children.show();
+ $(`path[data-parent="${node.id}"]`).show();
node.expanded = true;
}
@@ -262,9 +262,7 @@ erpnext.HierarchyChart = class {
let parent_node = document.querySelector(`#${parent_id}`);
let child_node = document.querySelector(`#${child_id}`);
- // variable for the namespace
- const svgns = 'http://www.w3.org/2000/svg';
- let path = document.createElementNS(svgns, 'path');
+ let path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
// we need to connect right side of the parent to the left side of the child node
let pos_parent_right = {
@@ -438,7 +436,7 @@ erpnext.HierarchyChart = class {
let parent = $(path).data('parent');
let child = $(path).data('child');
- if ($(parent).length || $(child).length)
+ if ($(`#${parent}`).length && $(`#${child}`).length)
return;
$(path).remove();
diff --git a/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js b/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
index 2ff00baa7c..102cbb03b0 100644
--- a/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
+++ b/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
@@ -289,9 +289,7 @@ erpnext.HierarchyChartMobile = class {
let parent_node = document.querySelector(`#${parent_id}`);
let child_node = document.querySelector(`#${child_id}`);
- // variable for the namespace
- const svgns = 'http://www.w3.org/2000/svg';
- let path = document.createElementNS(svgns, 'path');
+ let path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
let connector = undefined;
@@ -514,7 +512,7 @@ erpnext.HierarchyChartMobile = class {
let parent = $(path).data('parent');
let child = $(path).data('child');
- if ($(parent).length || $(child).length)
+ if ($(`#${parent}`).length && $(`#${child}`).length)
return;
$(path).remove();
From 97d2bab43404af5863aee72e832917327d44331a Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Wed, 7 Jul 2021 09:43:28 +0530
Subject: [PATCH 292/386] fix: unnecessary variables
---
.../js/hierarchy_chart/hierarchy_chart_desktop.js | 14 ++++++--------
1 file changed, 6 insertions(+), 8 deletions(-)
diff --git a/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js b/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
index 1896ac7c39..8d0685f80d 100644
--- a/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
+++ b/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
@@ -153,7 +153,7 @@ erpnext.HierarchyChart = class {
}
expand_node(node) {
- let is_sibling = this.selected_node && this.selected_node.parent_id === node.parent_id;
+ const is_sibling = this.selected_node && this.selected_node.parent_id === node.parent_id;
this.set_selected_node(node);
this.show_active_path(node);
this.collapse_previous_level_nodes(node);
@@ -243,11 +243,9 @@ erpnext.HierarchyChart = class {
}
add_node(node, data) {
- var $li = $(' ');
-
return new this.Node({
id: data.id,
- parent: $li.appendTo(node.$children),
+ parent: $(' ').appendTo(node.$children),
parent_id: node.id,
image: data.image,
name: data.name,
@@ -259,8 +257,8 @@ erpnext.HierarchyChart = class {
}
add_connector(parent_id, child_id) {
- let parent_node = document.querySelector(`#${parent_id}`);
- let child_node = document.querySelector(`#${child_id}`);
+ const parent_node = document.querySelector(`#${parent_id}`);
+ const child_node = document.querySelector(`#${child_id}`);
let path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
@@ -276,7 +274,7 @@ erpnext.HierarchyChart = class {
let connector = this.get_connector(pos_parent_right, pos_child_left);
- path.setAttribute("d", connector);
+ path.setAttribute('d', connector);
this.set_path_attributes(path, parent_id, child_id);
$('#connectors').append(path);
@@ -385,7 +383,7 @@ erpnext.HierarchyChart = class {
let node_element = $(`#${node.id}`);
node_element.click(function() {
- let is_sibling = me.selected_node.parent_id === node.parent_id;
+ const is_sibling = me.selected_node.parent_id === node.parent_id;
if (is_sibling) {
me.collapse_node();
From 31a0f36ed9203ed2a20143be527ffe4280f50938 Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Wed, 7 Jul 2021 12:05:50 +0530
Subject: [PATCH 293/386] feat: handle multiple root / orphan nodes
---
.../organizational_chart.py | 3 +-
.../hierarchy_chart_desktop.js | 48 +++++++++----------
.../hierarchy_chart/hierarchy_chart_mobile.js | 35 +++++++-------
erpnext/public/scss/hierarchy_chart.scss | 4 ++
4 files changed, 49 insertions(+), 41 deletions(-)
diff --git a/erpnext/hr/page/organizational_chart/organizational_chart.py b/erpnext/hr/page/organizational_chart/organizational_chart.py
index f3aa13897d..77b8df7520 100644
--- a/erpnext/hr/page/organizational_chart/organizational_chart.py
+++ b/erpnext/hr/page/organizational_chart/organizational_chart.py
@@ -17,7 +17,7 @@ def get_children(parent=None, company=None, exclude_node=None, is_root=False, is
if exclude_node:
filters.append(['name', '!=', exclude_node])
- if parent and company and parent!=company:
+ if parent and company and parent != company:
filters.append(['reports_to', '=', parent])
else:
filters.append(['reports_to', '=', ''])
@@ -32,6 +32,7 @@ def get_children(parent=None, company=None, exclude_node=None, is_root=False, is
employee.connections = get_connections(employee.id)
employee.expandable = 1 if is_expandable else 0
+ employees.sort(key=lambda x: x['connections'], reverse=True)
return employees
diff --git a/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js b/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
index 8d0685f80d..e89a98ac4f 100644
--- a/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
+++ b/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
@@ -84,11 +84,13 @@ erpnext.HierarchyChart = class {
// setup hierarchy
me.$hierarchy = $(
``);
me.page.main.append(me.$hierarchy);
- me.render_root_node();
+ me.render_root_nodes();
}
}
});
@@ -122,7 +124,7 @@ erpnext.HierarchyChart = class {
`);
}
- render_root_node() {
+ render_root_nodes() {
let me = this;
frappe.call({
@@ -132,21 +134,28 @@ erpnext.HierarchyChart = class {
},
callback: function(r) {
if (r.message.length) {
- let data = r.message[0];
+ let nodes = r.message;
+ let node = undefined;
+ let first_root = undefined;
- let root_node = new me.Node({
- id: data.id,
- parent: me.$hierarchy.find('.root-level'),
- parent_id: undefined,
- image: data.image,
- name: data.name,
- title: data.title,
- expandable: true,
- connections: data.connections,
- is_root: true,
+ $.each(nodes, (i, data) => {
+ node = new me.Node({
+ id: data.id,
+ parent: $(' ').appendTo(me.$hierarchy.find('.node-children')),
+ parent_id: undefined,
+ image: data.image,
+ name: data.name,
+ title: data.title,
+ expandable: true,
+ connections: data.connections,
+ is_root: true
+ });
+
+ if (i == 0)
+ first_root = node;
});
- me.expand_node(root_node);
+ me.expand_node(first_root);
}
}
});
@@ -344,12 +353,7 @@ erpnext.HierarchyChart = class {
collapse_previous_level_nodes(node) {
let node_parent = $(`#${node.parent_id}`);
-
let previous_level_nodes = node_parent.parent().parent().children('li');
- if (node_parent.parent().hasClass('root-level')) {
- previous_level_nodes = node_parent.parent().children('li');
- }
-
let node_card = undefined;
previous_level_nodes.each(function() {
@@ -409,10 +413,6 @@ erpnext.HierarchyChart = class {
remove_levels_after_node(node) {
let level = $(`#${node.id}`).parent().parent().parent();
- if ($(`#${node.id}`).parent().hasClass('root-level')) {
- level = $(`#${node.id}`).parent();
- }
-
level = $('.hierarchy > li:eq('+ level.index() + ')');
level.nextAll('li').remove();
diff --git a/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js b/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
index 102cbb03b0..5eee27b5fc 100644
--- a/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
+++ b/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
@@ -97,7 +97,7 @@ erpnext.HierarchyChartMobile = class {
`);
me.page.main.append(me.$hierarchy);
- me.render_root_node();
+ me.render_root_nodes();
}
}
});
@@ -131,7 +131,7 @@ erpnext.HierarchyChartMobile = class {
`);
}
- render_root_node() {
+ render_root_nodes() {
let me = this;
frappe.call({
@@ -141,21 +141,21 @@ erpnext.HierarchyChartMobile = class {
},
callback: function(r) {
if (r.message.length) {
- let data = r.message[0];
+ let nodes = r.message;
- let root_node = new me.Node({
- id: data.id,
- parent: me.$hierarchy.find('.root-level'),
- parent_id: undefined,
- image: data.image,
- name: data.name,
- title: data.title,
- expandable: true,
- connections: data.connections,
- is_root: true,
+ $.each(nodes, (_i, data) => {
+ return new me.Node({
+ id: data.id,
+ parent: me.$hierarchy.find('.root-level'),
+ parent_id: undefined,
+ image: data.image,
+ name: data.name,
+ title: data.title,
+ expandable: true,
+ connections: data.connections,
+ is_root: true
+ });
});
-
- me.expand_node(root_node);
}
}
});
@@ -375,7 +375,10 @@ erpnext.HierarchyChartMobile = class {
let node_element = $(`#${node.id}`);
node_element.click(function() {
- if (node_element.is(':visible') && node_element.hasClass('active-path')) {
+ if (node.is_root) {
+ me.$hierarchy.empty();
+ me.add_node_to_hierarchy(node, true);
+ } else if (node_element.is(':visible') && node_element.hasClass('active-path')) {
me.remove_levels_after_node(node);
me.remove_orphaned_connectors();
} else {
diff --git a/erpnext/public/scss/hierarchy_chart.scss b/erpnext/public/scss/hierarchy_chart.scss
index a54bf6f332..dd523c3443 100644
--- a/erpnext/public/scss/hierarchy_chart.scss
+++ b/erpnext/public/scss/hierarchy_chart.scss
@@ -246,6 +246,10 @@
margin-top: 16px;
}
+.root-level .node-card {
+ margin: 0 0 16px;
+}
+
// node group
.collapsed-level {
From a48b23e6a5aee5831f777e1cacfc55f4ad3afbd4 Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Thu, 8 Jul 2021 09:53:31 +0530
Subject: [PATCH 294/386] perf: Optimise Rendering
- optimise get_children function
- use promises instead of callbacks
- optimise selectors
- use const wherever possible
- use pure js instead of jquery for connectors for faster rendering
---
.../organizational_chart.py | 22 ++---
.../hierarchy_chart_desktop.js | 82 +++++++++----------
.../hierarchy_chart/hierarchy_chart_mobile.js | 65 +++++++--------
3 files changed, 78 insertions(+), 91 deletions(-)
diff --git a/erpnext/hr/page/organizational_chart/organizational_chart.py b/erpnext/hr/page/organizational_chart/organizational_chart.py
index 77b8df7520..46578f3aaf 100644
--- a/erpnext/hr/page/organizational_chart/organizational_chart.py
+++ b/erpnext/hr/page/organizational_chart/organizational_chart.py
@@ -2,33 +2,25 @@ from __future__ import unicode_literals
import frappe
@frappe.whitelist()
-def get_children(parent=None, company=None, exclude_node=None, is_root=False, is_tree=False, fields=None):
+def get_children(parent=None, company=None):
filters = [['status', '!=', 'Left']]
if company and company != 'All Companies':
filters.append(['company', '=', company])
- if not fields:
- fields = ['employee_name as name', 'name as id', 'reports_to', 'image', 'designation as title']
-
- if is_root:
- parent = ''
-
- if exclude_node:
- filters.append(['name', '!=', exclude_node])
-
if parent and company and parent != company:
filters.append(['reports_to', '=', parent])
else:
filters.append(['reports_to', '=', ''])
- employees = frappe.get_list('Employee', fields=fields,
- filters=filters, order_by='name')
+ employees = frappe.get_list('Employee',
+ fields=['employee_name as name', 'name as id', 'reports_to', 'image', 'designation as title'],
+ filters=filters,
+ order_by='name'
+ )
for employee in employees:
- is_expandable = frappe.get_all('Employee', filters=[
- ['reports_to', '=', employee.get('id')]
- ])
+ is_expandable = frappe.db.count('Employee', filters={'reports_to': employee.get('id')})
employee.connections = get_connections(employee.id)
employee.expandable = 1 if is_expandable else 0
diff --git a/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js b/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
index e89a98ac4f..bf366792a9 100644
--- a/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
+++ b/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
@@ -7,7 +7,6 @@ erpnext.HierarchyChart = class {
- this method should return id, name, title, image, and connections for each node
*/
constructor(doctype, wrapper, method) {
- this.wrapper = $(wrapper);
this.page = wrapper.page;
this.method = method;
this.doctype = doctype;
@@ -61,6 +60,8 @@ erpnext.HierarchyChart = class {
frappe.breadcrumbs.add('HR');
let me = this;
+ if ($(`[data-fieldname="company"]`).length) return;
+
let company = this.page.add_field({
fieldtype: 'Link',
options: 'Company',
@@ -131,32 +132,30 @@ erpnext.HierarchyChart = class {
method: me.method,
args: {
company: me.company
- },
- callback: function(r) {
- if (r.message.length) {
- let nodes = r.message;
- let node = undefined;
- let first_root = undefined;
+ }
+ }).then(r => {
+ if (r.message.length) {
+ let node = undefined;
+ let first_root = undefined;
- $.each(nodes, (i, data) => {
- node = new me.Node({
- id: data.id,
- parent: $(' ').appendTo(me.$hierarchy.find('.node-children')),
- parent_id: undefined,
- image: data.image,
- name: data.name,
- title: data.title,
- expandable: true,
- connections: data.connections,
- is_root: true
- });
-
- if (i == 0)
- first_root = node;
+ $.each(r.message, (i, data) => {
+ node = new me.Node({
+ id: data.id,
+ parent: $(' ').appendTo(me.$hierarchy.find('.node-children')),
+ parent_id: undefined,
+ image: data.image,
+ name: data.name,
+ title: data.title,
+ expandable: true,
+ connections: data.connections,
+ is_root: true
});
- me.expand_node(first_root);
- }
+ if (i == 0)
+ first_root = node;
+ });
+
+ me.expand_node(first_root);
}
});
}
@@ -204,18 +203,14 @@ erpnext.HierarchyChart = class {
}
get_child_nodes(node_id) {
- let me = this;
return new Promise(resolve => {
frappe.call({
method: this.method,
args: {
parent: node_id,
- company: me.company
- },
- callback: (r) => {
- resolve(r.message);
+ company: this.company
}
- });
+ }).then(r => resolve(r.message));
});
}
@@ -266,27 +261,28 @@ erpnext.HierarchyChart = class {
}
add_connector(parent_id, child_id) {
+ // using pure javascript for better performance
const parent_node = document.querySelector(`#${parent_id}`);
const child_node = document.querySelector(`#${child_id}`);
let path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
// we need to connect right side of the parent to the left side of the child node
- let pos_parent_right = {
+ const pos_parent_right = {
x: parent_node.offsetLeft + parent_node.offsetWidth,
y: parent_node.offsetTop + parent_node.offsetHeight / 2
};
- let pos_child_left = {
+ const pos_child_left = {
x: child_node.offsetLeft - 5,
y: child_node.offsetTop + child_node.offsetHeight / 2
};
- let connector = this.get_connector(pos_parent_right, pos_child_left);
+ const connector = this.get_connector(pos_parent_right, pos_child_left);
path.setAttribute('d', connector);
this.set_path_attributes(path, parent_id, child_id);
- $('#connectors').append(path);
+ document.getElementById('connectors').appendChild(path);
}
get_connector(pos_parent_right, pos_child_left) {
@@ -330,12 +326,13 @@ erpnext.HierarchyChart = class {
set_path_attributes(path, parent_id, child_id) {
path.setAttribute("data-parent", parent_id);
path.setAttribute("data-child", child_id);
+ const parent = $(`#${parent_id}`);
- if ($(`#${parent_id}`).hasClass('active')) {
+ if (parent.hasClass('active')) {
path.setAttribute("class", "active-connector");
path.setAttribute("marker-start", "url(#arrowstart-active)");
path.setAttribute("marker-end", "url(#arrowhead-active)");
- } else if ($(`#${parent_id}`).hasClass('active-path')) {
+ } else if (parent.hasClass('active-path')) {
path.setAttribute("class", "collapsed-connector");
path.setAttribute("marker-start", "url(#arrowstart-collapsed)");
path.setAttribute("marker-end", "url(#arrowhead-collapsed)");
@@ -343,8 +340,9 @@ erpnext.HierarchyChart = class {
}
set_selected_node(node) {
- // remove .active class from the current node
- $('.active').removeClass('active');
+ // remove active class from the current node
+ if (this.selected_node)
+ this.selected_node.$link.removeClass('active');
// add active class to the newly selected node
this.selected_node = node;
@@ -411,9 +409,9 @@ erpnext.HierarchyChart = class {
}
remove_levels_after_node(node) {
- let level = $(`#${node.id}`).parent().parent().parent();
+ let level = $(`#${node.id}`).parent().parent().parent().index();
- level = $('.hierarchy > li:eq('+ level.index() + ')');
+ level = $('.hierarchy > li:eq('+ level + ')');
level.nextAll('li').remove();
let nodes = level.find('.node-card');
@@ -431,8 +429,8 @@ erpnext.HierarchyChart = class {
remove_orphaned_connectors() {
let paths = $('#connectors > path');
$.each(paths, (_i, path) => {
- let parent = $(path).data('parent');
- let child = $(path).data('child');
+ const parent = $(path).data('parent');
+ const child = $(path).data('child');
if ($(`#${parent}`).length && $(`#${child}`).length)
return;
diff --git a/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js b/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
index 5eee27b5fc..17062e2585 100644
--- a/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
+++ b/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
@@ -7,7 +7,6 @@ erpnext.HierarchyChartMobile = class {
- this method should return id, name, title, image, and connections for each node
*/
constructor(doctype, wrapper, method) {
- this.wrapper = $(wrapper);
this.page = wrapper.page;
this.method = method;
this.doctype = doctype;
@@ -63,6 +62,8 @@ erpnext.HierarchyChartMobile = class {
frappe.breadcrumbs.add('HR');
let me = this;
+ if ($(`[data-fieldname="company"]`).length) return;
+
let company = this.page.add_field({
fieldtype: 'Link',
options: 'Company',
@@ -139,24 +140,21 @@ erpnext.HierarchyChartMobile = class {
args: {
company: me.company
},
- callback: function(r) {
- if (r.message.length) {
- let nodes = r.message;
-
- $.each(nodes, (_i, data) => {
- return new me.Node({
- id: data.id,
- parent: me.$hierarchy.find('.root-level'),
- parent_id: undefined,
- image: data.image,
- name: data.name,
- title: data.title,
- expandable: true,
- connections: data.connections,
- is_root: true
- });
+ }).then(r => {
+ if (r.message.length) {
+ $.each(r.message, (_i, data) => {
+ return new me.Node({
+ id: data.id,
+ parent: me.$hierarchy.find('.root-level'),
+ parent_id: undefined,
+ image: data.image,
+ name: data.name,
+ title: data.title,
+ expandable: true,
+ connections: data.connections,
+ is_root: true
});
- }
+ });
}
});
}
@@ -237,11 +235,8 @@ erpnext.HierarchyChartMobile = class {
parent: node_id,
company: me.company,
exclude_node: exclude_node
- },
- callback: (r) => {
- resolve(r.message);
}
- });
+ }).then(r => resolve(r.message));
});
}
@@ -286,10 +281,10 @@ erpnext.HierarchyChartMobile = class {
}
add_connector(parent_id, child_id) {
- let parent_node = document.querySelector(`#${parent_id}`);
- let child_node = document.querySelector(`#${child_id}`);
+ const parent_node = document.querySelector(`#${parent_id}`);
+ const child_node = document.querySelector(`#${child_id}`);
- let path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
+ const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
let connector = undefined;
@@ -299,10 +294,10 @@ erpnext.HierarchyChartMobile = class {
connector = this.get_connector_for_collapsed_node(parent_node, child_node);
}
- path.setAttribute("d", connector);
+ path.setAttribute('d', connector);
this.set_path_attributes(path, parent_id, child_id);
- $('#connectors').append(path);
+ document.getElementById('connectors').appendChild(path);
}
get_connector_for_active_node(parent_node, child_node) {
@@ -351,19 +346,21 @@ erpnext.HierarchyChartMobile = class {
set_path_attributes(path, parent_id, child_id) {
path.setAttribute("data-parent", parent_id);
path.setAttribute("data-child", child_id);
+ const parent = $(`#${parent_id}`);
- if ($(`#${parent_id}`).hasClass('active')) {
+ if (parent.hasClass('active')) {
path.setAttribute("class", "active-connector");
path.setAttribute("marker-start", "url(#arrowstart-active)");
path.setAttribute("marker-end", "url(#arrowhead-active)");
- } else if ($(`#${parent_id}`).hasClass('active-path')) {
+ } else if (parent.hasClass('active-path')) {
path.setAttribute("class", "collapsed-connector");
}
}
set_selected_node(node) {
// remove .active class from the current node
- $('.active').removeClass('active');
+ if (this.selected_node)
+ this.selected_node.$link.removeClass('active');
// add active class to the newly selected node
this.selected_node = node;
@@ -494,9 +491,9 @@ erpnext.HierarchyChartMobile = class {
}
remove_levels_after_node(node) {
- let level = $(`#${node.id}`).parent().parent();
+ let level = $(`#${node.id}`).parent().parent().index();
- level = $('.hierarchy-mobile > li:eq('+ (level.index()) + ')');
+ level = $('.hierarchy-mobile > li:eq('+ level + ')');
level.nextAll('li').remove();
let current_node = level.find(`#${node.id}`);
@@ -512,8 +509,8 @@ erpnext.HierarchyChartMobile = class {
remove_orphaned_connectors() {
let paths = $('#connectors > path');
$.each(paths, (_i, path) => {
- let parent = $(path).data('parent');
- let child = $(path).data('child');
+ const parent = $(path).data('parent');
+ const child = $(path).data('child');
if ($(`#${parent}`).length && $(`#${child}`).length)
return;
From b6715189fbb76dca90a60da972c05df267a0e030 Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Thu, 8 Jul 2021 11:23:50 +0530
Subject: [PATCH 295/386] fix: do not sort by number of connections
---
.../hr/page/organizational_chart/organizational_chart.py | 1 -
.../public/js/hierarchy_chart/hierarchy_chart_desktop.js | 8 ++++----
2 files changed, 4 insertions(+), 5 deletions(-)
diff --git a/erpnext/hr/page/organizational_chart/organizational_chart.py b/erpnext/hr/page/organizational_chart/organizational_chart.py
index 46578f3aaf..ce84b3c744 100644
--- a/erpnext/hr/page/organizational_chart/organizational_chart.py
+++ b/erpnext/hr/page/organizational_chart/organizational_chart.py
@@ -24,7 +24,6 @@ def get_children(parent=None, company=None):
employee.connections = get_connections(employee.id)
employee.expandable = 1 if is_expandable else 0
- employees.sort(key=lambda x: x['connections'], reverse=True)
return employees
diff --git a/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js b/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
index bf366792a9..374787c6ef 100644
--- a/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
+++ b/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
@@ -135,8 +135,8 @@ erpnext.HierarchyChart = class {
}
}).then(r => {
if (r.message.length) {
+ let expand_node = undefined;
let node = undefined;
- let first_root = undefined;
$.each(r.message, (i, data) => {
node = new me.Node({
@@ -151,11 +151,11 @@ erpnext.HierarchyChart = class {
is_root: true
});
- if (i == 0)
- first_root = node;
+ if (!expand_node && data.connections)
+ expand_node = node;
});
- me.expand_node(first_root);
+ me.expand_node(expand_node);
}
});
}
From 1a3c335febcbd8c130fdc60806fc772c910d782c Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Thu, 8 Jul 2021 16:55:42 +0530
Subject: [PATCH 296/386] feat: use icon for connections on mobile view
---
.../js/hierarchy_chart/hierarchy_chart_mobile.js | 2 +-
erpnext/public/js/templates/node_card.html | 12 +++++++++---
2 files changed, 10 insertions(+), 4 deletions(-)
diff --git a/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js b/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
index 17062e2585..1985299378 100644
--- a/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
+++ b/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
@@ -50,7 +50,7 @@ erpnext.HierarchyChartMobile = class {
image: node.image,
parent: node.parent_id,
connections: node.connections,
- is_mobile: 1
+ is_mobile: true
});
node.parent.append(node_card);
diff --git a/erpnext/public/js/templates/node_card.html b/erpnext/public/js/templates/node_card.html
index c3d8e010b5..fb94df85ed 100644
--- a/erpnext/public/js/templates/node_card.html
+++ b/erpnext/public/js/templates/node_card.html
@@ -16,10 +16,16 @@
{{ title }}
- {% if connections == 1 %}
-
· {{ connections }} Connection
+ {% if is_mobile %}
+
+ · {{ connections }}
+
{% else %}
-
· {{ connections }} Connections
+ {% if connections == 1 %}
+
· {{ connections }} Connection
+ {% else %}
+
· {{ connections }} Connections
+ {% endif %}
{% endif %}
From c79316a9c09a279374a4a3689265aaafaccc9665 Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Thu, 8 Jul 2021 17:05:40 +0530
Subject: [PATCH 297/386] fix: exclude active node while fetching sibling group
---
.../hr/page/organizational_chart/organizational_chart.py | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/erpnext/hr/page/organizational_chart/organizational_chart.py b/erpnext/hr/page/organizational_chart/organizational_chart.py
index ce84b3c744..1e03e3d06a 100644
--- a/erpnext/hr/page/organizational_chart/organizational_chart.py
+++ b/erpnext/hr/page/organizational_chart/organizational_chart.py
@@ -2,8 +2,7 @@ from __future__ import unicode_literals
import frappe
@frappe.whitelist()
-def get_children(parent=None, company=None):
-
+def get_children(parent=None, company=None, exclude_node=None):
filters = [['status', '!=', 'Left']]
if company and company != 'All Companies':
filters.append(['company', '=', company])
@@ -13,6 +12,9 @@ def get_children(parent=None, company=None):
else:
filters.append(['reports_to', '=', ''])
+ if exclude_node:
+ filters.append(['name', '!=', exclude_node])
+
employees = frappe.get_list('Employee',
fields=['employee_name as name', 'name as id', 'reports_to', 'image', 'designation as title'],
filters=filters,
From 9270de59f4c686431acd3e6a06c1974e990bb182 Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Thu, 8 Jul 2021 18:44:53 +0530
Subject: [PATCH 298/386] fix: sibling group expansion not working for root
nodes
---
.../hierarchy_chart/hierarchy_chart_mobile.js | 36 ++++++++++++-------
1 file changed, 24 insertions(+), 12 deletions(-)
diff --git a/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js b/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
index 1985299378..d48b4c8f36 100644
--- a/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
+++ b/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
@@ -88,16 +88,7 @@ erpnext.HierarchyChartMobile = class {
me.$sibling_group = $(`
`);
me.page.main.append(me.$sibling_group);
- if (me.$hierarchy)
- me.$hierarchy.remove();
-
- // setup hierarchy
- me.$hierarchy = $(
- ``);
-
- me.page.main.append(me.$hierarchy);
+ me.setup_hierarchy()
me.render_root_nodes();
}
}
@@ -132,6 +123,19 @@ erpnext.HierarchyChartMobile = class {
`);
}
+ setup_hierarchy() {
+ $(`#connectors`).empty();
+ if (this.$hierarchy)
+ this.$hierarchy.remove();
+
+ this.$hierarchy = $(
+ ``);
+
+ this.page.main.append(this.$hierarchy);
+ }
+
render_root_nodes() {
let me = this;
@@ -142,10 +146,13 @@ erpnext.HierarchyChartMobile = class {
},
}).then(r => {
if (r.message.length) {
+ let root_level = me.$hierarchy.find('.root-level');
+ root_level.empty();
+
$.each(r.message, (_i, data) => {
return new me.Node({
id: data.id,
- parent: me.$hierarchy.find('.root-level'),
+ parent: root_level,
parent_id: undefined,
image: data.image,
name: data.name,
@@ -401,7 +408,12 @@ erpnext.HierarchyChartMobile = class {
$('.node-group').on('click', function() {
let parent = $(this).attr('data-parent');
- me.expand_sibling_group_node(parent);
+ if (parent === 'undefined') {
+ me.setup_hierarchy();
+ me.render_root_nodes();
+ } else {
+ me.expand_sibling_group_node(parent);
+ }
});
}
From 9e7302a21ea49d3abcf180f5fcbf768a94eefccc Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Fri, 9 Jul 2021 01:03:02 +0530
Subject: [PATCH 299/386] fix(mobile): collapsed nodes not expanding
---
.../hierarchy_chart/hierarchy_chart_mobile.js | 58 ++++++++++---------
1 file changed, 32 insertions(+), 26 deletions(-)
diff --git a/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js b/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
index d48b4c8f36..58530eaaf9 100644
--- a/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
+++ b/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
@@ -88,7 +88,7 @@ erpnext.HierarchyChartMobile = class {
me.$sibling_group = $(`
`);
me.page.main.append(me.$sibling_group);
- me.setup_hierarchy()
+ me.setup_hierarchy();
me.render_root_nodes();
}
}
@@ -194,9 +194,9 @@ erpnext.HierarchyChartMobile = class {
collapse_node() {
let node = this.selected_node;
- if (node.expandable) {
+ if (node.expandable && node.$children) {
node.$children.hide();
- node.expanded = false;
+ node.expanded = 0;
// add a collapsed level to show the collapsed parent
// and a button beside it to move to that level
@@ -212,10 +212,7 @@ erpnext.HierarchyChartMobile = class {
frappe.run_serially([
() => this.get_child_nodes(node.parent_id, node.id),
(child_nodes) => this.get_node_group(child_nodes, node.parent_id),
- (node_group) => {
- node_parent.find('.collapsed-level')
- .append(node_group);
- },
+ (node_group) => node_parent.find('.collapsed-level').append(node_group),
() => this.setup_node_group_action()
]);
}
@@ -268,7 +265,7 @@ erpnext.HierarchyChartMobile = class {
}
node.$children.show();
- node.expanded = true;
+ node.expanded = 1;
}
add_node(node, data) {
@@ -380,13 +377,16 @@ erpnext.HierarchyChartMobile = class {
node_element.click(function() {
if (node.is_root) {
+ var el = $(this).detach();
me.$hierarchy.empty();
- me.add_node_to_hierarchy(node, true);
+ $(`#connectors`).empty();
+ me.add_node_to_hierarchy(el, node);
} else if (node_element.is(':visible') && node_element.hasClass('active-path')) {
me.remove_levels_after_node(node);
me.remove_orphaned_connectors();
} else {
- me.add_node_to_hierarchy(node, true);
+ var el = $(this).detach();
+ me.add_node_to_hierarchy(el, node);
me.collapse_node();
}
@@ -417,15 +417,15 @@ erpnext.HierarchyChartMobile = class {
});
}
- add_node_to_hierarchy(node) {
- this.$hierarchy.append(`
-
-
-
-
- `);
+ add_node_to_hierarchy(node_element, node) {
+ this.$hierarchy.append(` `);
+ node_element.removeClass('active-child active-path');
+ this.$hierarchy.find('.level:last').append(node_element);
- node.$link.appendTo(this.$hierarchy.find('.level:last'));
+ let node_object = this.nodes[node.id];
+ node_object.expanded = 0;
+ node_object.$children = undefined;
+ this.nodes[node.id] = node_object;
}
get_node_group(nodes, parent, collapsed=true) {
@@ -478,9 +478,11 @@ erpnext.HierarchyChartMobile = class {
expand_sibling_group_node(parent) {
let node_object = this.nodes[parent];
let node = node_object.$link;
+
node.removeClass('active-child active-path');
node_object.expanded = 0;
node_object.$children = undefined;
+ this.nodes[node.id] = node_object;
// show parent's siblings and expand parent node
frappe.run_serially([
@@ -491,17 +493,21 @@ erpnext.HierarchyChartMobile = class {
this.$sibling_group.empty().append(node_group);
},
() => this.setup_node_group_action(),
- () => {
- this.$hierarchy.empty().append(`
-
- `);
- this.$hierarchy.find('.level').append(node);
- $(`#connectors`).empty();
- this.expand_node(node_object);
- }
+ () => this.reattach_and_expand_node(node, node_object)
]);
}
+ reattach_and_expand_node(node, node_object) {
+ var el = node.detach();
+
+ this.$hierarchy.empty().append(`
+
+ `);
+ this.$hierarchy.find('.level').append(el);
+ $(`#connectors`).empty();
+ this.expand_node(node_object);
+ }
+
remove_levels_after_node(node) {
let level = $(`#${node.id}`).parent().parent().index();
From e1cf7712d916b73a4f61154135e55c3a83fec1be Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Fri, 9 Jul 2021 01:25:26 +0530
Subject: [PATCH 300/386] fix: sider
---
erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js b/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
index 58530eaaf9..5a6f168876 100644
--- a/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
+++ b/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
@@ -376,8 +376,9 @@ erpnext.HierarchyChartMobile = class {
let node_element = $(`#${node.id}`);
node_element.click(function() {
+ let el = $(this).detach();
+
if (node.is_root) {
- var el = $(this).detach();
me.$hierarchy.empty();
$(`#connectors`).empty();
me.add_node_to_hierarchy(el, node);
@@ -385,7 +386,6 @@ erpnext.HierarchyChartMobile = class {
me.remove_levels_after_node(node);
me.remove_orphaned_connectors();
} else {
- var el = $(this).detach();
me.add_node_to_hierarchy(el, node);
me.collapse_node();
}
From 3cc85e166f6d2b0212db88a16bb94425ed8c385c Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Wed, 14 Jul 2021 23:50:54 +0530
Subject: [PATCH 301/386] test: UI tests for org chart desktop
---
.../test_organizational_chart_desktop.js | 102 ++++++++++++++++++
.../hierarchy_chart_desktop.js | 3 +-
erpnext/tests/ui_test_helpers.py | 53 +++++++++
3 files changed, 157 insertions(+), 1 deletion(-)
create mode 100644 cypress/integration/test_organizational_chart_desktop.js
create mode 100644 erpnext/tests/ui_test_helpers.py
diff --git a/cypress/integration/test_organizational_chart_desktop.js b/cypress/integration/test_organizational_chart_desktop.js
new file mode 100644
index 0000000000..d50d551330
--- /dev/null
+++ b/cypress/integration/test_organizational_chart_desktop.js
@@ -0,0 +1,102 @@
+context('Organizational Chart', () => {
+ before(() => {
+ cy.login();
+ cy.visit('/app/website');
+
+ cy.visit(`app/organizational-chart`);
+ cy.fill_field('company', 'Test Org Chart');
+ cy.get('body').click();
+ cy.wait(500);
+ });
+
+ beforeEach(() => {
+ cy.window().its('frappe').then(frappe => {
+ return frappe.call('erpnext.tests.ui_test_helpers.create_employee_records');
+ }).as('employee_records');
+ });
+
+ it('renders root nodes and loads children for the first expandable node', () => {
+ // check rendered root nodes and the node name, title, connections
+ cy.get('.hierarchy').find('.root-level ul.node-children').children()
+ .should('have.length', 2)
+ .first()
+ .as('first-child');
+
+ cy.get('@first-child').get('.node-name').contains('Test Employee 1');
+ cy.get('@first-child').get('.node-info').find('.node-title').contains('CEO');
+ cy.get('@first-child').get('.node-info').find('.node-connections').contains('· 2 Connections');
+
+ // check children of first node
+ cy.get('@employee_records').then(employee_records => {
+ // children of 1st root visible
+ cy.get(`[data-parent="${employee_records.message[0]}"]`).as('child-node')
+ cy.get('@child-node')
+ .should('have.length', 1)
+ .should('be.visible');
+ cy.get('@child-node').get('.node-name').contains('Test Employee 3');
+
+ // connectors between first root node and immediate child
+ cy.get(`path[data-parent="${employee_records.message[0]}"]`)
+ .should('be.visible')
+ .invoke('attr', 'data-child')
+ .should('equal', employee_records.message[2]);
+ });
+ });
+
+ it('hides active nodes children and connectors on expanding sibling node', () => {
+ cy.get('@employee_records').then(employee_records => {
+ // click sibling
+ cy.get(`#${employee_records.message[1]}`)
+ .click()
+ .should('have.class', 'active');
+
+ // child nodes and connectors hidden
+ cy.get(`[data-parent="${employee_records.message[0]}"]`).should('not.be.visible');
+ cy.get(`path[data-parent="${employee_records.message[0]}"]`).should('not.be.visible');
+ });
+ });
+
+ it('collapses previous level nodes and refreshes connectors on expanding child node', () => {
+ cy.get('@employee_records').then(employee_records => {
+ // click child node
+ cy.get(`#${employee_records.message[3]}`)
+ .click()
+ .should('have.class', 'active');
+
+ // previous level nodes: parent should be on active-path; other nodes should be collapsed
+ cy.get(`#${employee_records.message[0]}`).should('have.class', 'collapsed');
+ cy.get(`#${employee_records.message[1]}`).should('have.class', 'active-path');
+
+ // previous level connectors refreshed
+ cy.get(`path[data-parent="${employee_records.message[1]}"]`)
+ .should('have.class', 'collapsed-connector');
+
+ // child node's children and connectors rendered
+ cy.get(`[data-parent="${employee_records.message[3]}"]`).should('be.visible');
+ cy.get(`path[data-parent="${employee_records.message[3]}"]`).should('be.visible');
+ });
+ });
+
+ it('expands previous level nodes', () => {
+ cy.get('@employee_records').then(employee_records => {
+ cy.get(`#${employee_records.message[0]}`)
+ .click()
+ .should('have.class', 'active');
+
+ cy.get(`[data-parent="${employee_records.message[0]}"]`)
+ .should('be.visible');
+
+ cy.get('ul.hierarchy').children().should('have.length', 2);
+ cy.get(`#connectors`).children().should('have.length', 1);
+ });
+ });
+
+ it('edit node navigates to employee master', () => {
+ cy.get('@employee_records').then(employee_records => {
+ cy.get(`#${employee_records.message[0]}`).find('.btn-edit-node')
+ .click();
+
+ cy.url().should('include', `/employee/${employee_records.message[0]}`);
+ });
+ });
+});
diff --git a/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js b/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
index 374787c6ef..fe4d17c210 100644
--- a/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
+++ b/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
@@ -49,7 +49,8 @@ erpnext.HierarchyChart = class {
title: node.title,
image: node.image,
parent: node.parent_id,
- connections: node.connections
+ connections: node.connections,
+ is_mobile: false
});
node.parent.append(node_card);
diff --git a/erpnext/tests/ui_test_helpers.py b/erpnext/tests/ui_test_helpers.py
new file mode 100644
index 0000000000..8e67b1cd34
--- /dev/null
+++ b/erpnext/tests/ui_test_helpers.py
@@ -0,0 +1,53 @@
+import frappe
+from frappe import _
+from frappe.utils import getdate
+
+@frappe.whitelist()
+def create_employee_records():
+ company = create_company()
+ create_missing_designation()
+
+ emp1 = create_employee('Test Employee 1', 'CEO')
+ emp2 = create_employee('Test Employee 2', 'CTO')
+ emp3 = create_employee('Test Employee 3', 'Head of Marketing and Sales', emp1)
+ emp4 = create_employee('Test Employee 4', 'Project Manager', emp2)
+ emp5 = create_employee('Test Employee 5', 'Analyst', emp3)
+ emp6 = create_employee('Test Employee 6', 'Software Developer', emp4)
+
+ employees = [emp1, emp2, emp3, emp4, emp5, emp6]
+ return employees
+
+def create_company():
+ company = frappe.db.exists('Company', 'Test Org Chart')
+ if not company:
+ company = frappe.get_doc({
+ 'doctype': 'Company',
+ 'company_name': 'Test Org Chart',
+ 'country': 'India',
+ 'default_currency': 'INR'
+ }).insert().name
+
+ return company
+
+def create_employee(first_name, designation, reports_to=None):
+ employee = frappe.db.exists('Employee', {'first_name': first_name, 'designation': designation})
+ if not employee:
+ employee = frappe.get_doc({
+ 'doctype': 'Employee',
+ 'first_name': first_name,
+ 'company': 'Test Org Chart',
+ 'gender': 'Female',
+ 'date_of_birth': getdate('08-12-1998'),
+ 'date_of_joining': getdate('01-01-2021'),
+ 'designation': designation,
+ 'reports_to': reports_to
+ }).insert().name
+
+ return employee
+
+def create_missing_designation():
+ if not frappe.db.exists('Designation', 'CTO'):
+ frappe.get_doc({
+ 'doctype': 'Designation',
+ 'designation_name': 'CTO'
+ }).insert()
\ No newline at end of file
From a1d379d5d4e7d40d2f327d2c76a28c076ec5f137 Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Thu, 15 Jul 2021 19:19:09 +0530
Subject: [PATCH 302/386] test: UI tests for org chart mobile
fix(mobile): detach node before emptying hierarchy
fix(mobile): sibling group not rendering for first level
---
.../test_organizational_chart_mobile.js | 182 ++++++++++++++++++
.../hierarchy_chart/hierarchy_chart_mobile.js | 13 +-
erpnext/tests/ui_test_helpers.py | 7 +-
3 files changed, 195 insertions(+), 7 deletions(-)
create mode 100644 cypress/integration/test_organizational_chart_mobile.js
diff --git a/cypress/integration/test_organizational_chart_mobile.js b/cypress/integration/test_organizational_chart_mobile.js
new file mode 100644
index 0000000000..656051289f
--- /dev/null
+++ b/cypress/integration/test_organizational_chart_mobile.js
@@ -0,0 +1,182 @@
+context('Organizational Chart Mobile', () => {
+ before(() => {
+ cy.login();
+ cy.viewport(375, 667);
+ cy.visit('/app/website');
+
+ cy.visit(`app/organizational-chart`);
+ cy.wait(500);
+ cy.fill_field('company', 'Test Org Chart');
+ cy.get('body').click();
+ cy.wait(500);
+ });
+
+ beforeEach(() => {
+ cy.viewport(375, 667);
+ cy.wait(500);
+
+ cy.window().its('frappe').then(frappe => {
+ return frappe.call('erpnext.tests.ui_test_helpers.create_employee_records');
+ }).as('employee_records');
+ });
+
+ it('renders root nodes', () => {
+ // check rendered root nodes and the node name, title, connections
+ cy.get('.hierarchy-mobile').find('.root-level').children()
+ .should('have.length', 2)
+ .first()
+ .as('first-child');
+
+ cy.get('@first-child').get('.node-name').contains('Test Employee 1');
+ cy.get('@first-child').get('.node-info').find('.node-title').contains('CEO');
+ cy.get('@first-child').get('.node-info').find('.node-connections').contains('· 2');
+ });
+
+ it('expands root node', () => {
+ cy.get('@employee_records').then(employee_records => {
+ cy.get(`#${employee_records.message[1]}`)
+ .click()
+ .should('have.class', 'active');
+
+ // other root node removed
+ cy.get(`#${employee_records.message[0]}`).should('not.exist');
+
+ // children of active root node
+ cy.get('.hierarchy-mobile').find('.level').first().find('ul.node-children').children()
+ .should('have.length', 2)
+
+ cy.get(`[data-parent="${employee_records.message[1]}"]`).first().as('child-node');
+ cy.get('@child-node').should('be.visible');
+
+ cy.get('@child-node')
+ .get('.node-name')
+ .contains('Test Employee 4');
+
+ // connectors between root node and immediate children
+ cy.get(`path[data-parent="${employee_records.message[1]}"]`).as('connectors');
+ cy.get('@connectors')
+ .should('have.length', 2)
+ .should('be.visible')
+
+ cy.get('@connectors')
+ .first()
+ .invoke('attr', 'data-child')
+ .should('eq', employee_records.message[3]);
+ });
+ });
+
+ it('expands child node', () => {
+ cy.get('@employee_records').then(employee_records => {
+ cy.get(`#${employee_records.message[3]}`)
+ .click()
+ .should('have.class', 'active')
+ .as('expanded_node');
+
+ // 2 levels on screen; 1 on active path; 1 collapsed
+ cy.get('.hierarchy-mobile').children().should('have.length', 2);
+ cy.get(`#${employee_records.message[1]}`).should('have.class', 'active-path');
+
+ // children of expanded node visible
+ cy.get('@expanded_node')
+ .next()
+ .should('have.class', 'node-children')
+ .as('node-children');
+
+ cy.get('@node-children').children().should('have.length', 1);
+ cy.get('@node-children')
+ .first()
+ .get('.node-card')
+ .should('have.class', 'active-child')
+ .contains('Test Employee 7');
+
+ // orphan connectors removed
+ cy.get(`#connectors`).children().should('have.length', 2);
+ });
+ });
+
+ it('renders sibling group', () => {
+ cy.get('@employee_records').then(employee_records => {
+ // sibling group visible for parent
+ cy.get(`#${employee_records.message[1]}`)
+ .next()
+ .as('sibling_group');
+
+ cy.get('@sibling_group')
+ .should('have.attr', 'data-parent', 'undefined')
+ .should('have.class', 'node-group')
+ .and('have.class', 'collapsed')
+
+ cy.get('@sibling_group').get('.avatar-group').children().as('siblings');
+ cy.get('@siblings').should('have.length', 1);
+ cy.get('@siblings')
+ .first()
+ .should('have.attr', 'title', 'Test Employee 1');
+
+ });
+ });
+
+ it('expands previous level nodes', () => {
+ cy.get('@employee_records').then(employee_records => {
+ cy.get(`#${employee_records.message[6]}`)
+ .click()
+ .should('have.class', 'active');
+
+ // clicking on previous level node should remove all the nodes ahead
+ // and expand that node
+ cy.get(`#${employee_records.message[3]}`).click();
+ cy.get(`#${employee_records.message[3]}`)
+ .should('have.class', 'active')
+ .should('not.have.class', 'active-path');
+
+ cy.get(`#${employee_records.message[6]}`).should('have.class', 'active-child');
+ cy.get('.hierarchy-mobile').children().should('have.length', 2);
+ cy.get(`#connectors`).children().should('have.length', 2);
+ });
+ });
+
+ it('expands sibling group', () => {
+ cy.get('@employee_records').then(employee_records => {
+ // sibling group visible for parent
+ cy.get(`#${employee_records.message[6]}`).click()
+
+ cy.get(`#${employee_records.message[3]}`)
+ .next()
+ .click();
+
+ // siblings of parent should be visible
+ cy.get('.hierarchy-mobile').prev().as('sibling_group');
+ cy.get('@sibling_group')
+ .should('exist')
+ .should('have.class', 'sibling-group')
+ .should('not.have.class', 'collapsed');
+
+ cy.get(`#${employee_records.message[1]}`)
+ .should('be.visible')
+ .should('have.class', 'active');
+
+ cy.get(`[data-parent="${employee_records.message[1]}"]`)
+ .should('be.visible')
+ .should('have.length', 2)
+ .should('have.class', 'active-child');
+ });
+ });
+
+ it('goes to the respective level after clicking on non-collapsed sibling group', () => {
+ // click on non-collapsed sibling group
+ cy.get('.hierarchy-mobile')
+ .prev()
+ .click();
+
+ // should take you to that level
+ cy.get('.hierarchy-mobile').find('li.level .node-card').should('have.length', 2);
+ });
+
+ it('edit node navigates to employee master', () => {
+ cy.get('@employee_records').then(employee_records => {
+ cy.get(`#${employee_records.message[0]}`).find('.btn-edit-node')
+ .click();
+
+ cy.url().should('include', `/employee/${employee_records.message[0]}`);
+ });
+ });
+});
diff --git a/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js b/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
index 5a6f168876..bd7946a1e1 100644
--- a/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
+++ b/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
@@ -128,6 +128,9 @@ erpnext.HierarchyChartMobile = class {
if (this.$hierarchy)
this.$hierarchy.remove();
+ if (this.$sibling_group)
+ this.$sibling_group.empty();
+
this.$hierarchy = $(
`
@@ -173,7 +176,7 @@ erpnext.HierarchyChartMobile = class {
if (this.$sibling_group) {
const sibling_parent = this.$sibling_group.find('.node-group').attr('data-parent');
- if (node.parent_id !== sibling_parent)
+ if (node.parent_id !== undefined && node.parent_id != sibling_parent)
this.$sibling_group.empty();
}
@@ -376,9 +379,10 @@ erpnext.HierarchyChartMobile = class {
let node_element = $(`#${node.id}`);
node_element.click(function() {
- let el = $(this).detach();
+ let el = undefined;
if (node.is_root) {
+ el = $(this).detach();
me.$hierarchy.empty();
$(`#connectors`).empty();
me.add_node_to_hierarchy(el, node);
@@ -386,6 +390,7 @@ erpnext.HierarchyChartMobile = class {
me.remove_levels_after_node(node);
me.remove_orphaned_connectors();
} else {
+ el = $(this).detach();
me.add_node_to_hierarchy(el, node);
me.collapse_node();
}
@@ -514,10 +519,10 @@ erpnext.HierarchyChartMobile = class {
level = $('.hierarchy-mobile > li:eq('+ level + ')');
level.nextAll('li').remove();
- let current_node = level.find(`#${node.id}`);
let node_object = this.nodes[node.id];
-
+ let current_node = level.find(`#${node.id}`).detach();
current_node.removeClass('active-child active-path');
+
node_object.expanded = 0;
node_object.$children = undefined;
diff --git a/erpnext/tests/ui_test_helpers.py b/erpnext/tests/ui_test_helpers.py
index 8e67b1cd34..99748dca02 100644
--- a/erpnext/tests/ui_test_helpers.py
+++ b/erpnext/tests/ui_test_helpers.py
@@ -11,10 +11,11 @@ def create_employee_records():
emp2 = create_employee('Test Employee 2', 'CTO')
emp3 = create_employee('Test Employee 3', 'Head of Marketing and Sales', emp1)
emp4 = create_employee('Test Employee 4', 'Project Manager', emp2)
- emp5 = create_employee('Test Employee 5', 'Analyst', emp3)
- emp6 = create_employee('Test Employee 6', 'Software Developer', emp4)
+ emp5 = create_employee('Test Employee 5', 'Engineer', emp2)
+ emp6 = create_employee('Test Employee 6', 'Analyst', emp3)
+ emp7 = create_employee('Test Employee 7', 'Software Developer', emp4)
- employees = [emp1, emp2, emp3, emp4, emp5, emp6]
+ employees = [emp1, emp2, emp3, emp4, emp5, emp6, emp7]
return employees
def create_company():
From 525d4d47761d8b635142d7f5847ca29cd24eca15 Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Thu, 15 Jul 2021 19:32:15 +0530
Subject: [PATCH 303/386] fix: sider
---
cypress/integration/test_organizational_chart_desktop.js | 4 ++--
cypress/integration/test_organizational_chart_mobile.js | 8 ++++----
erpnext/tests/ui_test_helpers.py | 3 +--
3 files changed, 7 insertions(+), 8 deletions(-)
diff --git a/cypress/integration/test_organizational_chart_desktop.js b/cypress/integration/test_organizational_chart_desktop.js
index d50d551330..807ef5731a 100644
--- a/cypress/integration/test_organizational_chart_desktop.js
+++ b/cypress/integration/test_organizational_chart_desktop.js
@@ -29,7 +29,7 @@ context('Organizational Chart', () => {
// check children of first node
cy.get('@employee_records').then(employee_records => {
// children of 1st root visible
- cy.get(`[data-parent="${employee_records.message[0]}"]`).as('child-node')
+ cy.get(`[data-parent="${employee_records.message[0]}"]`).as('child-node');
cy.get('@child-node')
.should('have.length', 1)
.should('be.visible');
@@ -39,7 +39,7 @@ context('Organizational Chart', () => {
cy.get(`path[data-parent="${employee_records.message[0]}"]`)
.should('be.visible')
.invoke('attr', 'data-child')
- .should('equal', employee_records.message[2]);
+ .should('equal', employee_records.message[2]);
});
});
diff --git a/cypress/integration/test_organizational_chart_mobile.js b/cypress/integration/test_organizational_chart_mobile.js
index 656051289f..f48972bdc6 100644
--- a/cypress/integration/test_organizational_chart_mobile.js
+++ b/cypress/integration/test_organizational_chart_mobile.js
@@ -43,7 +43,7 @@ context('Organizational Chart Mobile', () => {
// children of active root node
cy.get('.hierarchy-mobile').find('.level').first().find('ul.node-children').children()
- .should('have.length', 2)
+ .should('have.length', 2);
cy.get(`[data-parent="${employee_records.message[1]}"]`).first().as('child-node');
cy.get('@child-node').should('be.visible');
@@ -56,7 +56,7 @@ context('Organizational Chart Mobile', () => {
cy.get(`path[data-parent="${employee_records.message[1]}"]`).as('connectors');
cy.get('@connectors')
.should('have.length', 2)
- .should('be.visible')
+ .should('be.visible');
cy.get('@connectors')
.first()
@@ -104,7 +104,7 @@ context('Organizational Chart Mobile', () => {
cy.get('@sibling_group')
.should('have.attr', 'data-parent', 'undefined')
.should('have.class', 'node-group')
- .and('have.class', 'collapsed')
+ .and('have.class', 'collapsed');
cy.get('@sibling_group').get('.avatar-group').children().as('siblings');
cy.get('@siblings').should('have.length', 1);
@@ -137,7 +137,7 @@ context('Organizational Chart Mobile', () => {
it('expands sibling group', () => {
cy.get('@employee_records').then(employee_records => {
// sibling group visible for parent
- cy.get(`#${employee_records.message[6]}`).click()
+ cy.get(`#${employee_records.message[6]}`).click();
cy.get(`#${employee_records.message[3]}`)
.next()
diff --git a/erpnext/tests/ui_test_helpers.py b/erpnext/tests/ui_test_helpers.py
index 99748dca02..f66d69ba23 100644
--- a/erpnext/tests/ui_test_helpers.py
+++ b/erpnext/tests/ui_test_helpers.py
@@ -1,10 +1,9 @@
import frappe
-from frappe import _
from frappe.utils import getdate
@frappe.whitelist()
def create_employee_records():
- company = create_company()
+ create_company()
create_missing_designation()
emp1 = create_employee('Test Employee 1', 'CEO')
From 9dfddca22e31b35e1d4650cc75ac088f62000d1a Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Fri, 16 Jul 2021 10:32:38 +0530
Subject: [PATCH 304/386] ci(cypress): use env variable for key
documentation ref: https://docs.cypress.io/guides/guides/command-line\#cypress-run
---
.github/workflows/ui-tests.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/ui-tests.yml b/.github/workflows/ui-tests.yml
index 9e29b6f1d2..661525bedc 100644
--- a/.github/workflows/ui-tests.yml
+++ b/.github/workflows/ui-tests.yml
@@ -102,7 +102,7 @@ jobs:
- name: UI Tests
run: cd ~/frappe-bench/ && bench --site test_site run-ui-tests erpnext --headless
env:
- CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
+ CYPRESS_RECORD_KEY: 60a8e3bf-08f5-45b1-9269-2b207d7d30cd
- name: Show bench console if tests failed
if: ${{ failure() }}
From e126b370b01de0488da33d6fef72b58f8f3e466f Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Mon, 19 Jul 2021 16:26:17 +0530
Subject: [PATCH 305/386] fix(tests): clear filter before typing
---
cypress/integration/test_organizational_chart_desktop.js | 4 ++++
cypress/integration/test_organizational_chart_mobile.js | 4 ++++
2 files changed, 8 insertions(+)
diff --git a/cypress/integration/test_organizational_chart_desktop.js b/cypress/integration/test_organizational_chart_desktop.js
index 807ef5731a..ae8e75f219 100644
--- a/cypress/integration/test_organizational_chart_desktop.js
+++ b/cypress/integration/test_organizational_chart_desktop.js
@@ -2,6 +2,10 @@ context('Organizational Chart', () => {
before(() => {
cy.login();
cy.visit('/app/website');
+ cy.awesomebar('Organizational Chart');
+
+ cy.get('.frappe-control[data-fieldname=company] input').focus().as('input');
+ cy.get('@input').clear().type('Test Org Chart');
cy.visit(`app/organizational-chart`);
cy.fill_field('company', 'Test Org Chart');
diff --git a/cypress/integration/test_organizational_chart_mobile.js b/cypress/integration/test_organizational_chart_mobile.js
index f48972bdc6..093e808da0 100644
--- a/cypress/integration/test_organizational_chart_mobile.js
+++ b/cypress/integration/test_organizational_chart_mobile.js
@@ -3,6 +3,10 @@ context('Organizational Chart Mobile', () => {
cy.login();
cy.viewport(375, 667);
cy.visit('/app/website');
+ cy.awesomebar('Organizational Chart');
+
+ cy.get('.frappe-control[data-fieldname=company] input').focus().as('input');
+ cy.get('@input').clear().type('Test Org Chart');
cy.visit(`app/organizational-chart`);
cy.wait(500);
From e5406ece83229949b620823cb60d51aa416d0cb1 Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Mon, 19 Jul 2021 17:03:17 +0530
Subject: [PATCH 306/386] fix(tests): apply filters correctly
---
.../test_organizational_chart_desktop.js | 9 ++++---
.../test_organizational_chart_mobile.js | 24 +++++++++----------
2 files changed, 16 insertions(+), 17 deletions(-)
diff --git a/cypress/integration/test_organizational_chart_desktop.js b/cypress/integration/test_organizational_chart_desktop.js
index ae8e75f219..cb12eb5c0c 100644
--- a/cypress/integration/test_organizational_chart_desktop.js
+++ b/cypress/integration/test_organizational_chart_desktop.js
@@ -5,16 +5,15 @@ context('Organizational Chart', () => {
cy.awesomebar('Organizational Chart');
cy.get('.frappe-control[data-fieldname=company] input').focus().as('input');
- cy.get('@input').clear().type('Test Org Chart');
+ cy.get('@input').clear().wait(200).type('Test Org Chart');
+ cy.get('@input').type('{enter}', { delay: 100 });
+ cy.get('@input').blur();
- cy.visit(`app/organizational-chart`);
- cy.fill_field('company', 'Test Org Chart');
- cy.get('body').click();
cy.wait(500);
});
beforeEach(() => {
- cy.window().its('frappe').then(frappe => {
+ return cy.window().its('frappe').then(frappe => {
return frappe.call('erpnext.tests.ui_test_helpers.create_employee_records');
}).as('employee_records');
});
diff --git a/cypress/integration/test_organizational_chart_mobile.js b/cypress/integration/test_organizational_chart_mobile.js
index 093e808da0..a1d3c0083c 100644
--- a/cypress/integration/test_organizational_chart_mobile.js
+++ b/cypress/integration/test_organizational_chart_mobile.js
@@ -6,12 +6,10 @@ context('Organizational Chart Mobile', () => {
cy.awesomebar('Organizational Chart');
cy.get('.frappe-control[data-fieldname=company] input').focus().as('input');
- cy.get('@input').clear().type('Test Org Chart');
+ cy.get('@input').clear().wait(200).type('Test Org Chart');
+ cy.get('@input').type('{enter}', { delay: 100 });
+ cy.get('@input').blur();
- cy.visit(`app/organizational-chart`);
- cy.wait(500);
- cy.fill_field('company', 'Test Org Chart');
- cy.get('body').click();
cy.wait(500);
});
@@ -19,7 +17,7 @@ context('Organizational Chart Mobile', () => {
cy.viewport(375, 667);
cy.wait(500);
- cy.window().its('frappe').then(frappe => {
+ return cy.window().its('frappe').then(frappe => {
return frappe.call('erpnext.tests.ui_test_helpers.create_employee_records');
}).as('employee_records');
});
@@ -166,13 +164,15 @@ context('Organizational Chart Mobile', () => {
});
it('goes to the respective level after clicking on non-collapsed sibling group', () => {
- // click on non-collapsed sibling group
- cy.get('.hierarchy-mobile')
- .prev()
- .click();
+ cy.get('@employee_records').then(() => {
+ // click on non-collapsed sibling group
+ cy.get('.hierarchy-mobile')
+ .prev()
+ .click();
- // should take you to that level
- cy.get('.hierarchy-mobile').find('li.level .node-card').should('have.length', 2);
+ // should take you to that level
+ cy.get('.hierarchy-mobile').find('li.level .node-card').should('have.length', 2);
+ });
});
it('edit node navigates to employee master', () => {
From 2c7b500d1687f4b91f7f994e03139ca0407af558 Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Mon, 19 Jul 2021 17:34:15 +0530
Subject: [PATCH 307/386] fix: tests
---
cypress/integration/test_organizational_chart_desktop.js | 6 +++---
cypress/integration/test_organizational_chart_mobile.js | 6 +++---
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/cypress/integration/test_organizational_chart_desktop.js b/cypress/integration/test_organizational_chart_desktop.js
index cb12eb5c0c..95592e2f6a 100644
--- a/cypress/integration/test_organizational_chart_desktop.js
+++ b/cypress/integration/test_organizational_chart_desktop.js
@@ -4,10 +4,10 @@ context('Organizational Chart', () => {
cy.visit('/app/website');
cy.awesomebar('Organizational Chart');
- cy.get('.frappe-control[data-fieldname=company] input').focus().as('input');
- cy.get('@input').clear().wait(200).type('Test Org Chart');
+ cy.get('.frappe-control[data-fieldname=company] input').first().focus().as('input');
+ cy.get('@input').clear().wait(200).type('Test Org Chart', { force: true });
cy.get('@input').type('{enter}', { delay: 100 });
- cy.get('@input').blur();
+ cy.get('@input').blur({ force: true });
cy.wait(500);
});
diff --git a/cypress/integration/test_organizational_chart_mobile.js b/cypress/integration/test_organizational_chart_mobile.js
index a1d3c0083c..632d15ba6c 100644
--- a/cypress/integration/test_organizational_chart_mobile.js
+++ b/cypress/integration/test_organizational_chart_mobile.js
@@ -5,10 +5,10 @@ context('Organizational Chart Mobile', () => {
cy.visit('/app/website');
cy.awesomebar('Organizational Chart');
- cy.get('.frappe-control[data-fieldname=company] input').focus().as('input');
- cy.get('@input').clear().wait(200).type('Test Org Chart');
+ cy.get('.frappe-control[data-fieldname=company] input').first().focus().as('input');
+ cy.get('@input').clear().wait(200).type('Test Org Chart', { force: true });
cy.get('@input').type('{enter}', { delay: 100 });
- cy.get('@input').blur();
+ cy.get('@input').blur({ force: true });
cy.wait(500);
});
From 982a097d7ac3d324ddc43c567227e318ac071ee0 Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Mon, 19 Jul 2021 22:19:28 +0530
Subject: [PATCH 308/386] fix: tests
---
.../test_organizational_chart_desktop.js | 31 +++++++---------
.../test_organizational_chart_mobile.js | 37 ++++++++-----------
erpnext/tests/ui_test_helpers.py | 6 +++
3 files changed, 34 insertions(+), 40 deletions(-)
diff --git a/cypress/integration/test_organizational_chart_desktop.js b/cypress/integration/test_organizational_chart_desktop.js
index 95592e2f6a..0493732812 100644
--- a/cypress/integration/test_organizational_chart_desktop.js
+++ b/cypress/integration/test_organizational_chart_desktop.js
@@ -1,21 +1,17 @@
context('Organizational Chart', () => {
before(() => {
cy.login();
- cy.visit('/app/website');
+ cy.visit('/app');
+
+ cy.call('erpnext.tests.ui_test_helpers.create_employee_records');
cy.awesomebar('Organizational Chart');
- cy.get('.frappe-control[data-fieldname=company] input').first().focus().as('input');
- cy.get('@input').clear().wait(200).type('Test Org Chart', { force: true });
- cy.get('@input').type('{enter}', { delay: 100 });
+ cy.get('.frappe-control[data-fieldname=company] input').focus().as('input');
+ cy.get('@input')
+ .clear({ force: true })
+ .type('Test Org Chart', { force: true });
+ cy.wait(200);
cy.get('@input').blur({ force: true });
-
- cy.wait(500);
- });
-
- beforeEach(() => {
- return cy.window().its('frappe').then(frappe => {
- return frappe.call('erpnext.tests.ui_test_helpers.create_employee_records');
- }).as('employee_records');
});
it('renders root nodes and loads children for the first expandable node', () => {
@@ -29,8 +25,7 @@ context('Organizational Chart', () => {
cy.get('@first-child').get('.node-info').find('.node-title').contains('CEO');
cy.get('@first-child').get('.node-info').find('.node-connections').contains('· 2 Connections');
- // check children of first node
- cy.get('@employee_records').then(employee_records => {
+ cy.call('erpnext.tests.ui_test_helpers.get_employee_records').then(employee_records => {
// children of 1st root visible
cy.get(`[data-parent="${employee_records.message[0]}"]`).as('child-node');
cy.get('@child-node')
@@ -47,7 +42,7 @@ context('Organizational Chart', () => {
});
it('hides active nodes children and connectors on expanding sibling node', () => {
- cy.get('@employee_records').then(employee_records => {
+ cy.call('erpnext.tests.ui_test_helpers.get_employee_records').then(employee_records => {
// click sibling
cy.get(`#${employee_records.message[1]}`)
.click()
@@ -60,7 +55,7 @@ context('Organizational Chart', () => {
});
it('collapses previous level nodes and refreshes connectors on expanding child node', () => {
- cy.get('@employee_records').then(employee_records => {
+ cy.call('erpnext.tests.ui_test_helpers.get_employee_records').then(employee_records => {
// click child node
cy.get(`#${employee_records.message[3]}`)
.click()
@@ -81,7 +76,7 @@ context('Organizational Chart', () => {
});
it('expands previous level nodes', () => {
- cy.get('@employee_records').then(employee_records => {
+ cy.call('erpnext.tests.ui_test_helpers.get_employee_records').then(employee_records => {
cy.get(`#${employee_records.message[0]}`)
.click()
.should('have.class', 'active');
@@ -95,7 +90,7 @@ context('Organizational Chart', () => {
});
it('edit node navigates to employee master', () => {
- cy.get('@employee_records').then(employee_records => {
+ cy.call('erpnext.tests.ui_test_helpers.get_employee_records').then(employee_records => {
cy.get(`#${employee_records.message[0]}`).find('.btn-edit-node')
.click();
diff --git a/cypress/integration/test_organizational_chart_mobile.js b/cypress/integration/test_organizational_chart_mobile.js
index 632d15ba6c..1dcfbcfeb1 100644
--- a/cypress/integration/test_organizational_chart_mobile.js
+++ b/cypress/integration/test_organizational_chart_mobile.js
@@ -2,24 +2,17 @@ context('Organizational Chart Mobile', () => {
before(() => {
cy.login();
cy.viewport(375, 667);
- cy.visit('/app/website');
+ cy.visit('/app');
+
+ cy.call('erpnext.tests.ui_test_helpers.create_employee_records');
cy.awesomebar('Organizational Chart');
- cy.get('.frappe-control[data-fieldname=company] input').first().focus().as('input');
- cy.get('@input').clear().wait(200).type('Test Org Chart', { force: true });
- cy.get('@input').type('{enter}', { delay: 100 });
+ cy.get('.frappe-control[data-fieldname=company] input').focus().as('input');
+ cy.get('@input')
+ .clear({ force: true })
+ .type('Test Org Chart', { force: true });
+ cy.wait(200);
cy.get('@input').blur({ force: true });
-
- cy.wait(500);
- });
-
- beforeEach(() => {
- cy.viewport(375, 667);
- cy.wait(500);
-
- return cy.window().its('frappe').then(frappe => {
- return frappe.call('erpnext.tests.ui_test_helpers.create_employee_records');
- }).as('employee_records');
});
it('renders root nodes', () => {
@@ -35,7 +28,7 @@ context('Organizational Chart Mobile', () => {
});
it('expands root node', () => {
- cy.get('@employee_records').then(employee_records => {
+ cy.call('erpnext.tests.ui_test_helpers.get_employee_records').then(employee_records => {
cy.get(`#${employee_records.message[1]}`)
.click()
.should('have.class', 'active');
@@ -68,7 +61,7 @@ context('Organizational Chart Mobile', () => {
});
it('expands child node', () => {
- cy.get('@employee_records').then(employee_records => {
+ cy.call('erpnext.tests.ui_test_helpers.get_employee_records').then(employee_records => {
cy.get(`#${employee_records.message[3]}`)
.click()
.should('have.class', 'active')
@@ -97,7 +90,7 @@ context('Organizational Chart Mobile', () => {
});
it('renders sibling group', () => {
- cy.get('@employee_records').then(employee_records => {
+ cy.call('erpnext.tests.ui_test_helpers.get_employee_records').then(employee_records => {
// sibling group visible for parent
cy.get(`#${employee_records.message[1]}`)
.next()
@@ -118,7 +111,7 @@ context('Organizational Chart Mobile', () => {
});
it('expands previous level nodes', () => {
- cy.get('@employee_records').then(employee_records => {
+ cy.call('erpnext.tests.ui_test_helpers.get_employee_records').then(employee_records => {
cy.get(`#${employee_records.message[6]}`)
.click()
.should('have.class', 'active');
@@ -137,7 +130,7 @@ context('Organizational Chart Mobile', () => {
});
it('expands sibling group', () => {
- cy.get('@employee_records').then(employee_records => {
+ cy.call('erpnext.tests.ui_test_helpers.get_employee_records').then(employee_records => {
// sibling group visible for parent
cy.get(`#${employee_records.message[6]}`).click();
@@ -164,7 +157,7 @@ context('Organizational Chart Mobile', () => {
});
it('goes to the respective level after clicking on non-collapsed sibling group', () => {
- cy.get('@employee_records').then(() => {
+ cy.call('erpnext.tests.ui_test_helpers.get_employee_records').then(() => {
// click on non-collapsed sibling group
cy.get('.hierarchy-mobile')
.prev()
@@ -176,7 +169,7 @@ context('Organizational Chart Mobile', () => {
});
it('edit node navigates to employee master', () => {
- cy.get('@employee_records').then(employee_records => {
+ cy.call('erpnext.tests.ui_test_helpers.get_employee_records').then(employee_records => {
cy.get(`#${employee_records.message[0]}`).find('.btn-edit-node')
.click();
diff --git a/erpnext/tests/ui_test_helpers.py b/erpnext/tests/ui_test_helpers.py
index f66d69ba23..fc3aa29824 100644
--- a/erpnext/tests/ui_test_helpers.py
+++ b/erpnext/tests/ui_test_helpers.py
@@ -17,6 +17,12 @@ def create_employee_records():
employees = [emp1, emp2, emp3, emp4, emp5, emp6, emp7]
return employees
+@frappe.whitelist()
+def get_employee_records():
+ return frappe.db.get_list('Employee', filters={
+ 'company': 'Test Org Chart'
+ }, pluck='name', order_by='name')
+
def create_company():
company = frappe.db.exists('Company', 'Test Org Chart')
if not company:
From 76d192f099e3fd1c88c4c13f299919ab2571b1b8 Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Mon, 19 Jul 2021 23:34:02 +0530
Subject: [PATCH 309/386] fix: tests
---
.../test_organizational_chart_desktop.js | 19 +++++++++----------
.../test_organizational_chart_mobile.js | 19 +++++++++----------
2 files changed, 18 insertions(+), 20 deletions(-)
diff --git a/cypress/integration/test_organizational_chart_desktop.js b/cypress/integration/test_organizational_chart_desktop.js
index 0493732812..52863f18e0 100644
--- a/cypress/integration/test_organizational_chart_desktop.js
+++ b/cypress/integration/test_organizational_chart_desktop.js
@@ -1,17 +1,16 @@
context('Organizational Chart', () => {
before(() => {
cy.login();
- cy.visit('/app');
-
- cy.call('erpnext.tests.ui_test_helpers.create_employee_records');
+ cy.visit('/app/website');
cy.awesomebar('Organizational Chart');
- cy.get('.frappe-control[data-fieldname=company] input').focus().as('input');
- cy.get('@input')
- .clear({ force: true })
- .type('Test Org Chart', { force: true });
- cy.wait(200);
- cy.get('@input').blur({ force: true });
+ cy.call('erpnext.tests.ui_test_helpers.create_employee_records').then(() => {
+ cy.get('.frappe-control[data-fieldname=company] input').focus().as('input');
+ cy.get('@input')
+ .clear({ force: true })
+ .type('Test Org Chart{enter}', { force: true })
+ .blur({ force: true });
+ });
});
it('renders root nodes and loads children for the first expandable node', () => {
@@ -27,7 +26,7 @@ context('Organizational Chart', () => {
cy.call('erpnext.tests.ui_test_helpers.get_employee_records').then(employee_records => {
// children of 1st root visible
- cy.get(`[data-parent="${employee_records.message[0]}"]`).as('child-node');
+ cy.get(`div[data-parent="${employee_records.message[0]}"]`).as('child-node');
cy.get('@child-node')
.should('have.length', 1)
.should('be.visible');
diff --git a/cypress/integration/test_organizational_chart_mobile.js b/cypress/integration/test_organizational_chart_mobile.js
index 1dcfbcfeb1..2272a31046 100644
--- a/cypress/integration/test_organizational_chart_mobile.js
+++ b/cypress/integration/test_organizational_chart_mobile.js
@@ -2,17 +2,16 @@ context('Organizational Chart Mobile', () => {
before(() => {
cy.login();
cy.viewport(375, 667);
- cy.visit('/app');
-
- cy.call('erpnext.tests.ui_test_helpers.create_employee_records');
+ cy.visit('/app/website');
cy.awesomebar('Organizational Chart');
- cy.get('.frappe-control[data-fieldname=company] input').focus().as('input');
- cy.get('@input')
- .clear({ force: true })
- .type('Test Org Chart', { force: true });
- cy.wait(200);
- cy.get('@input').blur({ force: true });
+ cy.call('erpnext.tests.ui_test_helpers.create_employee_records').then(() => {
+ cy.get('.frappe-control[data-fieldname=company] input').focus().as('input');
+ cy.get('@input')
+ .clear({ force: true })
+ .type('Test Org Chart{enter}', { force: true })
+ .blur({ force: true });
+ });
});
it('renders root nodes', () => {
@@ -40,7 +39,7 @@ context('Organizational Chart Mobile', () => {
cy.get('.hierarchy-mobile').find('.level').first().find('ul.node-children').children()
.should('have.length', 2);
- cy.get(`[data-parent="${employee_records.message[1]}"]`).first().as('child-node');
+ cy.get(`div[data-parent="${employee_records.message[1]}"]`).first().as('child-node');
cy.get('@child-node').should('be.visible');
cy.get('@child-node')
From d32da5507f5fe7ffc55a7baf13ba0ada57efa3eb Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Tue, 20 Jul 2021 10:23:52 +0530
Subject: [PATCH 310/386] fix(test): increase timeout for record creation
---
.../test_organizational_chart_desktop.js | 27 ++++++++++++++-----
.../test_organizational_chart_mobile.js | 27 ++++++++++++++-----
2 files changed, 42 insertions(+), 12 deletions(-)
diff --git a/cypress/integration/test_organizational_chart_desktop.js b/cypress/integration/test_organizational_chart_desktop.js
index 52863f18e0..0da4e560a7 100644
--- a/cypress/integration/test_organizational_chart_desktop.js
+++ b/cypress/integration/test_organizational_chart_desktop.js
@@ -4,12 +4,27 @@ context('Organizational Chart', () => {
cy.visit('/app/website');
cy.awesomebar('Organizational Chart');
- cy.call('erpnext.tests.ui_test_helpers.create_employee_records').then(() => {
- cy.get('.frappe-control[data-fieldname=company] input').focus().as('input');
- cy.get('@input')
- .clear({ force: true })
- .type('Test Org Chart{enter}', { force: true })
- .blur({ force: true });
+ cy.window().its('frappe.csrf_token').then(csrf_token => {
+ return cy.request({
+ url: `/api/method/erpnext.tests.ui_test_helpers.create_employee_records`,
+ method: 'POST',
+ headers: {
+ Accept: 'application/json',
+ 'Content-Type': 'application/json',
+ 'X-Frappe-CSRF-Token': csrf_token
+ },
+ timeout: 60000
+ })
+ .then(res => {
+ expect(res.status).eq(200);
+ cy.get('.frappe-control[data-fieldname=company] input').focus().as('input');
+ cy.get('@input')
+ .clear({ force: true })
+ .type('Test Org Chart{enter}', { force: true })
+ .blur({ force: true });
+
+ cy.get('body').click();
+ });
});
});
diff --git a/cypress/integration/test_organizational_chart_mobile.js b/cypress/integration/test_organizational_chart_mobile.js
index 2272a31046..0374678a1a 100644
--- a/cypress/integration/test_organizational_chart_mobile.js
+++ b/cypress/integration/test_organizational_chart_mobile.js
@@ -5,12 +5,27 @@ context('Organizational Chart Mobile', () => {
cy.visit('/app/website');
cy.awesomebar('Organizational Chart');
- cy.call('erpnext.tests.ui_test_helpers.create_employee_records').then(() => {
- cy.get('.frappe-control[data-fieldname=company] input').focus().as('input');
- cy.get('@input')
- .clear({ force: true })
- .type('Test Org Chart{enter}', { force: true })
- .blur({ force: true });
+ cy.window().its('frappe.csrf_token').then(csrf_token => {
+ return cy.request({
+ url: `/api/method/erpnext.tests.ui_test_helpers.create_employee_records`,
+ method: 'POST',
+ headers: {
+ Accept: 'application/json',
+ 'Content-Type': 'application/json',
+ 'X-Frappe-CSRF-Token': csrf_token
+ },
+ timeout: 60000
+ })
+ .then(res => {
+ expect(res.status).eq(200);
+ cy.get('.frappe-control[data-fieldname=company] input').focus().as('input');
+ cy.get('@input')
+ .clear({ force: true })
+ .type('Test Org Chart{enter}', { force: true })
+ .blur({ force: true });
+
+ cy.get('body').click();
+ });
});
});
From 9c63fcb01bd16d453a0af4b2baf13b7e51db109e Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Tue, 20 Jul 2021 10:55:05 +0530
Subject: [PATCH 311/386] fix: sider
---
.../test_organizational_chart_desktop.js | 3 +-
.../test_organizational_chart_mobile.js | 36 +++++++++----------
2 files changed, 19 insertions(+), 20 deletions(-)
diff --git a/cypress/integration/test_organizational_chart_desktop.js b/cypress/integration/test_organizational_chart_desktop.js
index 0da4e560a7..57b7f7dced 100644
--- a/cypress/integration/test_organizational_chart_desktop.js
+++ b/cypress/integration/test_organizational_chart_desktop.js
@@ -14,8 +14,7 @@ context('Organizational Chart', () => {
'X-Frappe-CSRF-Token': csrf_token
},
timeout: 60000
- })
- .then(res => {
+ }).then(res => {
expect(res.status).eq(200);
cy.get('.frappe-control[data-fieldname=company] input').focus().as('input');
cy.get('@input')
diff --git a/cypress/integration/test_organizational_chart_mobile.js b/cypress/integration/test_organizational_chart_mobile.js
index 0374678a1a..214229f6f6 100644
--- a/cypress/integration/test_organizational_chart_mobile.js
+++ b/cypress/integration/test_organizational_chart_mobile.js
@@ -7,25 +7,25 @@ context('Organizational Chart Mobile', () => {
cy.window().its('frappe.csrf_token').then(csrf_token => {
return cy.request({
- url: `/api/method/erpnext.tests.ui_test_helpers.create_employee_records`,
- method: 'POST',
- headers: {
- Accept: 'application/json',
- 'Content-Type': 'application/json',
- 'X-Frappe-CSRF-Token': csrf_token
- },
- timeout: 60000
- })
- .then(res => {
- expect(res.status).eq(200);
- cy.get('.frappe-control[data-fieldname=company] input').focus().as('input');
- cy.get('@input')
- .clear({ force: true })
- .type('Test Org Chart{enter}', { force: true })
- .blur({ force: true });
+ url: `/api/method/erpnext.tests.ui_test_helpers.create_employee_records`,
+ method: 'POST',
+ headers: {
+ Accept: 'application/json',
+ 'Content-Type': 'application/json',
+ 'X-Frappe-CSRF-Token': csrf_token
+ },
+ timeout: 60000
+ })
+ .then(res => {
+ expect(res.status).eq(200);
+ cy.get('.frappe-control[data-fieldname=company] input').focus().as('input');
+ cy.get('@input')
+ .clear({ force: true })
+ .type('Test Org Chart{enter}', { force: true })
+ .blur({ force: true });
- cy.get('body').click();
- });
+ cy.get('body').click();
+ });
});
});
From 951b3a43132902f882774dbde9e9026bd6fcd241 Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Tue, 20 Jul 2021 12:19:44 +0530
Subject: [PATCH 312/386] fix: sider
---
.../test_organizational_chart_desktop.js | 2 --
.../test_organizational_chart_mobile.js | 35 +++++++++----------
2 files changed, 16 insertions(+), 21 deletions(-)
diff --git a/cypress/integration/test_organizational_chart_desktop.js b/cypress/integration/test_organizational_chart_desktop.js
index 57b7f7dced..fb46bbb433 100644
--- a/cypress/integration/test_organizational_chart_desktop.js
+++ b/cypress/integration/test_organizational_chart_desktop.js
@@ -21,8 +21,6 @@ context('Organizational Chart', () => {
.clear({ force: true })
.type('Test Org Chart{enter}', { force: true })
.blur({ force: true });
-
- cy.get('body').click();
});
});
});
diff --git a/cypress/integration/test_organizational_chart_mobile.js b/cypress/integration/test_organizational_chart_mobile.js
index 214229f6f6..df90dbfa22 100644
--- a/cypress/integration/test_organizational_chart_mobile.js
+++ b/cypress/integration/test_organizational_chart_mobile.js
@@ -7,25 +7,22 @@ context('Organizational Chart Mobile', () => {
cy.window().its('frappe.csrf_token').then(csrf_token => {
return cy.request({
- url: `/api/method/erpnext.tests.ui_test_helpers.create_employee_records`,
- method: 'POST',
- headers: {
- Accept: 'application/json',
- 'Content-Type': 'application/json',
- 'X-Frappe-CSRF-Token': csrf_token
- },
- timeout: 60000
- })
- .then(res => {
- expect(res.status).eq(200);
- cy.get('.frappe-control[data-fieldname=company] input').focus().as('input');
- cy.get('@input')
- .clear({ force: true })
- .type('Test Org Chart{enter}', { force: true })
- .blur({ force: true });
-
- cy.get('body').click();
- });
+ url: `/api/method/erpnext.tests.ui_test_helpers.create_employee_records`,
+ method: 'POST',
+ headers: {
+ Accept: 'application/json',
+ 'Content-Type': 'application/json',
+ 'X-Frappe-CSRF-Token': csrf_token
+ },
+ timeout: 60000
+ }).then(res => {
+ expect(res.status).eq(200);
+ cy.get('.frappe-control[data-fieldname=company] input').focus().as('input');
+ cy.get('@input')
+ .clear({ force: true })
+ .type('Test Org Chart{enter}', { force: true })
+ .blur({ force: true });
+ });
});
});
From 6f799d17ce77b25575b65c71fdb2fd5bd843bf9e Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Wed, 21 Jul 2021 23:19:47 +0530
Subject: [PATCH 313/386] feat: Expand All nodes option in Desktop view
---
.../hierarchy_chart_desktop.js | 152 +++++++++++++++---
erpnext/public/scss/hierarchy_chart.scss | 1 +
erpnext/utilities/hierarchy_chart.py | 29 ++++
3 files changed, 159 insertions(+), 23 deletions(-)
create mode 100644 erpnext/utilities/hierarchy_chart.py
diff --git a/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js b/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
index fe4d17c210..694c26567a 100644
--- a/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
+++ b/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
@@ -36,7 +36,11 @@ erpnext.HierarchyChart = class {
me.nodes[this.id] = this;
me.make_node_element(this);
- me.setup_node_click_action(this);
+
+ if (!me.all_nodes_expanded) {
+ me.setup_node_click_action(this);
+ }
+
me.setup_edit_node_action(this);
}
};
@@ -60,8 +64,9 @@ erpnext.HierarchyChart = class {
show() {
frappe.breadcrumbs.add('HR');
- let me = this;
+ this.setup_actions();
if ($(`[data-fieldname="company"]`).length) return;
+ let me = this;
let company = this.page.add_field({
fieldtype: 'Link',
@@ -79,20 +84,9 @@ erpnext.HierarchyChart = class {
// svg for connectors
me.make_svg_markers();
-
- if (me.$hierarchy)
- me.$hierarchy.remove();
-
- // setup hierarchy
- me.$hierarchy = $(
- ``);
-
- me.page.main.append(me.$hierarchy);
+ me.setup_hierarchy()
me.render_root_nodes();
+ me.all_nodes_expanded = false;
}
}
});
@@ -101,6 +95,42 @@ erpnext.HierarchyChart = class {
$(`[data-fieldname="company"]`).trigger('change');
}
+ setup_actions() {
+ let me = this;
+ this.page.add_inner_button(__('Expand All'), function() {
+ me.load_children(me.root_node, true);
+ me.all_nodes_expanded = true;
+
+ me.page.remove_inner_button(__('Expand All'));
+ me.page.add_inner_button(__('Collapse All'), function() {
+ me.setup_hierarchy();
+ me.render_root_nodes();
+ me.all_nodes_expanded = false;
+
+ me.page.remove_inner_button(__('Collapse All'));
+ me.setup_actions();
+ });
+ });
+ }
+
+ setup_hierarchy() {
+ if (this.$hierarchy)
+ this.$hierarchy.remove();
+
+ $(`#connectors`).empty();
+
+ // setup hierarchy
+ this.$hierarchy = $(
+ ``);
+
+ this.page.main.append(this.$hierarchy);
+ this.nodes = {};
+ }
+
make_svg_markers() {
$('#arrows').remove();
@@ -126,7 +156,7 @@ erpnext.HierarchyChart = class {
`);
}
- render_root_nodes() {
+ render_root_nodes(expanded_view=false) {
let me = this;
frappe.call({
@@ -156,7 +186,10 @@ erpnext.HierarchyChart = class {
expand_node = node;
});
- me.expand_node(expand_node);
+ if (!expanded_view) {
+ me.root_node = expand_node;
+ me.expand_node(expand_node);
+ }
}
});
}
@@ -196,11 +229,20 @@ erpnext.HierarchyChart = class {
$(`#${node.parent_id}`).addClass('active-path');
}
- load_children(node) {
- frappe.run_serially([
- () => this.get_child_nodes(node.id),
- (child_nodes) => this.render_child_nodes(node, child_nodes)
- ]);
+ load_children(node, deep=false) {
+ if (!deep) {
+ frappe.run_serially([
+ () => this.get_child_nodes(node.id),
+ (child_nodes) => this.render_child_nodes(node, child_nodes)
+ ]);
+ } else {
+ frappe.run_serially([
+ () => this.setup_hierarchy(),
+ () => this.render_root_nodes(true),
+ () => this.get_all_nodes(node.id, node.name),
+ (data_list) => this.render_children_of_all_nodes(data_list)
+ ]);
+ }
}
get_child_nodes(node_id) {
@@ -247,6 +289,70 @@ erpnext.HierarchyChart = class {
node.expanded = true;
}
+ get_all_nodes(node_id, node_name) {
+ return new Promise(resolve => {
+ frappe.call({
+ method: 'erpnext.utilities.hierarchy_chart.get_all_nodes',
+ args: {
+ method: this.method,
+ company: this.company,
+ parent: node_id,
+ parent_name: node_name
+ },
+ callback: (r) => {
+ resolve(r.message);
+ }
+ });
+ });
+ }
+
+ render_children_of_all_nodes(data_list) {
+ let entry = undefined;
+ let node = undefined;
+
+ while(data_list.length) {
+ // to avoid overlapping connectors
+ entry = data_list.shift();
+ node = this.nodes[entry.parent];
+ if (node) {
+ this.render_child_nodes_for_expanded_view(node, entry.data);
+ } else {
+ data_list.push(entry);
+ }
+ }
+ }
+
+ render_child_nodes_for_expanded_view(node, child_nodes) {
+ node.$children = $('')
+
+ const last_level = this.$hierarchy.find('.level:last').index();
+ const node_level = $(`#${node.id}`).parent().parent().parent().index();
+
+ if (last_level === node_level) {
+ this.$hierarchy.append(`
+
+ `);
+ node.$children.appendTo(this.$hierarchy.find('.level:last'));
+ } else {
+ node.$children.appendTo(this.$hierarchy.find('.level:eq(' + (node_level + 1) + ')'));
+ }
+
+ node.$children.hide().empty();
+
+ if (child_nodes) {
+ $.each(child_nodes, (_i, data) => {
+ this.add_node(node, data);
+ setTimeout(() => {
+ this.add_connector(node.id, data.id);
+ }, 250);
+ });
+ }
+
+ node.$children.show();
+ $(`path[data-parent="${node.id}"]`).show();
+ node.expanded = true;
+ }
+
add_node(node, data) {
return new this.Node({
id: data.id,
@@ -333,7 +439,7 @@ erpnext.HierarchyChart = class {
path.setAttribute("class", "active-connector");
path.setAttribute("marker-start", "url(#arrowstart-active)");
path.setAttribute("marker-end", "url(#arrowhead-active)");
- } else if (parent.hasClass('active-path')) {
+ } else {
path.setAttribute("class", "collapsed-connector");
path.setAttribute("marker-start", "url(#arrowstart-collapsed)");
path.setAttribute("marker-end", "url(#arrowhead-collapsed)");
diff --git a/erpnext/public/scss/hierarchy_chart.scss b/erpnext/public/scss/hierarchy_chart.scss
index dd523c3443..1c2f9421fa 100644
--- a/erpnext/public/scss/hierarchy_chart.scss
+++ b/erpnext/public/scss/hierarchy_chart.scss
@@ -194,6 +194,7 @@
.level {
margin-right: 8px;
align-items: flex-start;
+ flex-direction: column;
}
#arrows {
diff --git a/erpnext/utilities/hierarchy_chart.py b/erpnext/utilities/hierarchy_chart.py
new file mode 100644
index 0000000000..9b0279351f
--- /dev/null
+++ b/erpnext/utilities/hierarchy_chart.py
@@ -0,0 +1,29 @@
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
+# MIT License. See license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe import _
+
+@frappe.whitelist()
+def get_all_nodes(parent, parent_name, method, company):
+ '''Recursively gets all data from nodes'''
+ method = frappe.get_attr(method)
+
+ if not method in frappe.whitelisted:
+ frappe.throw(_('Not Permitted'), frappe.PermissionError)
+
+ data = method(parent, company)
+ result = [dict(parent=parent, parent_name=parent_name, data=data)]
+
+ nodes_to_expand = [{'id': d.get('id'), 'name': d.get('name')} for d in data if d.get('expandable')]
+
+ while nodes_to_expand:
+ parent = nodes_to_expand.pop(0)
+ data = method(parent.get('id'), company)
+ result.append(dict(parent=parent.get('id'), parent_name=parent.get('name'), data=data))
+ for d in data:
+ if d.get('expandable'):
+ nodes_to_expand.append({'id': d.get('id'), 'name': d.get('name')})
+
+ return result
\ No newline at end of file
From 58c31c72c37d79e8f424e371c0f868b38ed6125d Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Sun, 25 Jul 2021 20:23:20 +0530
Subject: [PATCH 314/386] feat: add html2canvas for easily exporting html to
images using canvas
---
.eslintrc | 1 +
package.json | 3 ++-
yarn.lock | 19 +++++++++++++++++++
3 files changed, 22 insertions(+), 1 deletion(-)
diff --git a/.eslintrc b/.eslintrc
index cb45ce5f69..321af084ae 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -154,6 +154,7 @@
"before": true,
"beforeEach": true,
"onScan": true,
+ "html2canvas": true,
"extend_cscript": true,
"localforage": true,
}
diff --git a/package.json b/package.json
index c9ee7a622c..5bc1e56a21 100644
--- a/package.json
+++ b/package.json
@@ -15,7 +15,8 @@
"snyk": "^1.518.0"
},
"dependencies": {
- "onscan.js": "^1.5.2"
+ "onscan.js": "^1.5.2",
+ "html2canvas": "^1.1.4"
},
"scripts": {
"snyk-protect": "snyk protect",
diff --git a/yarn.lock b/yarn.lock
index 242695c4b8..82e98215d1 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -688,6 +688,11 @@ balanced-match@^1.0.0:
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
+base64-arraybuffer@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.2.0.tgz#4b944fac0191aa5907afe2d8c999ccc57ce80f45"
+ integrity sha512-7emyCsu1/xiBXgQZrscw/8KPRT44I4Yq9Pe6EGs3aPRTsWuggML1/1DTuZUuIaJPIm1FTDUVXl4x/yW8s0kQDQ==
+
base64-js@^1.3.1:
version "1.5.1"
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
@@ -997,6 +1002,13 @@ crypto-random-string@^2.0.0:
resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5"
integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==
+css-line-break@1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/css-line-break/-/css-line-break-1.1.1.tgz#d5e9bdd297840099eb0503c7310fd34927a026ef"
+ integrity sha512-1feNVaM4Fyzdj4mKPIQNL2n70MmuYzAXZ1aytlROFX1JsOo070OsugwGjj7nl6jnDJWHDM8zRZswkmeYVWZJQA==
+ dependencies:
+ base64-arraybuffer "^0.2.0"
+
debug@^3.1.0, debug@^3.2.6:
version "3.2.6"
resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b"
@@ -1472,6 +1484,13 @@ hosted-git-info@^3.0.4, hosted-git-info@^3.0.7:
dependencies:
lru-cache "^6.0.0"
+html2canvas@^1.1.4:
+ version "1.1.4"
+ resolved "https://registry.yarnpkg.com/html2canvas/-/html2canvas-1.1.4.tgz#53ae91cd26e9e9e623c56533cccb2e3f57c8124c"
+ integrity sha512-uHgQDwrXsRmFdnlOVFvHin9R7mdjjZvoBoXxicPR+NnucngkaLa5zIDW9fzMkiip0jSffyTyWedE8iVogYOeWg==
+ dependencies:
+ css-line-break "1.1.1"
+
http-cache-semantics@^4.0.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz#49e91c5cbf36c9b94bcfcd71c23d5249ec74e390"
From 78f50a980947715d647985413b9a2811c8e6cd73 Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Sun, 25 Jul 2021 20:28:01 +0530
Subject: [PATCH 315/386] feat: Export chart option in desktop view
---
.../hierarchy_chart_desktop.js | 97 +++++++++++++------
erpnext/public/scss/hierarchy_chart.scss | 10 +-
erpnext/utilities/hierarchy_chart.py | 4 +-
3 files changed, 82 insertions(+), 29 deletions(-)
diff --git a/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js b/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
index 694c26567a..57d34d8225 100644
--- a/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
+++ b/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
@@ -1,3 +1,4 @@
+import html2canvas from 'html2canvas';
erpnext.HierarchyChart = class {
/* Options:
- doctype
@@ -11,16 +12,20 @@ erpnext.HierarchyChart = class {
this.method = method;
this.doctype = doctype;
+ this.setup_page_style();
+ this.page.main.addClass('frappe-card');
+
+ this.nodes = {};
+ this.setup_node_class();
+ }
+
+ setup_page_style() {
this.page.main.css({
'min-height': '300px',
'max-height': '600px',
'overflow': 'auto',
'position': 'relative'
});
- this.page.main.addClass('frappe-card');
-
- this.nodes = {};
- this.setup_node_class();
}
setup_node_class() {
@@ -84,7 +89,7 @@ erpnext.HierarchyChart = class {
// svg for connectors
me.make_svg_markers();
- me.setup_hierarchy()
+ me.setup_hierarchy();
me.render_root_nodes();
me.all_nodes_expanded = false;
}
@@ -97,6 +102,10 @@ erpnext.HierarchyChart = class {
setup_actions() {
let me = this;
+ this.page.add_inner_button(__('Export'), function() {
+ me.export_chart();
+ });
+
this.page.add_inner_button(__('Expand All'), function() {
me.load_children(me.root_node, true);
me.all_nodes_expanded = true;
@@ -113,6 +122,36 @@ erpnext.HierarchyChart = class {
});
}
+ export_chart() {
+ this.page.main.css({
+ 'min-height': '',
+ 'max-height': '',
+ 'overflow': 'visible',
+ 'position': 'fixed',
+ 'left': '0',
+ 'top': '0'
+ });
+
+ $('.node-card').addClass('exported');
+
+ html2canvas(document.querySelector('#hierarchy-chart-wrapper'), {
+ scrollY: -window.scrollY,
+ scrollX: 0
+ }).then(function(canvas) {
+ // Export the canvas to its data URI representation
+ let dataURL = canvas.toDataURL('image/png');
+
+ // download the image
+ let a = document.createElement('a');
+ a.href = dataURL;
+ a.download = 'hierarchy_chart';
+ a.click();
+ });
+
+ this.setup_page_style();
+ $('.node-card').removeClass('exported');
+ }
+
setup_hierarchy() {
if (this.$hierarchy)
this.$hierarchy.remove();
@@ -127,33 +166,37 @@ erpnext.HierarchyChart = class {
`);
- this.page.main.append(this.$hierarchy);
+ this.page.main
+ .find('#hierarchy-chart-wrapper')
+ .append(this.$hierarchy);
this.nodes = {};
}
make_svg_markers() {
$('#arrows').remove();
- this.page.main.prepend(`
-
-
-
-
-
-
-
-
+ this.page.main.append(`
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
- `);
+
+
+
+
+
+
+
+
+
+
+
`);
}
render_root_nodes(expanded_view=false) {
@@ -310,7 +353,7 @@ erpnext.HierarchyChart = class {
let entry = undefined;
let node = undefined;
- while(data_list.length) {
+ while (data_list.length) {
// to avoid overlapping connectors
entry = data_list.shift();
node = this.nodes[entry.parent];
@@ -323,7 +366,7 @@ erpnext.HierarchyChart = class {
}
render_child_nodes_for_expanded_view(node, child_nodes) {
- node.$children = $('')
+ node.$children = $('');
const last_level = this.$hierarchy.find('.level:last').index();
const node_level = $(`#${node.id}`).parent().parent().parent().index();
diff --git a/erpnext/public/scss/hierarchy_chart.scss b/erpnext/public/scss/hierarchy_chart.scss
index 1c2f9421fa..44288fe155 100644
--- a/erpnext/public/scss/hierarchy_chart.scss
+++ b/erpnext/public/scss/hierarchy_chart.scss
@@ -21,6 +21,10 @@
}
}
+.node-card.exported {
+ box-shadow: none
+}
+
.node-image {
width: 3.0rem;
height: 3.0rem;
@@ -178,9 +182,12 @@
}
// horizontal hierarchy tree view
+#hierarchy-chart-wrapper {
+ padding-top: 30px;
+}
+
.hierarchy {
display: flex;
- padding-top: 30px;
}
.hierarchy li {
@@ -200,6 +207,7 @@
#arrows {
position: absolute;
overflow: visible;
+ margin-top: -80px;
}
.active-connector {
diff --git a/erpnext/utilities/hierarchy_chart.py b/erpnext/utilities/hierarchy_chart.py
index 9b0279351f..22d3f28faa 100644
--- a/erpnext/utilities/hierarchy_chart.py
+++ b/erpnext/utilities/hierarchy_chart.py
@@ -3,14 +3,16 @@
from __future__ import unicode_literals
import frappe
+import os
from frappe import _
+from frappe.utils.pdf import get_pdf
@frappe.whitelist()
def get_all_nodes(parent, parent_name, method, company):
'''Recursively gets all data from nodes'''
method = frappe.get_attr(method)
- if not method in frappe.whitelisted:
+ if method not in frappe.whitelisted:
frappe.throw(_('Not Permitted'), frappe.PermissionError)
data = method(parent, company)
From 5f0edca3f37c7d8fcc5b7cfe6a116f9d9379af8b Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Sun, 25 Jul 2021 20:39:51 +0530
Subject: [PATCH 316/386] fix(style): longer titles overflowing
---
erpnext/public/scss/hierarchy_chart.scss | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/erpnext/public/scss/hierarchy_chart.scss b/erpnext/public/scss/hierarchy_chart.scss
index 44288fe155..7f1077dbbd 100644
--- a/erpnext/public/scss/hierarchy_chart.scss
+++ b/erpnext/public/scss/hierarchy_chart.scss
@@ -40,6 +40,10 @@
line-height: 1.35;
}
+.node-info {
+ width: 12.7rem;
+}
+
.node-connections {
font-size: 0.75rem;
line-height: 1.35;
From c1bb4eec9cf2e66f99f6ec6aa0e8f8b3b63f2a66 Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Sun, 25 Jul 2021 21:34:51 +0530
Subject: [PATCH 317/386] fix: remove unnecessary imports
---
erpnext/utilities/hierarchy_chart.py | 2 --
1 file changed, 2 deletions(-)
diff --git a/erpnext/utilities/hierarchy_chart.py b/erpnext/utilities/hierarchy_chart.py
index 22d3f28faa..fb58a5d586 100644
--- a/erpnext/utilities/hierarchy_chart.py
+++ b/erpnext/utilities/hierarchy_chart.py
@@ -3,9 +3,7 @@
from __future__ import unicode_literals
import frappe
-import os
from frappe import _
-from frappe.utils.pdf import get_pdf
@frappe.whitelist()
def get_all_nodes(parent, parent_name, method, company):
From f9afade7dc152b3419607f9fcd186af73417cf56 Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Sun, 25 Jul 2021 23:11:18 +0530
Subject: [PATCH 318/386] fix: test
---
erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js b/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
index 57d34d8225..89fb8d5792 100644
--- a/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
+++ b/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
@@ -173,7 +173,7 @@ erpnext.HierarchyChart = class {
}
make_svg_markers() {
- $('#arrows').remove();
+ $('#hierarchy-chart-wrapper').remove();
this.page.main.append(`
From 4ee6e32d74da3c7277a16a5dc48d3af2728e5ecf Mon Sep 17 00:00:00 2001
From: Noah Jacob
Date: Tue, 10 Aug 2021 13:14:11 +0530
Subject: [PATCH 319/386] test(fix): fixed test case
---
.../doctype/coupon_code/test_coupon_code.py | 19 ++++++++++---------
1 file changed, 10 insertions(+), 9 deletions(-)
diff --git a/erpnext/accounts/doctype/coupon_code/test_coupon_code.py b/erpnext/accounts/doctype/coupon_code/test_coupon_code.py
index 622bd33e20..5af12cde06 100644
--- a/erpnext/accounts/doctype/coupon_code/test_coupon_code.py
+++ b/erpnext/accounts/doctype/coupon_code/test_coupon_code.py
@@ -57,7 +57,7 @@ def test_create_test_data():
})
item_price.insert()
# create test item pricing rule
- if not frappe.db.exists("Pricing Rule","_Test Pricing Rule for _Test Item"):
+ if not frappe.db.exists("Pricing Rule", {"title": "_Test Pricing Rule for _Test Item"}):
item_pricing_rule = frappe.get_doc({
"doctype": "Pricing Rule",
"title": "_Test Pricing Rule for _Test Item",
@@ -86,14 +86,15 @@ def test_create_test_data():
sales_partner.insert()
# create test item coupon code
if not frappe.db.exists("Coupon Code", "SAVE30"):
+ pricing_rule = frappe.db.get_value("Pricing Rule", {"title": "_Test Pricing Rule for _Test Item"}, ['name'])
coupon_code = frappe.get_doc({
- "doctype": "Coupon Code",
- "coupon_name":"SAVE30",
- "coupon_code":"SAVE30",
- "pricing_rule": "_Test Pricing Rule for _Test Item",
- "valid_from": "2014-01-01",
- "maximum_use":1,
- "used":0
+ "doctype": "Coupon Code",
+ "coupon_name":"SAVE30",
+ "coupon_code":"SAVE30",
+ "pricing_rule": pricing_rule,
+ "valid_from": "2014-01-01",
+ "maximum_use":1,
+ "used":0
})
coupon_code.insert()
@@ -102,7 +103,7 @@ class TestCouponCode(unittest.TestCase):
test_create_test_data()
def tearDown(self):
- frappe.set_user("Administrator")
+ frappe.set_user("Administrator")
def test_sales_order_with_coupon_code(self):
frappe.db.set_value("Coupon Code", "SAVE30", "used", 0)
From 49b7c7575e9bc604fb9132929a63fb9b4bb1e484 Mon Sep 17 00:00:00 2001
From: Noah Jacob
Date: Tue, 10 Aug 2021 18:35:46 +0530
Subject: [PATCH 320/386] refactor: code cleanup
---
.../promotional_scheme/promotional_scheme.py | 27 +++++++++++--------
1 file changed, 16 insertions(+), 11 deletions(-)
diff --git a/erpnext/accounts/doctype/promotional_scheme/promotional_scheme.py b/erpnext/accounts/doctype/promotional_scheme/promotional_scheme.py
index f4ee1887c4..0fade84cfd 100644
--- a/erpnext/accounts/doctype/promotional_scheme/promotional_scheme.py
+++ b/erpnext/accounts/doctype/promotional_scheme/promotional_scheme.py
@@ -25,12 +25,14 @@ product_discount_fields = ['free_item', 'free_qty', 'free_item_uom',
class PromotionalScheme(Document):
def validate(self):
+ if not self.selling and not self.buying:
+ frappe.throw(_("Atleast one of the Selling or Buying must be selected"))
if not (self.price_discount_slabs
or self.product_discount_slabs):
frappe.throw(_("Price or product discount slabs are required"))
def on_update(self):
- data = frappe.get_all(
+ pricing_rules = frappe.get_all(
'Pricing Rule',
fields = ["promotional_scheme_id", "name", "creation"],
filters = {
@@ -39,15 +41,15 @@ class PromotionalScheme(Document):
},
order_by = 'creation asc',
) or {}
- self.update_pricing_rules(data)
+ self.update_pricing_rules(pricing_rules)
- def update_pricing_rules(self, data):
+ def update_pricing_rules(self, pricing_rules):
rules = {}
count = 0
names = []
- for d in data:
- names.append(d.name)
- rules[d.get('promotional_scheme_id')] = names
+ for rule in pricing_rules:
+ names.append(rule.name)
+ rules[rule.get('promotional_scheme_id')] = names
docs = get_pricing_rules(self, rules)
@@ -64,9 +66,9 @@ class PromotionalScheme(Document):
frappe.msgprint(_("New {0} pricing rules are created").format(count))
def on_trash(self):
- for d in frappe.get_all('Pricing Rule',
+ for rule in frappe.get_all('Pricing Rule',
{'promotional_scheme': self.name}):
- frappe.delete_doc('Pricing Rule', d.name)
+ frappe.delete_doc('Pricing Rule', rule.name)
def get_pricing_rules(doc, rules = {}):
new_doc = []
@@ -107,17 +109,20 @@ def _get_pricing_rules(doc, child_doc, discount_fields, rules = {}):
new_doc.append(pr)
else:
- for i in range(len(args.get(applicable_for))) :
-
+ applicable_for_values = args.get(applicable_for) or []
+ for applicable_for_value in applicable_for_values:
pr = frappe.new_doc("Pricing Rule")
pr.title = doc.name
temp_args = args.copy()
- temp_args[applicable_for] = args[applicable_for][i]
+ temp_args[applicable_for] = applicable_for_value
pr = set_args(temp_args, pr, doc, child_doc, discount_fields, d)
new_doc.append(pr)
return new_doc
+
+
+
def set_args(args, pr, doc, child_doc, discount_fields, child_doc_fields):
pr.update(args)
for field in (other_fields + discount_fields):
From af9863146dea5c41b4eee4a0024d6cac1cacc2b6 Mon Sep 17 00:00:00 2001
From: Marica
Date: Tue, 10 Aug 2021 18:49:07 +0530
Subject: [PATCH 321/386] fix: Grammar in Error message
---
.../accounts/doctype/promotional_scheme/promotional_scheme.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/accounts/doctype/promotional_scheme/promotional_scheme.py b/erpnext/accounts/doctype/promotional_scheme/promotional_scheme.py
index 0fade84cfd..3d7a891f33 100644
--- a/erpnext/accounts/doctype/promotional_scheme/promotional_scheme.py
+++ b/erpnext/accounts/doctype/promotional_scheme/promotional_scheme.py
@@ -26,7 +26,7 @@ product_discount_fields = ['free_item', 'free_qty', 'free_item_uom',
class PromotionalScheme(Document):
def validate(self):
if not self.selling and not self.buying:
- frappe.throw(_("Atleast one of the Selling or Buying must be selected"))
+ frappe.throw(_("Either 'Selling' or 'Buying' must be selected"), title=_("Mandatory"))
if not (self.price_discount_slabs
or self.product_discount_slabs):
frappe.throw(_("Price or product discount slabs are required"))
From 66784a16cb20088c870261cf2871d0c59f11f862 Mon Sep 17 00:00:00 2001
From: Anuja Pawar <60467153+Anuja-pawar@users.noreply.github.com>
Date: Tue, 10 Aug 2021 19:38:16 +0530
Subject: [PATCH 322/386] fix: Sales Return cancellation if linked with Payment
Entry (#26883)
---
.../purchase_invoice/purchase_invoice.py | 4 +-
.../doctype/sales_invoice/sales_invoice.py | 42 ++++++++++++++++++-
2 files changed, 44 insertions(+), 2 deletions(-)
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
index d7d9a3886a..85df225868 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
@@ -22,7 +22,7 @@ from erpnext.assets.doctype.asset.asset import get_asset_account, is_cwip_accoun
from frappe.model.mapper import get_mapped_doc
from six import iteritems
from erpnext.accounts.doctype.sales_invoice.sales_invoice import validate_inter_company_party, update_linked_doc,\
- unlink_inter_company_doc
+ unlink_inter_company_doc, check_if_return_invoice_linked_with_payment_entry
from erpnext.accounts.doctype.tax_withholding_category.tax_withholding_category import get_party_tax_withholding_details
from erpnext.accounts.deferred_revenue import validate_service_stop_date
from erpnext.stock.doctype.purchase_receipt.purchase_receipt import get_item_account_wise_additional_cost
@@ -988,6 +988,8 @@ class PurchaseInvoice(BuyingController):
}, item=self))
def on_cancel(self):
+ check_if_return_invoice_linked_with_payment_entry(self)
+
super(PurchaseInvoice, self).on_cancel()
self.check_on_hold_or_closed_status()
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index eba8ba830f..ba1e729a46 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -290,6 +290,8 @@ class SalesInvoice(SellingController):
self.update_time_sheet(None)
def on_cancel(self):
+ check_if_return_invoice_linked_with_payment_entry(self)
+
super(SalesInvoice, self).on_cancel()
self.check_sales_order_on_hold_or_close("sales_order")
@@ -971,7 +973,7 @@ class SalesInvoice(SellingController):
def set_asset_status(self, asset):
if self.is_return:
asset.set_status()
- else:
+ else:
asset.set_status("Sold" if self.docstatus==1 else None)
def make_loyalty_point_redemption_gle(self, gl_entries):
@@ -1939,3 +1941,41 @@ def create_dunning(source_name, target_doc=None):
}
}, target_doc, set_missing_values)
return doclist
+
+def check_if_return_invoice_linked_with_payment_entry(self):
+ # If a Return invoice is linked with payment entry along with other invoices,
+ # the cancellation of the Return causes allocated amount to be greater than paid
+
+ if not frappe.db.get_single_value('Accounts Settings', 'unlink_payment_on_cancellation_of_invoice'):
+ return
+
+ payment_entries = []
+ if self.is_return and self.return_against:
+ invoice = self.return_against
+ else:
+ invoice = self.name
+
+ payment_entries = frappe.db.sql_list("""
+ SELECT
+ t1.name
+ FROM
+ `tabPayment Entry` t1, `tabPayment Entry Reference` t2
+ WHERE
+ t1.name = t2.parent
+ and t1.docstatus = 1
+ and t2.reference_name = %s
+ and t2.allocated_amount < 0
+ """, invoice)
+
+ links_to_pe = []
+ if payment_entries:
+ for payment in payment_entries:
+ payment_entry = frappe.get_doc("Payment Entry", payment)
+ if len(payment_entry.references) > 1:
+ links_to_pe.append(payment_entry.name)
+ if links_to_pe:
+ payment_entries_link = [get_link_to_form('Payment Entry', name, label=name) for name in links_to_pe]
+ message = _("Please cancel and amend the Payment Entry")
+ message += " " + ", ".join(payment_entries_link) + " "
+ message += _("to unallocate the amount of this Return Invoice before cancelling it.")
+ frappe.throw(message)
From 1a39d1a3115605d7ccaf6285e7664197f1ff01a8 Mon Sep 17 00:00:00 2001
From: Frappe PR Bot
Date: Tue, 10 Aug 2021 19:38:39 +0530
Subject: [PATCH 323/386] fix: cost center & account validation in
Sales/Purchase Taxes and Charges (#26881)
---
.../sales_taxes_and_charges_template.py | 4 +++-
.../test_records.json | 8 +++++++
erpnext/controllers/accounts_controller.py | 21 +++++++++++++++++++
erpnext/public/js/controllers/accounts.js | 8 +++++++
erpnext/setup/doctype/company/company.py | 6 +++---
.../setup_wizard/operations/taxes_setup.py | 3 ++-
6 files changed, 45 insertions(+), 5 deletions(-)
diff --git a/erpnext/accounts/doctype/sales_taxes_and_charges_template/sales_taxes_and_charges_template.py b/erpnext/accounts/doctype/sales_taxes_and_charges_template/sales_taxes_and_charges_template.py
index 52d19d54a8..8f9eb6577b 100644
--- a/erpnext/accounts/doctype/sales_taxes_and_charges_template/sales_taxes_and_charges_template.py
+++ b/erpnext/accounts/doctype/sales_taxes_and_charges_template/sales_taxes_and_charges_template.py
@@ -6,7 +6,7 @@ import frappe
from frappe import _
from frappe.utils import flt
from frappe.model.document import Document
-from erpnext.controllers.accounts_controller import validate_taxes_and_charges, validate_inclusive_tax
+from erpnext.controllers.accounts_controller import validate_taxes_and_charges, validate_inclusive_tax, validate_cost_center, validate_account_head
class SalesTaxesandChargesTemplate(Document):
def validate(self):
@@ -39,6 +39,8 @@ def valdiate_taxes_and_charges_template(doc):
for tax in doc.get("taxes"):
validate_taxes_and_charges(tax)
+ validate_account_head(tax, doc)
+ validate_cost_center(tax, doc)
validate_inclusive_tax(tax, doc)
def validate_disabled(doc):
diff --git a/erpnext/accounts/doctype/sales_taxes_and_charges_template/test_records.json b/erpnext/accounts/doctype/sales_taxes_and_charges_template/test_records.json
index 2b737b9804..74db08d5b8 100644
--- a/erpnext/accounts/doctype/sales_taxes_and_charges_template/test_records.json
+++ b/erpnext/accounts/doctype/sales_taxes_and_charges_template/test_records.json
@@ -8,6 +8,7 @@
"charge_type": "On Net Total",
"description": "VAT",
"doctype": "Sales Taxes and Charges",
+ "cost_center": "Main - _TC",
"parentfield": "taxes",
"rate": 6
},
@@ -16,6 +17,7 @@
"charge_type": "On Net Total",
"description": "Service Tax",
"doctype": "Sales Taxes and Charges",
+ "cost_center": "Main - _TC",
"parentfield": "taxes",
"rate": 6.36
}
@@ -114,6 +116,7 @@
"charge_type": "On Net Total",
"description": "VAT",
"doctype": "Sales Taxes and Charges",
+ "cost_center": "Main - _TC",
"parentfield": "taxes",
"rate": 12
},
@@ -122,6 +125,7 @@
"charge_type": "On Net Total",
"description": "Service Tax",
"doctype": "Sales Taxes and Charges",
+ "cost_center": "Main - _TC",
"parentfield": "taxes",
"rate": 4
}
@@ -137,6 +141,7 @@
"charge_type": "On Net Total",
"description": "VAT",
"doctype": "Sales Taxes and Charges",
+ "cost_center": "Main - _TC",
"parentfield": "taxes",
"rate": 12
},
@@ -145,6 +150,7 @@
"charge_type": "On Net Total",
"description": "Service Tax",
"doctype": "Sales Taxes and Charges",
+ "cost_center": "Main - _TC",
"parentfield": "taxes",
"rate": 4
}
@@ -160,6 +166,7 @@
"charge_type": "On Net Total",
"description": "VAT",
"doctype": "Sales Taxes and Charges",
+ "cost_center": "Main - _TC",
"parentfield": "taxes",
"rate": 12
},
@@ -168,6 +175,7 @@
"charge_type": "On Net Total",
"description": "Service Tax",
"doctype": "Sales Taxes and Charges",
+ "cost_center": "Main - _TC",
"parentfield": "taxes",
"rate": 4
}
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index d65efa24b4..73d2411ede 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -1437,6 +1437,27 @@ def validate_taxes_and_charges(tax):
tax.rate = None
+def validate_account_head(tax, doc):
+ company = frappe.get_cached_value('Account',
+ tax.account_head, 'company')
+
+ if company != doc.company:
+ frappe.throw(_('Row {0}: Account {1} does not belong to Company {2}')
+ .format(tax.idx, frappe.bold(tax.account_head), frappe.bold(doc.company)), title=_('Invalid Account'))
+
+
+def validate_cost_center(tax, doc):
+ if not tax.cost_center:
+ return
+
+ company = frappe.get_cached_value('Cost Center',
+ tax.cost_center, 'company')
+
+ if company != doc.company:
+ frappe.throw(_('Row {0}: Cost Center {1} does not belong to Company {2}')
+ .format(tax.idx, frappe.bold(tax.cost_center), frappe.bold(doc.company)), title=_('Invalid Cost Center'))
+
+
def validate_inclusive_tax(tax, doc):
def _on_previous_row_error(row_range):
throw(_("To include tax in row {0} in Item rate, taxes in rows {1} must also be included").format(tax.idx, row_range))
diff --git a/erpnext/public/js/controllers/accounts.js b/erpnext/public/js/controllers/accounts.js
index 7b997a1153..84c717676c 100644
--- a/erpnext/public/js/controllers/accounts.js
+++ b/erpnext/public/js/controllers/accounts.js
@@ -31,6 +31,14 @@ frappe.ui.form.on(cur_frm.doctype, {
}
}
});
+ frm.set_query("cost_center", "taxes", function(doc) {
+ return {
+ filters: {
+ "company": doc.company,
+ "is_group": 0
+ }
+ };
+ });
}
},
validate: function(frm) {
diff --git a/erpnext/setup/doctype/company/company.py b/erpnext/setup/doctype/company/company.py
index 8755125c81..95cbf5150c 100644
--- a/erpnext/setup/doctype/company/company.py
+++ b/erpnext/setup/doctype/company/company.py
@@ -108,6 +108,9 @@ class Company(NestedSet):
frappe.flags.country_change = True
self.create_default_accounts()
self.create_default_warehouses()
+
+ if not frappe.db.get_value("Cost Center", {"is_group": 0, "company": self.name}):
+ self.create_default_cost_center()
if frappe.flags.country_change:
install_country_fixtures(self.name, self.country)
@@ -117,9 +120,6 @@ class Company(NestedSet):
from erpnext.setup.setup_wizard.operations.install_fixtures import install_post_company_fixtures
install_post_company_fixtures(frappe._dict({'company_name': self.name}))
- if not frappe.db.get_value("Cost Center", {"is_group": 0, "company": self.name}):
- self.create_default_cost_center()
-
if not frappe.local.flags.ignore_chart_of_accounts:
self.set_default_accounts()
if self.default_cash_account:
diff --git a/erpnext/setup/setup_wizard/operations/taxes_setup.py b/erpnext/setup/setup_wizard/operations/taxes_setup.py
index c7cc000518..c69f3d0b3f 100644
--- a/erpnext/setup/setup_wizard/operations/taxes_setup.py
+++ b/erpnext/setup/setup_wizard/operations/taxes_setup.py
@@ -124,7 +124,8 @@ def make_taxes_and_charges_template(company_name, doctype, template):
account_data = tax_row.get('account_head')
tax_row_defaults = {
'category': 'Total',
- 'charge_type': 'On Net Total'
+ 'charge_type': 'On Net Total',
+ 'cost_center': frappe.db.get_value('Company', company_name, 'cost_center')
}
if doctype == 'Purchase Taxes and Charges Template':
From 52cd0072928f75dea68399c16b477cf2ad1d21eb Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Tue, 10 Aug 2021 20:13:28 +0530
Subject: [PATCH 324/386] fix: make bundled assets for hierarchy chart
---
erpnext/hr/page/organizational_chart/organizational_chart.js | 2 +-
erpnext/public/js/hierarchy-chart.bundle.js | 3 +++
erpnext/public/scss/erpnext.bundle.scss | 1 +
3 files changed, 5 insertions(+), 1 deletion(-)
create mode 100644 erpnext/public/js/hierarchy-chart.bundle.js
diff --git a/erpnext/hr/page/organizational_chart/organizational_chart.js b/erpnext/hr/page/organizational_chart/organizational_chart.js
index a138886768..08f2c94ad4 100644
--- a/erpnext/hr/page/organizational_chart/organizational_chart.js
+++ b/erpnext/hr/page/organizational_chart/organizational_chart.js
@@ -6,7 +6,7 @@ frappe.pages['organizational-chart'].on_page_load = function(wrapper) {
});
$(wrapper).bind('show', () => {
- frappe.require('/assets/js/hierarchy-chart.min.js', () => {
+ frappe.require('hierarchy-chart.bundle.js', () => {
let organizational_chart = undefined;
let method = 'erpnext.hr.page.organizational_chart.organizational_chart.get_children';
diff --git a/erpnext/public/js/hierarchy-chart.bundle.js b/erpnext/public/js/hierarchy-chart.bundle.js
new file mode 100644
index 0000000000..26ab6d92b9
--- /dev/null
+++ b/erpnext/public/js/hierarchy-chart.bundle.js
@@ -0,0 +1,3 @@
+import "./hierarchy_chart/hierarchy_chart_desktop.js";
+import "./hierarchy_chart/hierarchy_chart_mobile.js";
+import "./templates/node_card.html";
\ No newline at end of file
diff --git a/erpnext/public/scss/erpnext.bundle.scss b/erpnext/public/scss/erpnext.bundle.scss
index d3313c7cee..b68ddf52b2 100644
--- a/erpnext/public/scss/erpnext.bundle.scss
+++ b/erpnext/public/scss/erpnext.bundle.scss
@@ -1,3 +1,4 @@
@import "./erpnext";
@import "./call_popup";
@import "./point-of-sale";
+@import "./hierarchy_chart";
From a6aa6cd7d63eb426b986d995985985c2aae4f553 Mon Sep 17 00:00:00 2001
From: Anupam Kumar
Date: Tue, 10 Aug 2021 20:32:15 +0530
Subject: [PATCH 325/386] fix: timesheet amount issue (#25993)
* fix: timesheet amount issue
* fix: timesheet detail rate conversion
* fix: condition to check timesheet currency
* fix: removing console statement
---
.../doctype/sales_invoice/sales_invoice.js | 55 ++++++++++---------
.../sales_invoice_timesheet.json | 14 ++++-
.../projects/doctype/timesheet/timesheet.json | 3 +-
.../projects/doctype/timesheet/timesheet.py | 16 +++++-
4 files changed, 58 insertions(+), 30 deletions(-)
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
index 56f11650ff..568e7721a3 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
@@ -447,6 +447,15 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
this.frm.refresh_field("outstanding_amount");
this.frm.refresh_field("paid_amount");
this.frm.refresh_field("base_paid_amount");
+ },
+
+ currency() {
+ this._super();
+ $.each(cur_frm.doc.timesheets, function(i, d) {
+ let row = frappe.get_doc(d.doctype, d.name)
+ set_timesheet_detail_rate(row.doctype, row.name, cur_frm.doc.currency, row.timesheet_detail)
+ });
+ calculate_total_billing_amount(cur_frm)
}
});
@@ -846,7 +855,8 @@ frappe.ui.form.on('Sales Invoice', {
'time_sheet': row.parent,
'billing_hours': row.billing_hours,
'billing_amount': flt(row.billing_amount) * flt(exchange_rate),
- 'timesheet_detail': row.name
+ 'timesheet_detail': row.name,
+ 'project_name': row.project_name
});
frm.refresh_field('timesheets');
calculate_total_billing_amount(frm);
@@ -965,43 +975,34 @@ frappe.ui.form.on('Sales Invoice', {
}
})
-frappe.ui.form.on('Sales Invoice Timesheet', {
- time_sheet: function(frm, cdt, cdn){
- var d = locals[cdt][cdn];
- if(d.time_sheet) {
- frappe.call({
- method: "erpnext.projects.doctype.timesheet.timesheet.get_timesheet_data",
- args: {
- 'name': d.time_sheet,
- 'project': frm.doc.project || null
- },
- callback: function(r, rt) {
- if(r.message){
- let data = r.message;
- frappe.model.set_value(cdt, cdn, "billing_hours", data.billing_hours);
- frappe.model.set_value(cdt, cdn, "billing_amount", data.billing_amount);
- frappe.model.set_value(cdt, cdn, "timesheet_detail", data.timesheet_detail);
- calculate_total_billing_amount(frm)
- }
- }
- })
- }
- }
-})
-
var calculate_total_billing_amount = function(frm) {
var doc = frm.doc;
doc.total_billing_amount = 0.0
- if(doc.timesheets) {
+ if (doc.timesheets) {
$.each(doc.timesheets, function(index, data){
- doc.total_billing_amount += data.billing_amount
+ doc.total_billing_amount += flt(data.billing_amount)
})
}
refresh_field('total_billing_amount')
}
+var set_timesheet_detail_rate = function(cdt, cdn, currency, timelog) {
+ frappe.call({
+ method: "erpnext.projects.doctype.timesheet.timesheet.get_timesheet_detail_rate",
+ args: {
+ timelog: timelog,
+ currency: currency
+ },
+ callback: function(r) {
+ if (!r.exc && r.message) {
+ frappe.model.set_value(cdt, cdn, 'billing_amount', r.message);
+ }
+ }
+ });
+}
+
var select_loyalty_program = function(frm, loyalty_programs) {
var dialog = new frappe.ui.Dialog({
title: __("Select Loyalty Program"),
diff --git a/erpnext/accounts/doctype/sales_invoice_timesheet/sales_invoice_timesheet.json b/erpnext/accounts/doctype/sales_invoice_timesheet/sales_invoice_timesheet.json
index f069e8dd0b..c90297328e 100644
--- a/erpnext/accounts/doctype/sales_invoice_timesheet/sales_invoice_timesheet.json
+++ b/erpnext/accounts/doctype/sales_invoice_timesheet/sales_invoice_timesheet.json
@@ -9,7 +9,9 @@
"description",
"billing_hours",
"billing_amount",
+ "column_break_5",
"time_sheet",
+ "project_name",
"timesheet_detail"
],
"fields": [
@@ -61,11 +63,21 @@
"in_list_view": 1,
"label": "Description",
"read_only": 1
+ },
+ {
+ "fieldname": "column_break_5",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "project_name",
+ "fieldtype": "Data",
+ "label": "Project Name",
+ "read_only": 1
}
],
"istable": 1,
"links": [],
- "modified": "2021-05-20 22:33:57.234846",
+ "modified": "2021-06-08 14:43:02.748981",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice Timesheet",
diff --git a/erpnext/projects/doctype/timesheet/timesheet.json b/erpnext/projects/doctype/timesheet/timesheet.json
index 75f7478ed1..be6771e56f 100644
--- a/erpnext/projects/doctype/timesheet/timesheet.json
+++ b/erpnext/projects/doctype/timesheet/timesheet.json
@@ -310,6 +310,7 @@
"read_only": 1
},
{
+ "default": "1",
"fieldname": "exchange_rate",
"fieldtype": "Float",
"label": "Exchange Rate"
@@ -319,7 +320,7 @@
"idx": 1,
"is_submittable": 1,
"links": [],
- "modified": "2021-05-18 16:10:08.249619",
+ "modified": "2021-06-09 12:08:53.930200",
"modified_by": "Administrator",
"module": "Projects",
"name": "Timesheet",
diff --git a/erpnext/projects/doctype/timesheet/timesheet.py b/erpnext/projects/doctype/timesheet/timesheet.py
index ae38d4ca19..a0042eb7d1 100644
--- a/erpnext/projects/doctype/timesheet/timesheet.py
+++ b/erpnext/projects/doctype/timesheet/timesheet.py
@@ -227,7 +227,8 @@ def get_projectwise_timesheet_data(project=None, parent=None, from_time=None, to
return frappe.db.sql("""SELECT tsd.name as name,
tsd.parent as parent, tsd.billing_hours as billing_hours,
tsd.billing_amount as billing_amount, tsd.activity_type as activity_type,
- tsd.description as description, ts.currency as currency
+ tsd.description as description, ts.currency as currency,
+ tsd.project_name as project_name
FROM `tabTimesheet Detail` tsd
INNER JOIN `tabTimesheet` ts ON ts.name = tsd.parent
WHERE tsd.parenttype = 'Timesheet'
@@ -235,6 +236,19 @@ def get_projectwise_timesheet_data(project=None, parent=None, from_time=None, to
and tsd.is_billable = 1
and tsd.sales_invoice is null""".format(condition), {'project': project, 'parent': parent, 'from_time': from_time, 'to_time': to_time}, as_dict=1)
+@frappe.whitelist()
+def get_timesheet_detail_rate(timelog, currency):
+ timelog_detail = frappe.db.sql("""SELECT tsd.billing_amount as billing_amount,
+ ts.currency as currency FROM `tabTimesheet Detail` tsd
+ INNER JOIN `tabTimesheet` ts ON ts.name=tsd.parent
+ WHERE tsd.name = '{0}'""".format(timelog), as_dict = 1)[0]
+
+ if timelog_detail.currency:
+ exchange_rate = get_exchange_rate(timelog_detail.currency, currency)
+
+ return timelog_detail.billing_amount * exchange_rate
+ return timelog_detail.billing_amount
+
@frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
def get_timesheet(doctype, txt, searchfield, start, page_len, filters):
From b7b111c3edd3dd42470b61061e866dfa1850d46c Mon Sep 17 00:00:00 2001
From: Frappe PR Bot
Date: Tue, 10 Aug 2021 22:52:37 +0530
Subject: [PATCH 326/386] fix: unseting of payment if no pos profile found
(#26884) (#26890)
(cherry picked from commit b614834efedbef572e0567828f0d9d82e81331ee)
Co-authored-by: Afshan <33727827+AfshanKhan@users.noreply.github.com>
---
erpnext/controllers/taxes_and_totals.py | 6 +-----
erpnext/public/js/controllers/taxes_and_totals.js | 2 --
2 files changed, 1 insertion(+), 7 deletions(-)
diff --git a/erpnext/controllers/taxes_and_totals.py b/erpnext/controllers/taxes_and_totals.py
index 099c7d4346..05edb2530c 100644
--- a/erpnext/controllers/taxes_and_totals.py
+++ b/erpnext/controllers/taxes_and_totals.py
@@ -679,17 +679,13 @@ class calculate_taxes_and_totals(object):
default_mode_of_payment = frappe.db.get_value('POS Payment Method',
{'parent': self.doc.pos_profile, 'default': 1}, ['mode_of_payment'], as_dict=1)
- self.doc.payments = []
-
if default_mode_of_payment:
+ self.doc.payments = []
self.doc.append('payments', {
'mode_of_payment': default_mode_of_payment.mode_of_payment,
'amount': total_amount_to_pay,
'default': 1
})
- else:
- self.doc.is_pos = 0
- self.doc.pos_profile = ''
self.calculate_paid_amount()
diff --git a/erpnext/public/js/controllers/taxes_and_totals.js b/erpnext/public/js/controllers/taxes_and_totals.js
index 53d5278bbf..891ec6edc1 100644
--- a/erpnext/public/js/controllers/taxes_and_totals.js
+++ b/erpnext/public/js/controllers/taxes_and_totals.js
@@ -747,8 +747,6 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
this.frm.doc.payments.find(pay => {
if (pay.default) {
pay.amount = total_amount_to_pay;
- } else {
- pay.amount = 0.0
}
});
this.frm.refresh_fields();
From 1167a9bf9481ddc806343c7a7b7c9d4ef93b1a7d Mon Sep 17 00:00:00 2001
From: Frappe PR Bot
Date: Tue, 10 Aug 2021 23:18:23 +0530
Subject: [PATCH 327/386] fix: unsetting of payment if no pos profile found
(#26891)
* fix: unseting of payment if no pos profile found (#26884)
(cherry picked from commit b614834efedbef572e0567828f0d9d82e81331ee)
# Conflicts:
# erpnext/public/js/controllers/taxes_and_totals.js
* fix: conflicts
* fix: conflicts
* fix: conflicts
* fix: conflicts
Co-authored-by: Afshan <33727827+AfshanKhan@users.noreply.github.com>
Co-authored-by: Afshan
---
erpnext/controllers/taxes_and_totals.py | 6 +-----
erpnext/public/js/controllers/taxes_and_totals.js | 2 --
2 files changed, 1 insertion(+), 7 deletions(-)
diff --git a/erpnext/controllers/taxes_and_totals.py b/erpnext/controllers/taxes_and_totals.py
index 099c7d4346..05edb2530c 100644
--- a/erpnext/controllers/taxes_and_totals.py
+++ b/erpnext/controllers/taxes_and_totals.py
@@ -679,17 +679,13 @@ class calculate_taxes_and_totals(object):
default_mode_of_payment = frappe.db.get_value('POS Payment Method',
{'parent': self.doc.pos_profile, 'default': 1}, ['mode_of_payment'], as_dict=1)
- self.doc.payments = []
-
if default_mode_of_payment:
+ self.doc.payments = []
self.doc.append('payments', {
'mode_of_payment': default_mode_of_payment.mode_of_payment,
'amount': total_amount_to_pay,
'default': 1
})
- else:
- self.doc.is_pos = 0
- self.doc.pos_profile = ''
self.calculate_paid_amount()
diff --git a/erpnext/public/js/controllers/taxes_and_totals.js b/erpnext/public/js/controllers/taxes_and_totals.js
index 9d8fcb64f7..90cb555939 100644
--- a/erpnext/public/js/controllers/taxes_and_totals.js
+++ b/erpnext/public/js/controllers/taxes_and_totals.js
@@ -749,8 +749,6 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
this.frm.doc.payments.find(pay => {
if (pay.default) {
pay.amount = total_amount_to_pay;
- } else {
- pay.amount = 0.0;
}
});
this.frm.refresh_fields();
From 15cb248d9e43ed4fd71157b8d6e3f6a2ee182311 Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Tue, 10 Aug 2021 23:44:08 +0530
Subject: [PATCH 328/386] fix(style): apply svg container margin only in
desktop view
---
erpnext/public/scss/hierarchy_chart.scss | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/erpnext/public/scss/hierarchy_chart.scss b/erpnext/public/scss/hierarchy_chart.scss
index 7f1077dbbd..8a1ec4992b 100644
--- a/erpnext/public/scss/hierarchy_chart.scss
+++ b/erpnext/public/scss/hierarchy_chart.scss
@@ -188,6 +188,10 @@
// horizontal hierarchy tree view
#hierarchy-chart-wrapper {
padding-top: 30px;
+
+ #arrows {
+ margin-top: -80px;
+ }
}
.hierarchy {
@@ -211,7 +215,6 @@
#arrows {
position: absolute;
overflow: visible;
- margin-top: -80px;
}
.active-connector {
From 9855bbb95e2dbcc4140753309abbee283db91a3b Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Tue, 10 Aug 2021 23:49:56 +0530
Subject: [PATCH 329/386] fix(style): apply svg container margin only in
desktop view (#26894)
---
erpnext/public/scss/hierarchy_chart.scss | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/erpnext/public/scss/hierarchy_chart.scss b/erpnext/public/scss/hierarchy_chart.scss
index 7f1077dbbd..8a1ec4992b 100644
--- a/erpnext/public/scss/hierarchy_chart.scss
+++ b/erpnext/public/scss/hierarchy_chart.scss
@@ -188,6 +188,10 @@
// horizontal hierarchy tree view
#hierarchy-chart-wrapper {
padding-top: 30px;
+
+ #arrows {
+ margin-top: -80px;
+ }
}
.hierarchy {
@@ -211,7 +215,6 @@
#arrows {
position: absolute;
overflow: visible;
- margin-top: -80px;
}
.active-connector {
From 99658ceb4e743c4758a306f70f5497a8818738e0 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Wed, 11 Aug 2021 14:19:07 +0530
Subject: [PATCH 330/386] fix: Nest .level class style under .hierarchy class
- To avoid style overrides in list view
---
erpnext/public/scss/hierarchy_chart.scss | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/erpnext/public/scss/hierarchy_chart.scss b/erpnext/public/scss/hierarchy_chart.scss
index 8a1ec4992b..a66d6474e0 100644
--- a/erpnext/public/scss/hierarchy_chart.scss
+++ b/erpnext/public/scss/hierarchy_chart.scss
@@ -206,10 +206,12 @@
margin: 0px 0px 16px 0px;
}
-.level {
- margin-right: 8px;
- align-items: flex-start;
- flex-direction: column;
+.hierarchy, .hierarchy-mobile {
+ .level {
+ margin-right: 8px;
+ align-items: flex-start;
+ flex-direction: column;
+ }
}
#arrows {
From 08e4026456a698e4a41e1919795a03366e0ae2cb Mon Sep 17 00:00:00 2001
From: Marica
Date: Thu, 12 Aug 2021 10:31:01 +0530
Subject: [PATCH 331/386] fix: Stock Analytics Report must consider warehouse
during calculation (#26908)
* fix: Stock Analytics Report must consider warehouse during calculation
* fix: Brand filter in Stock Analytics
(cherry picked from commit 703b081172981833bcf9a1fc5c86517817c3ff32)
---
.../report/stock_analytics/stock_analytics.py | 44 +++++++++++++++----
.../report/stock_balance/stock_balance.py | 3 ++
2 files changed, 39 insertions(+), 8 deletions(-)
diff --git a/erpnext/stock/report/stock_analytics/stock_analytics.py b/erpnext/stock/report/stock_analytics/stock_analytics.py
index 0cc8ca48aa..d44685060c 100644
--- a/erpnext/stock/report/stock_analytics/stock_analytics.py
+++ b/erpnext/stock/report/stock_analytics/stock_analytics.py
@@ -114,14 +114,41 @@ def get_period(posting_date, filters):
def get_periodic_data(entry, filters):
+ """Structured as:
+ Item 1
+ - Balance (updated and carried forward):
+ - Warehouse A : bal_qty/value
+ - Warehouse B : bal_qty/value
+ - Jun 2021 (sum of warehouse quantities used in report)
+ - Warehouse A : bal_qty/value
+ - Warehouse B : bal_qty/value
+ - Jul 2021 (sum of warehouse quantities used in report)
+ - Warehouse A : bal_qty/value
+ - Warehouse B : bal_qty/value
+ Item 2
+ - Balance (updated and carried forward):
+ - Warehouse A : bal_qty/value
+ - Warehouse B : bal_qty/value
+ - Jun 2021 (sum of warehouse quantities used in report)
+ - Warehouse A : bal_qty/value
+ - Warehouse B : bal_qty/value
+ - Jul 2021 (sum of warehouse quantities used in report)
+ - Warehouse A : bal_qty/value
+ - Warehouse B : bal_qty/value
+ """
periodic_data = {}
for d in entry:
period = get_period(d.posting_date, filters)
bal_qty = 0
+ # if period against item does not exist yet, instantiate it
+ # insert existing balance dict against period, and add/subtract to it
+ if periodic_data.get(d.item_code) and not periodic_data.get(d.item_code).get(period):
+ periodic_data[d.item_code][period] = periodic_data[d.item_code]['balance']
+
if d.voucher_type == "Stock Reconciliation":
- if periodic_data.get(d.item_code):
- bal_qty = periodic_data[d.item_code]["balance"]
+ if periodic_data.get(d.item_code) and periodic_data.get(d.item_code).get('balance').get(d.warehouse):
+ bal_qty = periodic_data[d.item_code]['balance'][d.warehouse]
qty_diff = d.qty_after_transaction - bal_qty
else:
@@ -132,12 +159,12 @@ def get_periodic_data(entry, filters):
else:
value = d.stock_value_difference
- periodic_data.setdefault(d.item_code, {}).setdefault(period, 0.0)
- periodic_data.setdefault(d.item_code, {}).setdefault("balance", 0.0)
-
- periodic_data[d.item_code]["balance"] += value
- periodic_data[d.item_code][period] = periodic_data[d.item_code]["balance"]
+ # period-warehouse wise balance
+ periodic_data.setdefault(d.item_code, {}).setdefault('balance', {}).setdefault(d.warehouse, 0.0)
+ periodic_data.setdefault(d.item_code, {}).setdefault(period, {}).setdefault(d.warehouse, 0.0)
+ periodic_data[d.item_code]['balance'][d.warehouse] += value
+ periodic_data[d.item_code][period][d.warehouse] = periodic_data[d.item_code]['balance'][d.warehouse]
return periodic_data
@@ -160,7 +187,8 @@ def get_data(filters):
total = 0
for dummy, end_date in ranges:
period = get_period(end_date, filters)
- amount = flt(periodic_data.get(item_data.name, {}).get(period))
+ period_data = periodic_data.get(item_data.name, {}).get(period)
+ amount = sum(period_data.values()) if period_data else 0
row[scrub(period)] = amount
total += amount
row["total"] = total
diff --git a/erpnext/stock/report/stock_balance/stock_balance.py b/erpnext/stock/report/stock_balance/stock_balance.py
index 9e56ad4130..fc3d719a78 100644
--- a/erpnext/stock/report/stock_balance/stock_balance.py
+++ b/erpnext/stock/report/stock_balance/stock_balance.py
@@ -235,12 +235,15 @@ def filter_items_with_no_transactions(iwb_map, float_precision):
return iwb_map
def get_items(filters):
+ "Get items based on item code, item group or brand."
conditions = []
if filters.get("item_code"):
conditions.append("item.name=%(item_code)s")
else:
if filters.get("item_group"):
conditions.append(get_item_group_condition(filters.get("item_group")))
+ if filters.get("brand"): # used in stock analytics report
+ conditions.append("item.brand=%(brand)s")
items = []
if conditions:
From f4b2f4aaf7823cdae0ed344035fc8835ba2d9909 Mon Sep 17 00:00:00 2001
From: Frappe PR Bot
Date: Thu, 12 Aug 2021 17:11:38 +0530
Subject: [PATCH 332/386] fix: ZeroDivisionError on creating e-invoice for
credit note (#26918)
---
erpnext/regional/india/e_invoice/utils.py | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/erpnext/regional/india/e_invoice/utils.py b/erpnext/regional/india/e_invoice/utils.py
index e65442dbff..2373512cca 100644
--- a/erpnext/regional/india/e_invoice/utils.py
+++ b/erpnext/regional/india/e_invoice/utils.py
@@ -190,8 +190,10 @@ def get_item_list(invoice):
item.description = sanitize_for_json(d.item_name)
item.qty = abs(item.qty)
-
- item.unit_rate = abs(item.taxable_value / item.qty)
+ if flt(item.qty) != 0.0:
+ item.unit_rate = abs(item.taxable_value / item.qty)
+ else:
+ item.unit_rate = abs(item.taxable_value)
item.gross_amount = abs(item.taxable_value)
item.taxable_value = abs(item.taxable_value)
item.discount_amount = 0
From 2e6899fbe439a6d194eedb3ef46adbdd9d2e4cfb Mon Sep 17 00:00:00 2001
From: Marica
Date: Fri, 13 Aug 2021 15:37:45 +0530
Subject: [PATCH 333/386] fix: Copy previous balance dict object instead of
assigning (#26942)
- Due to plain assignment, dict mutation gave wrong monthly values
(cherry picked from commit fe2a34f17197a2877356bcdf5d0bb6c46312ed33)
---
erpnext/stock/report/stock_analytics/stock_analytics.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/erpnext/stock/report/stock_analytics/stock_analytics.py b/erpnext/stock/report/stock_analytics/stock_analytics.py
index d44685060c..fde934b133 100644
--- a/erpnext/stock/report/stock_analytics/stock_analytics.py
+++ b/erpnext/stock/report/stock_analytics/stock_analytics.py
@@ -144,7 +144,8 @@ def get_periodic_data(entry, filters):
# if period against item does not exist yet, instantiate it
# insert existing balance dict against period, and add/subtract to it
if periodic_data.get(d.item_code) and not periodic_data.get(d.item_code).get(period):
- periodic_data[d.item_code][period] = periodic_data[d.item_code]['balance']
+ previous_balance = periodic_data[d.item_code]['balance'].copy()
+ periodic_data[d.item_code][period] = previous_balance
if d.voucher_type == "Stock Reconciliation":
if periodic_data.get(d.item_code) and periodic_data.get(d.item_code).get('balance').get(d.warehouse):
From 15149165205876059346f9f3c6787a0e42fe9bd4 Mon Sep 17 00:00:00 2001
From: Suraj Shetty <13928957+surajshetty3416@users.noreply.github.com>
Date: Thu, 12 Aug 2021 21:12:52 +0530
Subject: [PATCH 334/386] fix: Nest `.level` class style under `.hierarchy`
class (#26905)
fix: Nest `.level` class style under `.hierarchy` class
---
erpnext/public/scss/hierarchy_chart.scss | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/erpnext/public/scss/hierarchy_chart.scss b/erpnext/public/scss/hierarchy_chart.scss
index 8a1ec4992b..a66d6474e0 100644
--- a/erpnext/public/scss/hierarchy_chart.scss
+++ b/erpnext/public/scss/hierarchy_chart.scss
@@ -206,10 +206,12 @@
margin: 0px 0px 16px 0px;
}
-.level {
- margin-right: 8px;
- align-items: flex-start;
- flex-direction: column;
+.hierarchy, .hierarchy-mobile {
+ .level {
+ margin-right: 8px;
+ align-items: flex-start;
+ flex-direction: column;
+ }
}
#arrows {
From 4c612b7cb291b8318af595fa7efdbd7ee7e4f9f8 Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Sun, 15 Aug 2021 21:32:39 +0530
Subject: [PATCH 335/386] fix: add z-index to filter to avoid svg wrapper
overlapping
---
erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js | 1 +
1 file changed, 1 insertion(+)
diff --git a/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js b/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
index 89fb8d5792..fd4365ad8f 100644
--- a/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
+++ b/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
@@ -98,6 +98,7 @@ erpnext.HierarchyChart = class {
company.refresh();
$(`[data-fieldname="company"]`).trigger('change');
+ $(`[data-fieldname="company"] .link-field`).css('z-index', 2);
}
setup_actions() {
From 0b4959966c04ee708ef8fb6d573bdeeeb3694741 Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Mon, 16 Aug 2021 10:19:48 +0530
Subject: [PATCH 336/386] fix: expand all nodes not working when there are only
2 levels
- added dom freeze while expanding all nodes and exporting
---
.../organizational_chart.py | 17 +++++++++--------
.../hierarchy_chart/hierarchy_chart_desktop.js | 16 ++++++++++++----
2 files changed, 21 insertions(+), 12 deletions(-)
diff --git a/erpnext/hr/page/organizational_chart/organizational_chart.py b/erpnext/hr/page/organizational_chart/organizational_chart.py
index 1e03e3d06a..2983198217 100644
--- a/erpnext/hr/page/organizational_chart/organizational_chart.py
+++ b/erpnext/hr/page/organizational_chart/organizational_chart.py
@@ -32,16 +32,17 @@ def get_children(parent=None, company=None, exclude_node=None):
def get_connections(employee):
num_connections = 0
- connections = frappe.get_list('Employee', filters=[
+ nodes_to_expand = frappe.get_list('Employee', filters=[
['reports_to', '=', employee]
])
- num_connections += len(connections)
+ num_connections += len(nodes_to_expand)
- while connections:
- for entry in connections:
- connections = frappe.get_list('Employee', filters=[
- ['reports_to', '=', entry.name]
- ])
- num_connections += len(connections)
+ while nodes_to_expand:
+ parent = nodes_to_expand.pop(0)
+ descendants = frappe.get_list('Employee', filters=[
+ ['reports_to', '=', parent.name]
+ ])
+ num_connections += len(descendants)
+ nodes_to_expand.extend(descendants)
return num_connections
\ No newline at end of file
diff --git a/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js b/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
index fd4365ad8f..da050abc6e 100644
--- a/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
+++ b/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
@@ -103,6 +103,7 @@ erpnext.HierarchyChart = class {
setup_actions() {
let me = this;
+ this.page.clear_inner_toolbar();
this.page.add_inner_button(__('Export'), function() {
me.export_chart();
});
@@ -124,6 +125,7 @@ erpnext.HierarchyChart = class {
}
export_chart() {
+ frappe.dom.freeze(__('Exporting...'));
this.page.main.css({
'min-height': '',
'max-height': '',
@@ -147,6 +149,8 @@ erpnext.HierarchyChart = class {
a.href = dataURL;
a.download = 'hierarchy_chart';
a.click();
+ }).finally(() => {
+ frappe.dom.unfreeze();
});
this.setup_page_style();
@@ -170,7 +174,9 @@ erpnext.HierarchyChart = class {
this.page.main
.find('#hierarchy-chart-wrapper')
.append(this.$hierarchy);
+
this.nodes = {};
+ this.all_nodes_expanded = false;
}
make_svg_markers() {
@@ -203,7 +209,7 @@ erpnext.HierarchyChart = class {
render_root_nodes(expanded_view=false) {
let me = this;
- frappe.call({
+ return frappe.call({
method: me.method,
args: {
company: me.company
@@ -230,8 +236,8 @@ erpnext.HierarchyChart = class {
expand_node = node;
});
+ me.root_node = expand_node;
if (!expanded_view) {
- me.root_node = expand_node;
me.expand_node(expand_node);
}
}
@@ -281,10 +287,12 @@ erpnext.HierarchyChart = class {
]);
} else {
frappe.run_serially([
+ () => frappe.dom.freeze(),
() => this.setup_hierarchy(),
() => this.render_root_nodes(true),
() => this.get_all_nodes(node.id, node.name),
- (data_list) => this.render_children_of_all_nodes(data_list)
+ (data_list) => this.render_children_of_all_nodes(data_list),
+ () => frappe.dom.unfreeze()
]);
}
}
@@ -360,7 +368,7 @@ erpnext.HierarchyChart = class {
node = this.nodes[entry.parent];
if (node) {
this.render_child_nodes_for_expanded_view(node, entry.data);
- } else {
+ } else if (data_list.length) {
data_list.push(entry);
}
}
From 67e3971c3bb80a37a03da320172e7df1f17dd18b Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Mon, 16 Aug 2021 10:38:39 +0530
Subject: [PATCH 337/386] fix: Org Chart fixes (#26952)
* fix: add z-index to filter to avoid svg wrapper overlapping
* fix: expand all nodes not working when there are only 2 levels
- added dom freeze while expanding all nodes and exporting
---
.../organizational_chart.py | 17 +++++++++--------
.../hierarchy_chart/hierarchy_chart_desktop.js | 17 +++++++++++++----
2 files changed, 22 insertions(+), 12 deletions(-)
diff --git a/erpnext/hr/page/organizational_chart/organizational_chart.py b/erpnext/hr/page/organizational_chart/organizational_chart.py
index 1e03e3d06a..2983198217 100644
--- a/erpnext/hr/page/organizational_chart/organizational_chart.py
+++ b/erpnext/hr/page/organizational_chart/organizational_chart.py
@@ -32,16 +32,17 @@ def get_children(parent=None, company=None, exclude_node=None):
def get_connections(employee):
num_connections = 0
- connections = frappe.get_list('Employee', filters=[
+ nodes_to_expand = frappe.get_list('Employee', filters=[
['reports_to', '=', employee]
])
- num_connections += len(connections)
+ num_connections += len(nodes_to_expand)
- while connections:
- for entry in connections:
- connections = frappe.get_list('Employee', filters=[
- ['reports_to', '=', entry.name]
- ])
- num_connections += len(connections)
+ while nodes_to_expand:
+ parent = nodes_to_expand.pop(0)
+ descendants = frappe.get_list('Employee', filters=[
+ ['reports_to', '=', parent.name]
+ ])
+ num_connections += len(descendants)
+ nodes_to_expand.extend(descendants)
return num_connections
\ No newline at end of file
diff --git a/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js b/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
index 89fb8d5792..da050abc6e 100644
--- a/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
+++ b/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
@@ -98,10 +98,12 @@ erpnext.HierarchyChart = class {
company.refresh();
$(`[data-fieldname="company"]`).trigger('change');
+ $(`[data-fieldname="company"] .link-field`).css('z-index', 2);
}
setup_actions() {
let me = this;
+ this.page.clear_inner_toolbar();
this.page.add_inner_button(__('Export'), function() {
me.export_chart();
});
@@ -123,6 +125,7 @@ erpnext.HierarchyChart = class {
}
export_chart() {
+ frappe.dom.freeze(__('Exporting...'));
this.page.main.css({
'min-height': '',
'max-height': '',
@@ -146,6 +149,8 @@ erpnext.HierarchyChart = class {
a.href = dataURL;
a.download = 'hierarchy_chart';
a.click();
+ }).finally(() => {
+ frappe.dom.unfreeze();
});
this.setup_page_style();
@@ -169,7 +174,9 @@ erpnext.HierarchyChart = class {
this.page.main
.find('#hierarchy-chart-wrapper')
.append(this.$hierarchy);
+
this.nodes = {};
+ this.all_nodes_expanded = false;
}
make_svg_markers() {
@@ -202,7 +209,7 @@ erpnext.HierarchyChart = class {
render_root_nodes(expanded_view=false) {
let me = this;
- frappe.call({
+ return frappe.call({
method: me.method,
args: {
company: me.company
@@ -229,8 +236,8 @@ erpnext.HierarchyChart = class {
expand_node = node;
});
+ me.root_node = expand_node;
if (!expanded_view) {
- me.root_node = expand_node;
me.expand_node(expand_node);
}
}
@@ -280,10 +287,12 @@ erpnext.HierarchyChart = class {
]);
} else {
frappe.run_serially([
+ () => frappe.dom.freeze(),
() => this.setup_hierarchy(),
() => this.render_root_nodes(true),
() => this.get_all_nodes(node.id, node.name),
- (data_list) => this.render_children_of_all_nodes(data_list)
+ (data_list) => this.render_children_of_all_nodes(data_list),
+ () => frappe.dom.unfreeze()
]);
}
}
@@ -359,7 +368,7 @@ erpnext.HierarchyChart = class {
node = this.nodes[entry.parent];
if (node) {
this.render_child_nodes_for_expanded_view(node, entry.data);
- } else {
+ } else if (data_list.length) {
data_list.push(entry);
}
}
From 3f07bb70215a8834d887f8f3fe2f48db99d59e65 Mon Sep 17 00:00:00 2001
From: Deepesh Garg
Date: Mon, 16 Aug 2021 13:18:39 +0530
Subject: [PATCH 338/386] fix: Add mandatory depends on condition for export
type field
---
erpnext/patches.txt | 2 +-
erpnext/patches/v13_0/update_export_type_for_gst.py | 12 ++++++++++--
erpnext/regional/india/setup.py | 6 ++++--
3 files changed, 15 insertions(+), 5 deletions(-)
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 86356e3026..0fc50c5954 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -296,7 +296,7 @@ erpnext.patches.v13_0.update_subscription_status_in_memberships
erpnext.patches.v13_0.update_amt_in_work_order_required_items
erpnext.patches.v12_0.show_einvoice_irn_cancelled_field
erpnext.patches.v13_0.delete_orphaned_tables
-erpnext.patches.v13_0.update_export_type_for_gst
+erpnext.patches.v13_0.update_export_type_for_gst #2021-08-16
erpnext.patches.v13_0.update_tds_check_field #3
erpnext.patches.v13_0.add_custom_field_for_south_africa #2
erpnext.patches.v13_0.shopify_deprecation_warning
diff --git a/erpnext/patches/v13_0/update_export_type_for_gst.py b/erpnext/patches/v13_0/update_export_type_for_gst.py
index 478a2a6c80..3e20212af6 100644
--- a/erpnext/patches/v13_0/update_export_type_for_gst.py
+++ b/erpnext/patches/v13_0/update_export_type_for_gst.py
@@ -8,11 +8,19 @@ def execute():
# Update custom fields
fieldname = frappe.db.get_value('Custom Field', {'dt': 'Customer', 'fieldname': 'export_type'})
if fieldname:
- frappe.db.set_value('Custom Field', fieldname, 'default', '')
+ frappe.db.set_value('Custom Field', fieldname,
+ {
+ 'default': '',
+ 'mandatory_depends_on': 'eval:in_list(["SEZ", "Overseas", "Deemed Export"], doc.gst_category)'
+ })
fieldname = frappe.db.get_value('Custom Field', {'dt': 'Supplier', 'fieldname': 'export_type'})
if fieldname:
- frappe.db.set_value('Custom Field', fieldname, 'default', '')
+ frappe.db.set_value('Custom Field', fieldname,
+ {
+ 'default': '',
+ 'mandatory_depends_on': 'eval:in_list(["SEZ", "Overseas"], doc.gst_category)'
+ })
# Update Customer/Supplier Masters
frappe.db.sql("""
diff --git a/erpnext/regional/india/setup.py b/erpnext/regional/india/setup.py
index b4f146ce57..2d6b913390 100644
--- a/erpnext/regional/india/setup.py
+++ b/erpnext/regional/india/setup.py
@@ -642,7 +642,8 @@ def make_custom_fields(update=True):
'fieldtype': 'Select',
'insert_after': 'gst_category',
'depends_on':'eval:in_list(["SEZ", "Overseas"], doc.gst_category)',
- 'options': '\nWith Payment of Tax\nWithout Payment of Tax'
+ 'options': '\nWith Payment of Tax\nWithout Payment of Tax',
+ 'mandatory_depends_on': 'eval:in_list(["SEZ", "Overseas"], doc.gst_category)'
}
],
'Customer': [
@@ -660,7 +661,8 @@ def make_custom_fields(update=True):
'fieldtype': 'Select',
'insert_after': 'gst_category',
'depends_on':'eval:in_list(["SEZ", "Overseas", "Deemed Export"], doc.gst_category)',
- 'options': '\nWith Payment of Tax\nWithout Payment of Tax'
+ 'options': '\nWith Payment of Tax\nWithout Payment of Tax',
+ 'mandatory_depends_on': 'eval:in_list(["SEZ", "Overseas", "Deemed Export"], doc.gst_category)'
}
],
'Member': [
From b58b1127f3776735484a41d4884387397e78533d Mon Sep 17 00:00:00 2001
From: Deepesh Garg
Date: Mon, 16 Aug 2021 13:18:39 +0530
Subject: [PATCH 339/386] fix: Add mandatory depends on condition for export
type field
---
erpnext/patches.txt | 2 +-
erpnext/patches/v13_0/update_export_type_for_gst.py | 12 ++++++++++--
erpnext/regional/india/setup.py | 6 ++++--
3 files changed, 15 insertions(+), 5 deletions(-)
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index b891719b02..fec727d289 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -293,4 +293,4 @@ erpnext.patches.v13_0.update_job_card_details
erpnext.patches.v13_0.update_level_in_bom #1234sswef
erpnext.patches.v13_0.add_missing_fg_item_for_stock_entry
erpnext.patches.v13_0.update_subscription_status_in_memberships
-erpnext.patches.v13_0.update_export_type_for_gst
+erpnext.patches.v13_0.update_export_type_for_gst #2021-08-16
diff --git a/erpnext/patches/v13_0/update_export_type_for_gst.py b/erpnext/patches/v13_0/update_export_type_for_gst.py
index 478a2a6c80..3e20212af6 100644
--- a/erpnext/patches/v13_0/update_export_type_for_gst.py
+++ b/erpnext/patches/v13_0/update_export_type_for_gst.py
@@ -8,11 +8,19 @@ def execute():
# Update custom fields
fieldname = frappe.db.get_value('Custom Field', {'dt': 'Customer', 'fieldname': 'export_type'})
if fieldname:
- frappe.db.set_value('Custom Field', fieldname, 'default', '')
+ frappe.db.set_value('Custom Field', fieldname,
+ {
+ 'default': '',
+ 'mandatory_depends_on': 'eval:in_list(["SEZ", "Overseas", "Deemed Export"], doc.gst_category)'
+ })
fieldname = frappe.db.get_value('Custom Field', {'dt': 'Supplier', 'fieldname': 'export_type'})
if fieldname:
- frappe.db.set_value('Custom Field', fieldname, 'default', '')
+ frappe.db.set_value('Custom Field', fieldname,
+ {
+ 'default': '',
+ 'mandatory_depends_on': 'eval:in_list(["SEZ", "Overseas"], doc.gst_category)'
+ })
# Update Customer/Supplier Masters
frappe.db.sql("""
diff --git a/erpnext/regional/india/setup.py b/erpnext/regional/india/setup.py
index e9372f9b8f..37c714d216 100644
--- a/erpnext/regional/india/setup.py
+++ b/erpnext/regional/india/setup.py
@@ -642,7 +642,8 @@ def make_custom_fields(update=True):
'fieldtype': 'Select',
'insert_after': 'gst_category',
'depends_on':'eval:in_list(["SEZ", "Overseas"], doc.gst_category)',
- 'options': '\nWith Payment of Tax\nWithout Payment of Tax'
+ 'options': '\nWith Payment of Tax\nWithout Payment of Tax',
+ 'mandatory_depends_on': 'eval:in_list(["SEZ", "Overseas"], doc.gst_category)'
}
],
'Customer': [
@@ -660,7 +661,8 @@ def make_custom_fields(update=True):
'fieldtype': 'Select',
'insert_after': 'gst_category',
'depends_on':'eval:in_list(["SEZ", "Overseas", "Deemed Export"], doc.gst_category)',
- 'options': '\nWith Payment of Tax\nWithout Payment of Tax'
+ 'options': '\nWith Payment of Tax\nWithout Payment of Tax',
+ 'mandatory_depends_on': 'eval:in_list(["SEZ", "Overseas", "Deemed Export"], doc.gst_category)'
}
],
'Member': [
From a9a24051c94dc07dae6b12b9099c1a4dc9c3e2cf Mon Sep 17 00:00:00 2001
From: Anupam Kumar
Date: Mon, 16 Aug 2021 14:48:53 +0530
Subject: [PATCH 340/386] feat: enable track changes for leave type (#26917)
Co-authored-by: Jannat Patel <31363128+pateljannat@users.noreply.github.com>
---
erpnext/hr/doctype/leave_type/leave_type.json | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/erpnext/hr/doctype/leave_type/leave_type.json b/erpnext/hr/doctype/leave_type/leave_type.json
index fc577ef1d3..8f2ae6eb15 100644
--- a/erpnext/hr/doctype/leave_type/leave_type.json
+++ b/erpnext/hr/doctype/leave_type/leave_type.json
@@ -214,7 +214,7 @@
"icon": "fa fa-flag",
"idx": 1,
"links": [],
- "modified": "2021-03-02 11:22:33.776320",
+ "modified": "2021-08-12 16:10:36.464690",
"modified_by": "Administrator",
"module": "HR",
"name": "Leave Type",
@@ -248,5 +248,6 @@
}
],
"sort_field": "modified",
- "sort_order": "DESC"
+ "sort_order": "DESC",
+ "track_changes": 1
}
\ No newline at end of file
From 8410e4854ff90f68c2e5d41072aa0665d7482edb Mon Sep 17 00:00:00 2001
From: Deepesh Garg
Date: Mon, 16 Aug 2021 17:14:40 +0530
Subject: [PATCH 341/386] fix: Budget variance missing values
---
.../report/budget_variance_report/budget_variance_report.py | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/erpnext/accounts/report/budget_variance_report/budget_variance_report.py b/erpnext/accounts/report/budget_variance_report/budget_variance_report.py
index f1b231b690..9f0eee8aa5 100644
--- a/erpnext/accounts/report/budget_variance_report/budget_variance_report.py
+++ b/erpnext/accounts/report/budget_variance_report/budget_variance_report.py
@@ -38,8 +38,8 @@ def execute(filters=None):
GROUP BY parent''',{'dimension':[dimension]})
if DCC_allocation:
filters['budget_against_filter'] = [DCC_allocation[0][0]]
- cam_map = get_dimension_account_month_map(filters)
- dimension_items = cam_map.get(DCC_allocation[0][0])
+ ddc_cam_map = get_dimension_account_month_map(filters)
+ dimension_items = ddc_cam_map.get(DCC_allocation[0][0])
if dimension_items:
data = get_final_data(dimension, dimension_items, filters, period_month_ranges, data, DCC_allocation[0][1])
@@ -48,7 +48,6 @@ def execute(filters=None):
return columns, data, None, chart
def get_final_data(dimension, dimension_items, filters, period_month_ranges, data, DCC_allocation):
-
for account, monthwise_data in iteritems(dimension_items):
row = [dimension, account]
totals = [0, 0, 0]
From bf75ea70fba1925cbfade53ae2e9d36d8b32ae88 Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Mon, 16 Aug 2021 17:22:51 +0530
Subject: [PATCH 342/386] feat: Training Event Status Update and Validations
(#26698)
* fix: training event employee status not updated on feedback submission
* feat: update attendees status on training event status update
* test: Training Event and Feedback
* chore: remove unused import
---
.../training_event/test_training_event.py | 57 +++++++++++------
.../doctype/training_event/training_event.py | 17 ++++-
.../test_training_feedback.py | 63 +++++++++++++++++--
.../training_feedback/training_feedback.py | 38 ++++++++---
4 files changed, 142 insertions(+), 33 deletions(-)
diff --git a/erpnext/hr/doctype/training_event/test_training_event.py b/erpnext/hr/doctype/training_event/test_training_event.py
index 313f90eba8..9b32136bfb 100644
--- a/erpnext/hr/doctype/training_event/test_training_event.py
+++ b/erpnext/hr/doctype/training_event/test_training_event.py
@@ -11,21 +11,34 @@ from erpnext.payroll.doctype.salary_structure.test_salary_structure import make_
class TestTrainingEvent(unittest.TestCase):
def setUp(self):
create_training_program("Basic Training")
- self.employee = make_employee("robert_loan@trainig.com")
- self.employee2 = make_employee("suzie.tan@trainig.com")
+ employee = make_employee("robert_loan@trainig.com")
+ employee2 = make_employee("suzie.tan@trainig.com")
+ self.attendees = [
+ {"employee": employee},
+ {"employee": employee2}
+ ]
+
+ def test_training_event_status_update(self):
+ training_event = create_training_event(self.attendees)
+ training_event.submit()
+
+ training_event.event_status = "Completed"
+ training_event.save()
+ training_event.reload()
+
+ for entry in training_event.employees:
+ self.assertEqual(entry.status, "Completed")
+
+ training_event.event_status = "Scheduled"
+ training_event.save()
+ training_event.reload()
+
+ for entry in training_event.employees:
+ self.assertEqual(entry.status, "Open")
+
+ def tearDown(self):
+ frappe.db.rollback()
- def test_create_training_event(self):
- if not frappe.db.get_value("Training Event", "Basic Training Event"):
- frappe.get_doc({
- "doctype": "Training Event",
- "event_name": "Basic Training Event",
- "training_program": "Basic Training",
- "location": "Union Square",
- "start_time": add_days(today(), 5),
- "end_time": add_days(today(), 6),
- "introduction": "Welcome to the Basic Training Event",
- "employees": get_attendees(self.employee, self.employee2)
- }).insert()
def create_training_program(training_program):
if not frappe.db.get_value("Training Program", training_program):
@@ -35,8 +48,14 @@ def create_training_program(training_program):
"description": training_program
}).insert()
-def get_attendees(employee, employee2):
- return [
- {"employee": employee},
- {"employee": employee2}
- ]
\ No newline at end of file
+def create_training_event(attendees):
+ return frappe.get_doc({
+ "doctype": "Training Event",
+ "event_name": "Basic Training Event",
+ "training_program": "Basic Training",
+ "location": "Union Square",
+ "start_time": add_days(today(), 5),
+ "end_time": add_days(today(), 6),
+ "introduction": "Welcome to the Basic Training Event",
+ "employees": attendees
+ }).insert()
\ No newline at end of file
diff --git a/erpnext/hr/doctype/training_event/training_event.py b/erpnext/hr/doctype/training_event/training_event.py
index 5064f03308..e2c30cb314 100644
--- a/erpnext/hr/doctype/training_event/training_event.py
+++ b/erpnext/hr/doctype/training_event/training_event.py
@@ -14,10 +14,25 @@ class TrainingEvent(Document):
self.set_employee_emails()
self.validate_period()
+ def on_update_after_submit(self):
+ self.set_status_for_attendees()
+
def set_employee_emails(self):
self.employee_emails = ', '.join(get_employee_emails([d.employee
for d in self.employees]))
def validate_period(self):
if time_diff_in_seconds(self.end_time, self.start_time) <= 0:
- frappe.throw(_('End time cannot be before start time'))
\ No newline at end of file
+ frappe.throw(_('End time cannot be before start time'))
+
+ def set_status_for_attendees(self):
+ if self.event_status == 'Completed':
+ for employee in self.employees:
+ if employee.attendance == 'Present' and employee.status != 'Feedback Submitted':
+ employee.status = 'Completed'
+
+ elif self.event_status == 'Scheduled':
+ for employee in self.employees:
+ employee.status = 'Open'
+
+ self.db_update_all()
diff --git a/erpnext/hr/doctype/training_feedback/test_training_feedback.py b/erpnext/hr/doctype/training_feedback/test_training_feedback.py
index 34559982a2..c30a3ad34c 100644
--- a/erpnext/hr/doctype/training_feedback/test_training_feedback.py
+++ b/erpnext/hr/doctype/training_feedback/test_training_feedback.py
@@ -5,8 +5,63 @@ from __future__ import unicode_literals
import frappe
import unittest
-
-# test_records = frappe.get_test_records('Training Feedback')
-
+from erpnext.payroll.doctype.salary_structure.test_salary_structure import make_employee
+from erpnext.hr.doctype.training_event.test_training_event import create_training_program, create_training_event
class TestTrainingFeedback(unittest.TestCase):
- pass
+ def setUp(self):
+ create_training_program("Basic Training")
+ self.employee = make_employee("robert_loan@trainig.com")
+ self.employee2 = make_employee("suzie.tan@trainig.com")
+ self.attendees = [{"employee": self.employee}]
+
+ def test_employee_validations_for_feedback(self):
+ training_event = create_training_event(self.attendees)
+ training_event.submit()
+
+ training_event.event_status = "Completed"
+ training_event.save()
+ training_event.reload()
+
+ # should not allow creating feedback since employee2 was not part of the event
+ feedback = create_training_feedback(training_event.name, self.employee2)
+ self.assertRaises(frappe.ValidationError, feedback.save)
+
+ # cannot record feedback for absent employee
+ employee = frappe.db.get_value("Training Event Employee", {
+ "parent": training_event.name,
+ "employee": self.employee
+ }, "name")
+
+ frappe.db.set_value("Training Event Employee", employee, "attendance", "Absent")
+ feedback = create_training_feedback(training_event.name, self.employee)
+ self.assertRaises(frappe.ValidationError, feedback.save)
+
+ def test_training_feedback_status(self):
+ training_event = create_training_event(self.attendees)
+ training_event.submit()
+
+ training_event.event_status = "Completed"
+ training_event.save()
+ training_event.reload()
+
+ feedback = create_training_feedback(training_event.name, self.employee)
+ feedback.submit()
+
+ status = frappe.db.get_value("Training Event Employee", {
+ "parent": training_event.name,
+ "employee": self.employee
+ }, "status")
+
+ self.assertEqual(status, "Feedback Submitted")
+
+ def tearDown(self):
+ frappe.db.rollback()
+
+
+def create_training_feedback(event, employee):
+ return frappe.get_doc({
+ "doctype": "Training Feedback",
+ "training_event": event,
+ "employee": employee,
+ "feedback": "Test"
+ })
\ No newline at end of file
diff --git a/erpnext/hr/doctype/training_feedback/training_feedback.py b/erpnext/hr/doctype/training_feedback/training_feedback.py
index 1a33450791..0d32de793c 100644
--- a/erpnext/hr/doctype/training_feedback/training_feedback.py
+++ b/erpnext/hr/doctype/training_feedback/training_feedback.py
@@ -11,15 +11,35 @@ class TrainingFeedback(Document):
def validate(self):
training_event = frappe.get_doc("Training Event", self.training_event)
if training_event.docstatus != 1:
- frappe.throw(_('{0} must be submitted').format(_('Training Event')))
+ frappe.throw(_("{0} must be submitted").format(_("Training Event")))
+
+ emp_event_details = frappe.db.get_value("Training Event Employee", {
+ "parent": self.training_event,
+ "employee": self.employee
+ }, ["name", "attendance"], as_dict=True)
+
+ if not emp_event_details:
+ frappe.throw(_("Employee {0} not found in Training Event Participants.").format(
+ frappe.bold(self.employee_name)))
+
+ if emp_event_details.attendance == "Absent":
+ frappe.throw(_("Feedback cannot be recorded for an absent Employee."))
def on_submit(self):
- training_event = frappe.get_doc("Training Event", self.training_event)
- event_status = None
- for e in training_event.employees:
- if e.employee == self.employee:
- event_status = 'Feedback Submitted'
- break
+ employee = frappe.db.get_value("Training Event Employee", {
+ "parent": self.training_event,
+ "employee": self.employee
+ })
+
+ if employee:
+ frappe.db.set_value("Training Event Employee", employee, "status", "Feedback Submitted")
+
+ def on_cancel(self):
+ employee = frappe.db.get_value("Training Event Employee", {
+ "parent": self.training_event,
+ "employee": self.employee
+ })
+
+ if employee:
+ frappe.db.set_value("Training Event Employee", employee, "status", "Completed")
- if event_status:
- frappe.db.set_value("Training Event", self.training_event, "event_status", event_status)
From 2a43fe1a22f993ed4eca779ce268064e56fe5246 Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Mon, 16 Aug 2021 18:03:21 +0530
Subject: [PATCH 343/386] ci: ignore backports while checking docs (#26962)
[skip ci]
---
.github/helper/documentation.py | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/.github/helper/documentation.py b/.github/helper/documentation.py
index 9cc4663c39..b4a4ba1bbd 100644
--- a/.github/helper/documentation.py
+++ b/.github/helper/documentation.py
@@ -32,11 +32,15 @@ if __name__ == "__main__":
if response.ok:
payload = response.json()
- title = payload.get("title", "").lower()
+ title = payload.get("title", "").lower().strip()
head_sha = payload.get("head", {}).get("sha")
body = payload.get("body", "").lower()
- if title.startswith("feat") and head_sha and "no-docs" not in body:
+ if (title.startswith("feat")
+ and head_sha
+ and "no-docs" not in body
+ and "backport" not in body
+ ):
if docs_link_exists(body):
print("Documentation Link Found. You're Awesome! 🎉")
From 58c1739eacf18bd7866c6bf852375624aa985f1a Mon Sep 17 00:00:00 2001
From: Deepesh Garg
Date: Mon, 16 Aug 2021 17:14:40 +0530
Subject: [PATCH 344/386] fix: Budget variance missing values
---
.../report/budget_variance_report/budget_variance_report.py | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/erpnext/accounts/report/budget_variance_report/budget_variance_report.py b/erpnext/accounts/report/budget_variance_report/budget_variance_report.py
index f1b231b690..9f0eee8aa5 100644
--- a/erpnext/accounts/report/budget_variance_report/budget_variance_report.py
+++ b/erpnext/accounts/report/budget_variance_report/budget_variance_report.py
@@ -38,8 +38,8 @@ def execute(filters=None):
GROUP BY parent''',{'dimension':[dimension]})
if DCC_allocation:
filters['budget_against_filter'] = [DCC_allocation[0][0]]
- cam_map = get_dimension_account_month_map(filters)
- dimension_items = cam_map.get(DCC_allocation[0][0])
+ ddc_cam_map = get_dimension_account_month_map(filters)
+ dimension_items = ddc_cam_map.get(DCC_allocation[0][0])
if dimension_items:
data = get_final_data(dimension, dimension_items, filters, period_month_ranges, data, DCC_allocation[0][1])
@@ -48,7 +48,6 @@ def execute(filters=None):
return columns, data, None, chart
def get_final_data(dimension, dimension_items, filters, period_month_ranges, data, DCC_allocation):
-
for account, monthwise_data in iteritems(dimension_items):
row = [dimension, account]
totals = [0, 0, 0]
From 33032ce07d7857dc90b8c66db1744481601664d0 Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Mon, 16 Aug 2021 19:27:29 +0530
Subject: [PATCH 345/386] fix: test
---
cypress/integration/test_organizational_chart_desktop.js | 3 +++
1 file changed, 3 insertions(+)
diff --git a/cypress/integration/test_organizational_chart_desktop.js b/cypress/integration/test_organizational_chart_desktop.js
index fb46bbb433..5dac15f218 100644
--- a/cypress/integration/test_organizational_chart_desktop.js
+++ b/cypress/integration/test_organizational_chart_desktop.js
@@ -3,6 +3,8 @@ context('Organizational Chart', () => {
cy.login();
cy.visit('/app/website');
cy.awesomebar('Organizational Chart');
+ cy.wait(500);
+ cy.url().should('include', '/organizational-chart');
cy.window().its('frappe.csrf_token').then(csrf_token => {
return cy.request({
@@ -17,6 +19,7 @@ context('Organizational Chart', () => {
}).then(res => {
expect(res.status).eq(200);
cy.get('.frappe-control[data-fieldname=company] input').focus().as('input');
+
cy.get('@input')
.clear({ force: true })
.type('Test Org Chart{enter}', { force: true })
From 97226418474394e982750d82b522edd7ed124351 Mon Sep 17 00:00:00 2001
From: Rohit Waghchaure
Date: Mon, 16 Aug 2021 20:36:04 +0530
Subject: [PATCH 346/386] chore: Release Notes v13.9.0
---
erpnext/change_log/v13/v13_9_0.md | 46 +++++++++++++++++++++++++++++++
1 file changed, 46 insertions(+)
create mode 100644 erpnext/change_log/v13/v13_9_0.md
diff --git a/erpnext/change_log/v13/v13_9_0.md b/erpnext/change_log/v13/v13_9_0.md
new file mode 100644
index 0000000000..e52766673c
--- /dev/null
+++ b/erpnext/change_log/v13/v13_9_0.md
@@ -0,0 +1,46 @@
+# Version 13.9.0 Release Notes
+
+### Features & Enhancements
+- Organizational Chart ([#26261](https://github.com/frappe/erpnext/pull/26261))
+- Enable discount accounting ([#26579](https://github.com/frappe/erpnext/pull/26579))
+- Added multi-select fields in promotional scheme to create multiple pricing rules ([#25622](https://github.com/frappe/erpnext/pull/25622))
+- Over transfer allowance for material transfers ([#26814](https://github.com/frappe/erpnext/pull/26814))
+- Enhancements in Tax Withholding Category ([#26661](https://github.com/frappe/erpnext/pull/26661))
+
+### Fixes
+- Sales Return cancellation if linked with Payment Entry ([#26883](https://github.com/frappe/erpnext/pull/26883))
+- Production plan not fetching sales order of a variant ([#25845](https://github.com/frappe/erpnext/pull/25845))
+- Stock Analytics Report must consider warehouse during calculation ([#26908](https://github.com/frappe/erpnext/pull/26908))
+- Incorrect date difference calculation ([#26805](https://github.com/frappe/erpnext/pull/26805))
+- Tax calculation for Recurring additional salary ([#24206](https://github.com/frappe/erpnext/pull/24206))
+- Cannot cancel payment entry if linked with invoices ([#26703](https://github.com/frappe/erpnext/pull/26703))
+- Included company in link document type filters for contact ([#26576](https://github.com/frappe/erpnext/pull/26576))
+- Fetch Payment Terms from linked Sales/Purchase Order ([#26723](https://github.com/frappe/erpnext/pull/26723))
+- Let all System Managers be able to delete Company transactions ([#26819](https://github.com/frappe/erpnext/pull/26819))
+- Bank remittance report issue ([#26398](https://github.com/frappe/erpnext/pull/26398))
+- Faulty Gl Entry for Asset LCVs ([#26803](https://github.com/frappe/erpnext/pull/26803))
+- Clean Serial No input on Server Side ([#26878](https://github.com/frappe/erpnext/pull/26878))
+- Supplier invoice importer fix v13 ([#26633](https://github.com/frappe/erpnext/pull/26633))
+- POS payment modes displayed wrong total ([#26808](https://github.com/frappe/erpnext/pull/26808))
+- Fetching of item tax from hsn code ([#26736](https://github.com/frappe/erpnext/pull/26736))
+- Cannot cancel invoice if IRN cancelled on portal ([#26879](https://github.com/frappe/erpnext/pull/26879))
+- Validate python expressions ([#26856](https://github.com/frappe/erpnext/pull/26856))
+- POS Item Cart non-stop scroll issue ([#26693](https://github.com/frappe/erpnext/pull/26693))
+- Add mandatory depends on condition for export type field ([#26958](https://github.com/frappe/erpnext/pull/26958))
+- Cannot generate IRNs for standalone credit notes ([#26824](https://github.com/frappe/erpnext/pull/26824))
+- Added progress bar in Repost Item Valuation to check the status of reposting ([#26630](https://github.com/frappe/erpnext/pull/26630))
+- TDS calculation for first threshold breach for TDS category 194Q ([#26710](https://github.com/frappe/erpnext/pull/26710))
+- Student category mapping from the program enrollment tool ([#26739](https://github.com/frappe/erpnext/pull/26739))
+- Cost center & account validation in Sales/Purchase Taxes and Charges ([#26881](https://github.com/frappe/erpnext/pull/26881))
+- Reset weight_per_unit on replacing Item ([#26791](https://github.com/frappe/erpnext/pull/26791))
+- Do not fetch fully return issued purchase receipts ([#26825](https://github.com/frappe/erpnext/pull/26825))
+- Incorrect amount in work order required items table. ([#26585](https://github.com/frappe/erpnext/pull/26585))
+- Additional discount calculations in Invoices ([#26553](https://github.com/frappe/erpnext/pull/26553))
+- Refactored Asset Repair ([#26415](https://github.com/frappe/erpnext/pull/25798))
+- Exchange rate revaluation posting date and precision fixes ([#26650](https://github.com/frappe/erpnext/pull/26650))
+- POS Invoice consolidated Sales Invoice field set to no copy ([#26768](https://github.com/frappe/erpnext/pull/26768))
+- Consider grand total for threshold check ([#26683](https://github.com/frappe/erpnext/pull/26683))
+- Budget variance missing values ([#26966](https://github.com/frappe/erpnext/pull/26966))
+- GL Entries for exchange gain loss ([#26728](https://github.com/frappe/erpnext/pull/26728))
+- Add missing cess amount in GSTR-3B report ([#26544](https://github.com/frappe/erpnext/pull/26544))
+- GST Reports timeout issue ([#26575](https://github.com/frappe/erpnext/pull/26575))
\ No newline at end of file
From 03fdce5a1975602a295de2dcf76f8c6facc9fc6b Mon Sep 17 00:00:00 2001
From: Rohit Waghchaure
Date: Tue, 17 Aug 2021 10:25:49 +0550
Subject: [PATCH 347/386] bumped to version 13.9.0
---
erpnext/__init__.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/__init__.py b/erpnext/__init__.py
index c90e01cfbd..17d650568a 100644
--- a/erpnext/__init__.py
+++ b/erpnext/__init__.py
@@ -5,7 +5,7 @@ import frappe
from erpnext.hooks import regional_overrides
from frappe.utils import getdate
-__version__ = '13.8.0'
+__version__ = '13.9.0'
def get_default_company(user=None):
'''Get default company for user'''
From 8c851b7019db72fd5a5f835b985cd08bf10f723d Mon Sep 17 00:00:00 2001
From: Chillar Anand
Date: Tue, 17 Aug 2021 10:39:18 +0530
Subject: [PATCH 348/386] Merge pull request #26906 from ChillarAnand/label
fix: Changed label to "Inpatient Visit Charge" in appointment type
---
.../appointment_type_service_item.json | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/erpnext/healthcare/doctype/appointment_type_service_item/appointment_type_service_item.json b/erpnext/healthcare/doctype/appointment_type_service_item/appointment_type_service_item.json
index 5ff68cd682..ccae129ea0 100644
--- a/erpnext/healthcare/doctype/appointment_type_service_item/appointment_type_service_item.json
+++ b/erpnext/healthcare/doctype/appointment_type_service_item/appointment_type_service_item.json
@@ -48,13 +48,13 @@
"fieldname": "inpatient_visit_charge",
"fieldtype": "Currency",
"in_list_view": 1,
- "label": "Inpatient Visit Charge Item"
+ "label": "Inpatient Visit Charge"
}
],
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
- "modified": "2021-01-22 09:35:26.503443",
+ "modified": "2021-08-17 06:05:02.240812",
"modified_by": "Administrator",
"module": "Healthcare",
"name": "Appointment Type Service Item",
From b1bcb3bf13ac0c10f155e7f37670a42939a4c217 Mon Sep 17 00:00:00 2001
From: Deepesh Garg
Date: Tue, 17 Aug 2021 11:28:46 +0530
Subject: [PATCH 349/386] fix: Incorrect unallocated amount calculation in
payment entry
---
erpnext/accounts/doctype/payment_entry/payment_entry.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py
index 46904f7c57..831b270858 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.py
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py
@@ -529,7 +529,7 @@ class PaymentEntry(AccountsController):
if self.payment_type == "Receive" \
and self.base_total_allocated_amount < self.base_received_amount + total_deductions \
and self.total_allocated_amount < self.paid_amount + (total_deductions / self.source_exchange_rate):
- self.unallocated_amount = (self.received_amount + total_deductions -
+ self.unallocated_amount = (self.base_received_amount + total_deductions -
self.base_total_allocated_amount) / self.source_exchange_rate
self.unallocated_amount -= included_taxes
elif self.payment_type == "Pay" \
From fbb328b84a741e1d407a48c06d4abaa49e14f3aa Mon Sep 17 00:00:00 2001
From: Rohit Waghchaure
Date: Tue, 17 Aug 2021 13:07:03 +0530
Subject: [PATCH 350/386] chore: added missing fieldname
---
.../doctype/service_level_agreement/service_level_agreement.json | 1 +
1 file changed, 1 insertion(+)
diff --git a/erpnext/support/doctype/service_level_agreement/service_level_agreement.json b/erpnext/support/doctype/service_level_agreement/service_level_agreement.json
index b1273b704f..b67c7fceac 100644
--- a/erpnext/support/doctype/service_level_agreement/service_level_agreement.json
+++ b/erpnext/support/doctype/service_level_agreement/service_level_agreement.json
@@ -183,6 +183,7 @@
},
{
"label": "Pause SLA On",
+ "fieldname": "pause_sla_on",
"options": "Pause SLA On Status"
},
{
From d932cba38afc176e0e6384f9081c523d66c0320e Mon Sep 17 00:00:00 2001
From: Sagar Vora
Date: Tue, 17 Aug 2021 13:17:09 +0530
Subject: [PATCH 351/386] Merge pull request #26976 from
resilient-tech/fix-incorrect-modified
fix: Incorrect `modified` time in documents that inherit from `StatusUpdater`
---
erpnext/controllers/status_updater.py | 14 +++++++++-----
1 file changed, 9 insertions(+), 5 deletions(-)
diff --git a/erpnext/controllers/status_updater.py b/erpnext/controllers/status_updater.py
index 943f7aaeb1..b1f89b08d7 100644
--- a/erpnext/controllers/status_updater.py
+++ b/erpnext/controllers/status_updater.py
@@ -3,7 +3,7 @@
from __future__ import unicode_literals
import frappe
-from frappe.utils import flt, comma_or, nowdate, getdate
+from frappe.utils import flt, comma_or, nowdate, getdate, now
from frappe import _
from frappe.model.document import Document
@@ -336,10 +336,14 @@ class StatusUpdater(Document):
target.notify_update()
def _update_modified(self, args, update_modified):
- args['update_modified'] = ''
- if update_modified:
- args['update_modified'] = ', modified = now(), modified_by = {0}'\
- .format(frappe.db.escape(frappe.session.user))
+ if not update_modified:
+ args['update_modified'] = ''
+ return
+
+ args['update_modified'] = ', modified = {0}, modified_by = {1}'.format(
+ frappe.db.escape(now()),
+ frappe.db.escape(frappe.session.user)
+ )
def update_billing_status_for_zero_amount_refdoc(self, ref_dt):
ref_fieldname = frappe.scrub(ref_dt)
From 3c525e11360869048845e0f4f32cf4743a40871c Mon Sep 17 00:00:00 2001
From: Saqib
Date: Tue, 17 Aug 2021 14:22:47 +0530
Subject: [PATCH 352/386] fix(sla): 'doctype' is not defined (#26982)
---
.../doctype/service_level_agreement/service_level_agreement.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/support/doctype/service_level_agreement/service_level_agreement.py b/erpnext/support/doctype/service_level_agreement/service_level_agreement.py
index eb9fa12b66..083bde9a42 100644
--- a/erpnext/support/doctype/service_level_agreement/service_level_agreement.py
+++ b/erpnext/support/doctype/service_level_agreement/service_level_agreement.py
@@ -220,7 +220,7 @@ def get_active_service_level_agreement_for(doc):
return
filters = [
- ["Service Level Agreement", "document_type", "=", doctype],
+ ["Service Level Agreement", "document_type", "=", doc.get('doctype')],
["Service Level Agreement", "enabled", "=", 1]
]
From 8bbec42fa0c9271006f04cefacae5dbe4d109a44 Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Tue, 17 Aug 2021 15:14:13 +0530
Subject: [PATCH 353/386] fix: undo changes to patch (#26983)
* fix: undo changes to patch
* ci: ignore empty body / head
---
.github/helper/documentation.py | 6 +++---
erpnext/patches/v13_0/shopify_deprecation_warning.py | 4 ----
2 files changed, 3 insertions(+), 7 deletions(-)
diff --git a/.github/helper/documentation.py b/.github/helper/documentation.py
index b4a4ba1bbd..91983d3eae 100644
--- a/.github/helper/documentation.py
+++ b/.github/helper/documentation.py
@@ -32,9 +32,9 @@ if __name__ == "__main__":
if response.ok:
payload = response.json()
- title = payload.get("title", "").lower().strip()
- head_sha = payload.get("head", {}).get("sha")
- body = payload.get("body", "").lower()
+ title = (payload.get("title") or "").lower().strip()
+ head_sha = (payload.get("head") or {}).get("sha")
+ body = (payload.get("body") or "").lower()
if (title.startswith("feat")
and head_sha
diff --git a/erpnext/patches/v13_0/shopify_deprecation_warning.py b/erpnext/patches/v13_0/shopify_deprecation_warning.py
index 8b0f1935cf..6f199c87b6 100644
--- a/erpnext/patches/v13_0/shopify_deprecation_warning.py
+++ b/erpnext/patches/v13_0/shopify_deprecation_warning.py
@@ -4,10 +4,6 @@ import frappe
def execute():
- frappe.reload_doc("erpnext_integrations", "doctype", "shopify_settings")
- if not frappe.db.get_single_value("Shopify Settings", "enable_shopify"):
- return
-
click.secho(
"Shopify Integration is moved to a separate app and will be removed from ERPNext in version-14.\n"
"Please install the app to continue using the integration: https://github.com/frappe/ecommerce_integrations",
From a14d21883414cceb29e764b3af7748fb85d70fe6 Mon Sep 17 00:00:00 2001
From: Frappe PR Bot
Date: Tue, 17 Aug 2021 16:14:37 +0530
Subject: [PATCH 354/386] fix: typo (#26967) (#26984)
(cherry picked from commit ace8cf965d2aab3faa18aa704e0e796f707cc666)
Co-authored-by: Raffael Meyer <14891507+barredterra@users.noreply.github.com>
---
erpnext/accounts/doctype/sales_invoice/sales_invoice.py | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index 5424ef3c66..92f558fb33 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -1463,7 +1463,7 @@ class SalesInvoice(SellingController):
discounting_status = None
if self.is_discounted:
- discountng_status = get_discounting_status(self.name)
+ discounting_status = get_discounting_status(self.name)
if not status:
if self.docstatus == 2:
@@ -1471,11 +1471,11 @@ class SalesInvoice(SellingController):
elif self.docstatus == 1:
if self.is_internal_transfer():
self.status = 'Internal Transfer'
- elif outstanding_amount > 0 and due_date < nowdate and self.is_discounted and discountng_status=='Disbursed':
+ elif outstanding_amount > 0 and due_date < nowdate and self.is_discounted and discounting_status=='Disbursed':
self.status = "Overdue and Discounted"
elif outstanding_amount > 0 and due_date < nowdate:
self.status = "Overdue"
- elif outstanding_amount > 0 and due_date >= nowdate and self.is_discounted and discountng_status=='Disbursed':
+ elif outstanding_amount > 0 and due_date >= nowdate and self.is_discounted and discounting_status=='Disbursed':
self.status = "Unpaid and Discounted"
elif outstanding_amount > 0 and due_date >= nowdate:
self.status = "Unpaid"
From fd739749bae7f3f1e544270451ccee24b5dd38f8 Mon Sep 17 00:00:00 2001
From: Deepesh Garg
Date: Tue, 17 Aug 2021 16:38:25 +0530
Subject: [PATCH 355/386] test: Add test case for payment entry
---
.../payment_entry/test_payment_entry.py | 28 +++++++++++++++++++
1 file changed, 28 insertions(+)
diff --git a/erpnext/accounts/doctype/payment_entry/test_payment_entry.py b/erpnext/accounts/doctype/payment_entry/test_payment_entry.py
index d1302f5ae7..801dadc7f1 100644
--- a/erpnext/accounts/doctype/payment_entry/test_payment_entry.py
+++ b/erpnext/accounts/doctype/payment_entry/test_payment_entry.py
@@ -295,6 +295,34 @@ class TestPaymentEntry(unittest.TestCase):
outstanding_amount = flt(frappe.db.get_value("Sales Invoice", si.name, "outstanding_amount"))
self.assertEqual(outstanding_amount, 80)
+ def test_payment_entry_against_si_usd_to_usd_with_deduction_in_base_currency (self):
+ si = create_sales_invoice(customer="_Test Customer USD", debit_to="_Test Receivable USD - _TC",
+ currency="USD", conversion_rate=50, do_not_save=1)
+
+ si.plc_conversion_rate = 50
+ si.save()
+ si.submit()
+
+ pe = get_payment_entry("Sales Invoice", si.name, party_amount=20,
+ bank_account="_Test Bank USD - _TC", bank_amount=900)
+
+ pe.source_exchange_rate = 45.263
+ pe.target_exchange_rate = 45.263
+ pe.reference_no = "1"
+ pe.reference_date = "2016-01-01"
+
+
+ pe.append("deductions", {
+ "account": "_Test Exchange Gain/Loss - _TC",
+ "cost_center": "_Test Cost Center - _TC",
+ "amount": 94.80
+ })
+
+ pe.save()
+
+ self.assertEqual(flt(pe.difference_amount, 2), 0.0)
+ self.assertEqual(flt(pe.unallocated_amount, 2), 0.0)
+
def test_payment_entry_retrieves_last_exchange_rate(self):
from erpnext.setup.doctype.currency_exchange.test_currency_exchange import test_records, save_new_records
From a2966db1e55a1a5c44fe22a6818b6c3f504e3fc7 Mon Sep 17 00:00:00 2001
From: Mohammed Redah
Date: Tue, 17 Aug 2021 16:15:55 +0300
Subject: [PATCH 356/386] fix: change print_format_type from Server to Jinja
(#26374)
---
.../bank_and_cash_payment_voucher.json | 2 +-
.../cheque_printing_format/cheque_printing_format.json | 2 +-
erpnext/accounts/print_format/credit_note/credit_note.json | 2 +-
.../print_format/gst_purchase_invoice/gst_purchase_invoice.json | 2 +-
.../journal_auditing_voucher/journal_auditing_voucher.json | 2 +-
.../payment_receipt_voucher/payment_receipt_voucher.json | 2 +-
.../purchase_auditing_voucher/purchase_auditing_voucher.json | 2 +-
.../sales_auditing_voucher/sales_auditing_voucher.json | 2 +-
.../print_format/drop_shipping_format/drop_shipping_format.json | 2 +-
.../print_format/encounter_print/encounter_print.json | 2 +-
.../print_format/sample_id_print/sample_id_print.json | 2 +-
erpnext/hr/print_format/job_offer/job_offer.json | 2 +-
.../salary_slip_based_on_timesheet.json | 2 +-
.../print_format/salary_slip_standard/salary_slip_standard.json | 2 +-
.../print_format/detailed_tax_invoice/detailed_tax_invoice.json | 2 +-
.../regional/print_format/gst_tax_invoice/gst_tax_invoice.json | 2 +-
.../simplified_tax_invoice/simplified_tax_invoice.json | 2 +-
erpnext/regional/print_format/tax_invoice/tax_invoice.json | 2 +-
18 files changed, 18 insertions(+), 18 deletions(-)
diff --git a/erpnext/accounts/print_format/bank_and_cash_payment_voucher/bank_and_cash_payment_voucher.json b/erpnext/accounts/print_format/bank_and_cash_payment_voucher/bank_and_cash_payment_voucher.json
index e3afaec2ad..9e126bade7 100644
--- a/erpnext/accounts/print_format/bank_and_cash_payment_voucher/bank_and_cash_payment_voucher.json
+++ b/erpnext/accounts/print_format/bank_and_cash_payment_voucher/bank_and_cash_payment_voucher.json
@@ -16,7 +16,7 @@
"name": "Bank and Cash Payment Voucher",
"owner": "Administrator",
"print_format_builder": 0,
- "print_format_type": "Server",
+ "print_format_type": "Jinja",
"show_section_headings": 0,
"standard": "Yes"
}
\ No newline at end of file
diff --git a/erpnext/accounts/print_format/cheque_printing_format/cheque_printing_format.json b/erpnext/accounts/print_format/cheque_printing_format/cheque_printing_format.json
index 8c9c26691e..08b8ef8890 100755
--- a/erpnext/accounts/print_format/cheque_printing_format/cheque_printing_format.json
+++ b/erpnext/accounts/print_format/cheque_printing_format/cheque_printing_format.json
@@ -10,6 +10,6 @@
"modified_by": "Administrator",
"name": "Cheque Printing Format",
"owner": "Administrator",
- "print_format_type": "Server",
+ "print_format_type": "Jinja",
"standard": "Yes"
}
\ No newline at end of file
diff --git a/erpnext/accounts/print_format/credit_note/credit_note.json b/erpnext/accounts/print_format/credit_note/credit_note.json
index c5a11cf395..d12b872dd7 100644
--- a/erpnext/accounts/print_format/credit_note/credit_note.json
+++ b/erpnext/accounts/print_format/credit_note/credit_note.json
@@ -17,7 +17,7 @@
"owner": "Administrator",
"parentfield": "__print_formats",
"print_format_builder": 0,
- "print_format_type": "Server",
+ "print_format_type": "Jinja",
"show_section_headings": 0,
"standard": "Yes"
}
\ No newline at end of file
diff --git a/erpnext/accounts/print_format/gst_purchase_invoice/gst_purchase_invoice.json b/erpnext/accounts/print_format/gst_purchase_invoice/gst_purchase_invoice.json
index 6d7c3d31ae..1467f27e66 100644
--- a/erpnext/accounts/print_format/gst_purchase_invoice/gst_purchase_invoice.json
+++ b/erpnext/accounts/print_format/gst_purchase_invoice/gst_purchase_invoice.json
@@ -16,7 +16,7 @@
"name": "GST Purchase Invoice",
"owner": "Administrator",
"print_format_builder": 1,
- "print_format_type": "Server",
+ "print_format_type": "Jinja",
"show_section_headings": 0,
"standard": "Yes"
}
\ No newline at end of file
diff --git a/erpnext/accounts/print_format/journal_auditing_voucher/journal_auditing_voucher.json b/erpnext/accounts/print_format/journal_auditing_voucher/journal_auditing_voucher.json
index 927e818e01..e45295d9fe 100644
--- a/erpnext/accounts/print_format/journal_auditing_voucher/journal_auditing_voucher.json
+++ b/erpnext/accounts/print_format/journal_auditing_voucher/journal_auditing_voucher.json
@@ -16,7 +16,7 @@
"name": "Journal Auditing Voucher",
"owner": "Administrator",
"print_format_builder": 0,
- "print_format_type": "Server",
+ "print_format_type": "Jinja",
"show_section_headings": 0,
"standard": "Yes"
}
\ No newline at end of file
diff --git a/erpnext/accounts/print_format/payment_receipt_voucher/payment_receipt_voucher.json b/erpnext/accounts/print_format/payment_receipt_voucher/payment_receipt_voucher.json
index f1de448bb9..c52eeb2dfb 100755
--- a/erpnext/accounts/print_format/payment_receipt_voucher/payment_receipt_voucher.json
+++ b/erpnext/accounts/print_format/payment_receipt_voucher/payment_receipt_voucher.json
@@ -12,6 +12,6 @@
"name": "Payment Receipt Voucher",
"owner": "Administrator",
"print_format_builder": 0,
- "print_format_type": "Server",
+ "print_format_type": "Jinja",
"standard": "Yes"
}
\ No newline at end of file
diff --git a/erpnext/accounts/print_format/purchase_auditing_voucher/purchase_auditing_voucher.json b/erpnext/accounts/print_format/purchase_auditing_voucher/purchase_auditing_voucher.json
index 73779d49aa..3398117822 100644
--- a/erpnext/accounts/print_format/purchase_auditing_voucher/purchase_auditing_voucher.json
+++ b/erpnext/accounts/print_format/purchase_auditing_voucher/purchase_auditing_voucher.json
@@ -16,7 +16,7 @@
"name": "Purchase Auditing Voucher",
"owner": "Administrator",
"print_format_builder": 0,
- "print_format_type": "Server",
+ "print_format_type": "Jinja",
"show_section_headings": 0,
"standard": "Yes"
}
\ No newline at end of file
diff --git a/erpnext/accounts/print_format/sales_auditing_voucher/sales_auditing_voucher.json b/erpnext/accounts/print_format/sales_auditing_voucher/sales_auditing_voucher.json
index 0544e0bc9e..289e184848 100644
--- a/erpnext/accounts/print_format/sales_auditing_voucher/sales_auditing_voucher.json
+++ b/erpnext/accounts/print_format/sales_auditing_voucher/sales_auditing_voucher.json
@@ -16,7 +16,7 @@
"name": "Sales Auditing Voucher",
"owner": "Administrator",
"print_format_builder": 0,
- "print_format_type": "Server",
+ "print_format_type": "Jinja",
"show_section_headings": 0,
"standard": "Yes"
}
\ No newline at end of file
diff --git a/erpnext/buying/print_format/drop_shipping_format/drop_shipping_format.json b/erpnext/buying/print_format/drop_shipping_format/drop_shipping_format.json
index 0c7cad6e94..2e2a04826a 100644
--- a/erpnext/buying/print_format/drop_shipping_format/drop_shipping_format.json
+++ b/erpnext/buying/print_format/drop_shipping_format/drop_shipping_format.json
@@ -13,6 +13,6 @@
"name": "Drop Shipping Format",
"owner": "Administrator",
"print_format_builder": 0,
- "print_format_type": "Server",
+ "print_format_type": "Jinja",
"standard": "Yes"
}
\ No newline at end of file
diff --git a/erpnext/healthcare/print_format/encounter_print/encounter_print.json b/erpnext/healthcare/print_format/encounter_print/encounter_print.json
index ec1e0f202a..3c90adb0a1 100644
--- a/erpnext/healthcare/print_format/encounter_print/encounter_print.json
+++ b/erpnext/healthcare/print_format/encounter_print/encounter_print.json
@@ -16,7 +16,7 @@
"name": "Encounter Print",
"owner": "Administrator",
"print_format_builder": 0,
- "print_format_type": "Server",
+ "print_format_type": "Jinja",
"show_section_headings": 0,
"standard": "Yes"
}
\ No newline at end of file
diff --git a/erpnext/healthcare/print_format/sample_id_print/sample_id_print.json b/erpnext/healthcare/print_format/sample_id_print/sample_id_print.json
index e99ce708f4..4819e6d57a 100644
--- a/erpnext/healthcare/print_format/sample_id_print/sample_id_print.json
+++ b/erpnext/healthcare/print_format/sample_id_print/sample_id_print.json
@@ -16,7 +16,7 @@
"name": "Sample ID Print",
"owner": "Administrator",
"print_format_builder": 0,
- "print_format_type": "Server",
+ "print_format_type": "Jinja",
"show_section_headings": 0,
"standard": "Yes"
}
diff --git a/erpnext/hr/print_format/job_offer/job_offer.json b/erpnext/hr/print_format/job_offer/job_offer.json
index 3fc2bcf7d2..0a922306b4 100644
--- a/erpnext/hr/print_format/job_offer/job_offer.json
+++ b/erpnext/hr/print_format/job_offer/job_offer.json
@@ -15,7 +15,7 @@
"name": "Job Offer",
"owner": "Administrator",
"print_format_builder": 0,
- "print_format_type": "Server",
+ "print_format_type": "Jinja",
"show_section_headings": 0,
"standard": "Yes"
}
\ No newline at end of file
diff --git a/erpnext/payroll/print_format/salary_slip_based_on_timesheet/salary_slip_based_on_timesheet.json b/erpnext/payroll/print_format/salary_slip_based_on_timesheet/salary_slip_based_on_timesheet.json
index ceaf4a6ac7..d5fee6b5b8 100644
--- a/erpnext/payroll/print_format/salary_slip_based_on_timesheet/salary_slip_based_on_timesheet.json
+++ b/erpnext/payroll/print_format/salary_slip_based_on_timesheet/salary_slip_based_on_timesheet.json
@@ -13,6 +13,6 @@
"name": "Salary Slip based on Timesheet",
"owner": "Administrator",
"print_format_builder": 1,
- "print_format_type": "Server",
+ "print_format_type": "Jinja",
"standard": "Yes"
}
\ No newline at end of file
diff --git a/erpnext/payroll/print_format/salary_slip_standard/salary_slip_standard.json b/erpnext/payroll/print_format/salary_slip_standard/salary_slip_standard.json
index b01239fe02..98a4435a50 100644
--- a/erpnext/payroll/print_format/salary_slip_standard/salary_slip_standard.json
+++ b/erpnext/payroll/print_format/salary_slip_standard/salary_slip_standard.json
@@ -16,7 +16,7 @@
"name": "Salary Slip Standard",
"owner": "Administrator",
"print_format_builder": 1,
- "print_format_type": "Server",
+ "print_format_type": "Jinja",
"show_section_headings": 0,
"standard": "Yes"
}
\ No newline at end of file
diff --git a/erpnext/regional/print_format/detailed_tax_invoice/detailed_tax_invoice.json b/erpnext/regional/print_format/detailed_tax_invoice/detailed_tax_invoice.json
index ab56c6bc3c..f67e2450a2 100644
--- a/erpnext/regional/print_format/detailed_tax_invoice/detailed_tax_invoice.json
+++ b/erpnext/regional/print_format/detailed_tax_invoice/detailed_tax_invoice.json
@@ -16,7 +16,7 @@
"name": "Detailed Tax Invoice",
"owner": "Administrator",
"print_format_builder": 1,
- "print_format_type": "Server",
+ "print_format_type": "Jinja",
"show_section_headings": 0,
"standard": "Yes"
}
\ No newline at end of file
diff --git a/erpnext/regional/print_format/gst_tax_invoice/gst_tax_invoice.json b/erpnext/regional/print_format/gst_tax_invoice/gst_tax_invoice.json
index 7d8e675e9f..b23206b0bd 100644
--- a/erpnext/regional/print_format/gst_tax_invoice/gst_tax_invoice.json
+++ b/erpnext/regional/print_format/gst_tax_invoice/gst_tax_invoice.json
@@ -16,7 +16,7 @@
"name": "GST Tax Invoice",
"owner": "Administrator",
"print_format_builder": 1,
- "print_format_type": "Server",
+ "print_format_type": "Jinja",
"show_section_headings": 0,
"standard": "Yes"
}
\ No newline at end of file
diff --git a/erpnext/regional/print_format/simplified_tax_invoice/simplified_tax_invoice.json b/erpnext/regional/print_format/simplified_tax_invoice/simplified_tax_invoice.json
index b324f6ee68..aed2e89ed7 100644
--- a/erpnext/regional/print_format/simplified_tax_invoice/simplified_tax_invoice.json
+++ b/erpnext/regional/print_format/simplified_tax_invoice/simplified_tax_invoice.json
@@ -16,7 +16,7 @@
"name": "Simplified Tax Invoice",
"owner": "Administrator",
"print_format_builder": 1,
- "print_format_type": "Server",
+ "print_format_type": "Jinja",
"show_section_headings": 0,
"standard": "Yes"
}
\ No newline at end of file
diff --git a/erpnext/regional/print_format/tax_invoice/tax_invoice.json b/erpnext/regional/print_format/tax_invoice/tax_invoice.json
index 74db06727b..7479891595 100644
--- a/erpnext/regional/print_format/tax_invoice/tax_invoice.json
+++ b/erpnext/regional/print_format/tax_invoice/tax_invoice.json
@@ -16,7 +16,7 @@
"name": "Tax Invoice",
"owner": "Administrator",
"print_format_builder": 1,
- "print_format_type": "Server",
+ "print_format_type": "Jinja",
"show_section_headings": 0,
"standard": "Yes"
}
\ No newline at end of file
From 5fec44446eed481021f5ec9c187b6558e790501e Mon Sep 17 00:00:00 2001
From: Afshan <33727827+AfshanKhan@users.noreply.github.com>
Date: Tue, 17 Aug 2021 20:06:19 +0530
Subject: [PATCH 357/386] fix: set account for change amount even if pos
profile not found (#26986)
---
erpnext/accounts/doctype/sales_invoice/sales_invoice.py | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index 92f558fb33..5fa622856b 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -478,6 +478,9 @@ class SalesInvoice(SellingController):
if cint(self.is_pos) != 1:
return
+ if not self.account_for_change_amount:
+ self.account_for_change_amount = frappe.get_cached_value('Company', self.company, 'default_cash_account')
+
from erpnext.stock.get_item_details import get_pos_profile_item_details, get_pos_profile
if not self.pos_profile:
pos_profile = get_pos_profile(self.company) or {}
@@ -492,9 +495,6 @@ class SalesInvoice(SellingController):
if not self.get('payments') and not for_validate:
update_multi_mode_option(self, pos)
- if not self.account_for_change_amount:
- self.account_for_change_amount = frappe.get_cached_value('Company', self.company, 'default_cash_account')
-
if pos:
if not for_validate:
self.tax_category = pos.get("tax_category")
From e0862de863f46e9641620eecbc35a935ee90fe43 Mon Sep 17 00:00:00 2001
From: Rohit Waghchaure
Date: Wed, 18 Aug 2021 10:27:58 +0530
Subject: [PATCH 358/386] fix: sales invoice not loading issue
---
erpnext/accounts/doctype/sales_invoice/sales_invoice.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
index 7a273c7504..8d65101b3b 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
@@ -447,10 +447,10 @@ erpnext.accounts.SalesInvoiceController = class SalesInvoiceController extends e
this.frm.refresh_field("outstanding_amount");
this.frm.refresh_field("paid_amount");
this.frm.refresh_field("base_paid_amount");
- },
+ }
currency() {
- this._super();
+ super.currency();
$.each(cur_frm.doc.timesheets, function(i, d) {
let row = frappe.get_doc(d.doctype, d.name)
set_timesheet_detail_rate(row.doctype, row.name, cur_frm.doc.currency, row.timesheet_detail)
From 15df0ad6a0ede96008b3e40db0f823dff0a35570 Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Wed, 18 Aug 2021 11:23:44 +0530
Subject: [PATCH 359/386] fix: undefined variable due to inconsistent porting
of commits (#26994)
---
erpnext/payroll/doctype/salary_slip/salary_slip.py | 1 -
1 file changed, 1 deletion(-)
diff --git a/erpnext/payroll/doctype/salary_slip/salary_slip.py b/erpnext/payroll/doctype/salary_slip/salary_slip.py
index bd982cf488..5f5fdd5c83 100644
--- a/erpnext/payroll/doctype/salary_slip/salary_slip.py
+++ b/erpnext/payroll/doctype/salary_slip/salary_slip.py
@@ -680,7 +680,6 @@ class SalarySlip(TransactionBase):
component_row.set(attr, component_data.get(attr))
if additional_salary:
- component_row.is_recurring_additional_salary = is_recurring
if additional_salary.overwrite:
component_row.additional_amount = flt(flt(amount) - flt(component_row.get("default_amount", 0)),
component_row.precision("additional_amount"))
From fbc163cea66b52494595435200c43ea581fe9bd2 Mon Sep 17 00:00:00 2001
From: Saqib
Date: Wed, 18 Aug 2021 11:53:26 +0530
Subject: [PATCH 360/386] feat: dynamic conditions for applying SLA (#26662)
---
.../service_level_agreement.json | 7 +----
.../service_level_agreement.py | 25 +++++++++---------
.../test_service_level_agreement.py | 26 +++++++++++++++++--
3 files changed, 38 insertions(+), 20 deletions(-)
diff --git a/erpnext/support/doctype/service_level_agreement/service_level_agreement.json b/erpnext/support/doctype/service_level_agreement/service_level_agreement.json
index b67c7fceac..b649b8768b 100644
--- a/erpnext/support/doctype/service_level_agreement/service_level_agreement.json
+++ b/erpnext/support/doctype/service_level_agreement/service_level_agreement.json
@@ -181,11 +181,6 @@
"fieldtype": "Check",
"label": "Apply SLA for Resolution Time"
},
- {
- "label": "Pause SLA On",
- "fieldname": "pause_sla_on",
- "options": "Pause SLA On Status"
- },
{
"fieldname": "filters_section",
"fieldtype": "Section Break",
@@ -208,7 +203,7 @@
}
],
"links": [],
- "modified": "2021-07-09 12:28:46.283334",
+ "modified": "2021-07-27 11:16:45.596579",
"modified_by": "Administrator",
"module": "Support",
"name": "Service Level Agreement",
diff --git a/erpnext/support/doctype/service_level_agreement/service_level_agreement.py b/erpnext/support/doctype/service_level_agreement/service_level_agreement.py
index 083bde9a42..d9cffc231f 100644
--- a/erpnext/support/doctype/service_level_agreement/service_level_agreement.py
+++ b/erpnext/support/doctype/service_level_agreement/service_level_agreement.py
@@ -11,6 +11,7 @@ from frappe.core.utils import get_parent_doc
from frappe.utils import time_diff_in_seconds, getdate, get_weekdays, add_to_date, get_time, get_datetime, \
get_time_zone, to_timedelta, get_datetime_str, get_link_to_form, cint, nowdate
from datetime import datetime
+from frappe.utils.safe_exec import get_safe_globals
from erpnext.support.doctype.issue.issue import get_holidays
from frappe.utils.safe_exec import get_safe_globals
@@ -100,7 +101,7 @@ class ServiceLevelAgreement(Document):
frappe.bold(self.document_type)))
def validate_condition(self):
- temp_doc = frappe.new_doc('Issue')
+ temp_doc = frappe.new_doc(self.document_type)
if self.condition:
try:
frappe.safe_eval(self.condition, None, get_context(temp_doc))
@@ -227,25 +228,26 @@ def get_active_service_level_agreement_for(doc):
if doc.get('priority'):
filters.append(["Service Level Priority", "priority", "=", doc.get('priority')])
- customer = doc.get('customer')
- or_filters = [
- ["Service Level Agreement", "entity", "in", [customer, get_customer_group(customer), get_customer_territory(customer)]]
- ]
-
- service_level_agreement = doc.get('service_level_agreement')
- if service_level_agreement:
+ or_filters = []
+ if doc.get('service_level_agreement'):
or_filters = [
["Service Level Agreement", "name", "=", doc.get('service_level_agreement')],
]
+ customer = doc.get('customer')
+ if customer:
+ or_filters.append(
+ ["Service Level Agreement", "entity", "in", [customer, get_customer_group(customer), get_customer_territory(customer)]]
+ )
+
default_sla_filter = filters + [["Service Level Agreement", "default_service_level_agreement", "=", 1]]
default_sla = frappe.get_all("Service Level Agreement", filters=default_sla_filter,
- fields=["name", "default_priority", "condition"])
+ fields=["name", "default_priority", "apply_sla_for_resolution", "condition"])
filters += [["Service Level Agreement", "default_service_level_agreement", "=", 0]]
agreements = frappe.get_all("Service Level Agreement", filters=filters, or_filters=or_filters,
- fields=["name", "default_priority", "condition"])
-
+ fields=["name", "default_priority", "apply_sla_for_resolution", "condition"])
+
# check if the current document on which SLA is to be applied fulfills all the conditions
filtered_agreements = []
for agreement in agreements:
@@ -261,7 +263,6 @@ def get_active_service_level_agreement_for(doc):
def get_context(doc):
return {"doc": doc.as_dict(), "nowdate": nowdate, "frappe": frappe._dict(utils=get_safe_globals().get("frappe").get("utils"))}
-
def get_customer_group(customer):
return frappe.db.get_value("Customer", customer, "customer_group") if customer else None
diff --git a/erpnext/support/doctype/service_level_agreement/test_service_level_agreement.py b/erpnext/support/doctype/service_level_agreement/test_service_level_agreement.py
index 7bc97d6022..1a5ff27d2a 100644
--- a/erpnext/support/doctype/service_level_agreement/test_service_level_agreement.py
+++ b/erpnext/support/doctype/service_level_agreement/test_service_level_agreement.py
@@ -253,6 +253,26 @@ class TestServiceLevelAgreement(unittest.TestCase):
lead.reload()
self.assertEqual(lead.response_by_variance, 1800.0)
+ def test_service_level_agreement_filters(self):
+ doctype = "Lead"
+ lead_sla = create_service_level_agreement(
+ default_service_level_agreement=0,
+ doctype=doctype,
+ holiday_list="__Test Holiday List",
+ entity_type=None, entity=None,
+ condition='doc.source == "Test Source"',
+ response_time=14400,
+ sla_fulfilled_on=[{"status": "Replied"}],
+ apply_sla_for_resolution=0
+ )
+ creation = datetime.datetime(2019, 3, 4, 12, 0)
+ lead = make_lead(creation=creation, index=4)
+ self.assertFalse(lead.service_level_agreement)
+
+ lead.source = "Test Source"
+ lead.save()
+ self.assertEqual(lead.service_level_agreement, lead_sla.name)
+
def tearDown(self):
for d in frappe.get_all("Service Level Agreement"):
frappe.delete_doc("Service Level Agreement", d.name, force=1)
@@ -268,7 +288,7 @@ def get_service_level_agreement(default_service_level_agreement=None, entity_typ
return service_level_agreement
def create_service_level_agreement(default_service_level_agreement, holiday_list, response_time, entity_type,
- entity, resolution_time=0, doctype="Issue", sla_fulfilled_on=[], pause_sla_on=[], apply_sla_for_resolution=1):
+ entity, resolution_time=0, doctype="Issue", condition="", sla_fulfilled_on=[], pause_sla_on=[], apply_sla_for_resolution=1):
make_holiday_list()
make_priorities()
@@ -287,6 +307,7 @@ def create_service_level_agreement(default_service_level_agreement, holiday_list
"document_type": doctype,
"service_level": "__Test {} SLA".format(entity_type if entity_type else "Default"),
"default_service_level_agreement": default_service_level_agreement,
+ "condition": condition,
"default_priority": "Medium",
"holiday_list": holiday_list,
"entity_type": entity_type,
@@ -488,5 +509,6 @@ def make_lead(creation=None, index=0):
"lead_name": "_Test Lead {0}".format(index),
"status": "Open",
"creation": creation,
- "service_level_agreement_creation": creation
+ "service_level_agreement_creation": creation,
+ "priority": "Medium"
}).insert(ignore_permissions=True)
\ No newline at end of file
From cab49254fcb2ead50486851e93e8fa57ec058c3d Mon Sep 17 00:00:00 2001
From: Saqib
Date: Wed, 18 Aug 2021 14:53:32 +0530
Subject: [PATCH 361/386] fix: failing tests in issue doctype (#26998)
---
erpnext/support/doctype/issue/test_issue.py | 4 ++++
.../service_level_agreement/service_level_agreement.py | 7 +++----
2 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/erpnext/support/doctype/issue/test_issue.py b/erpnext/support/doctype/issue/test_issue.py
index 84f8c398be..739324f562 100644
--- a/erpnext/support/doctype/issue/test_issue.py
+++ b/erpnext/support/doctype/issue/test_issue.py
@@ -13,6 +13,10 @@ from datetime import timedelta
class TestSetUp(unittest.TestCase):
def setUp(self):
frappe.db.sql("delete from `tabService Level Agreement`")
+ frappe.db.sql("delete from `tabService Level Priority`")
+ frappe.db.sql("delete from `tabSLA Fulfilled On Status`")
+ frappe.db.sql("delete from `tabPause SLA On Status`")
+ frappe.db.sql("delete from `tabService Day`")
frappe.db.set_value("Support Settings", None, "track_service_level_agreement", 1)
create_service_level_agreements_for_issues()
diff --git a/erpnext/support/doctype/service_level_agreement/service_level_agreement.py b/erpnext/support/doctype/service_level_agreement/service_level_agreement.py
index d9cffc231f..472e96c059 100644
--- a/erpnext/support/doctype/service_level_agreement/service_level_agreement.py
+++ b/erpnext/support/doctype/service_level_agreement/service_level_agreement.py
@@ -235,10 +235,9 @@ def get_active_service_level_agreement_for(doc):
]
customer = doc.get('customer')
- if customer:
- or_filters.append(
- ["Service Level Agreement", "entity", "in", [customer, get_customer_group(customer), get_customer_territory(customer)]]
- )
+ or_filters.append(
+ ["Service Level Agreement", "entity", "in", [customer, get_customer_group(customer), get_customer_territory(customer)]]
+ )
default_sla_filter = filters + [["Service Level Agreement", "default_service_level_agreement", "=", 1]]
default_sla = frappe.get_all("Service Level Agreement", filters=default_sla_filter,
From 112fc888f1a2ec52d8c736669111fd62e6808109 Mon Sep 17 00:00:00 2001
From: Marica
Date: Wed, 18 Aug 2021 15:29:48 +0530
Subject: [PATCH 362/386] fix: Return Qty in PR/DN for legacy data (#27001)
---
.../patches/v13_0/update_returned_qty_in_pr_dn.py | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/erpnext/patches/v13_0/update_returned_qty_in_pr_dn.py b/erpnext/patches/v13_0/update_returned_qty_in_pr_dn.py
index 7f42cd92e3..409f4da859 100644
--- a/erpnext/patches/v13_0/update_returned_qty_in_pr_dn.py
+++ b/erpnext/patches/v13_0/update_returned_qty_in_pr_dn.py
@@ -1,8 +1,7 @@
-# Copyright (c) 2019, Frappe and Contributors
+# Copyright (c) 2021, Frappe and Contributors
# License: GNU General Public License v3. See license.txt
-
-from __future__ import unicode_literals
import frappe
+from erpnext.controllers.status_updater import OverAllowanceError
def execute():
frappe.reload_doc('stock', 'doctype', 'purchase_receipt')
@@ -14,9 +13,15 @@ def execute():
for return_doc in frappe.get_all(doctype, filters={'is_return' : 1, 'docstatus' : 1}):
# Update original receipt/delivery document from return
return_doc = frappe.get_cached_doc(doctype, return_doc.name)
- return_doc.update_prevdoc_status()
+ try:
+ return_doc.update_prevdoc_status()
+ except OverAllowanceError:
+ frappe.db.rollback()
+ continue
+
return_against = frappe.get_doc(doctype, return_doc.return_against)
return_against.update_billing_status()
+ frappe.db.commit()
# Set received qty in stock uom in PR, as returned qty is checked against it
frappe.db.sql(""" update `tabPurchase Receipt Item`
From 333e44eb471346bb56a5133e4677b889af545d10 Mon Sep 17 00:00:00 2001
From: Subin Tom <36098155+nemesis189@users.noreply.github.com>
Date: Wed, 18 Aug 2021 16:17:54 +0530
Subject: [PATCH 363/386] fix: Dimension filter query fix to avoid including
disabled dimensions (#26988)
* reverting ot v12.7.1
* fix: Dimension filter query fix to not display disabled dimensions
Co-authored-by: Subin Tom
Co-authored-by: Afshan <33727827+AfshanKhan@users.noreply.github.com>
---
erpnext/controllers/queries.py | 3 +++
1 file changed, 3 insertions(+)
diff --git a/erpnext/controllers/queries.py b/erpnext/controllers/queries.py
index 21c052a391..4b4c8befa5 100644
--- a/erpnext/controllers/queries.py
+++ b/erpnext/controllers/queries.py
@@ -526,6 +526,9 @@ def get_filtered_dimensions(doctype, txt, searchfield, start, page_len, filters)
if meta.is_tree:
query_filters.append(['is_group', '=', 0])
+ if meta.has_field('disabled'):
+ query_filters.append(['disabled', '!=', 1])
+
if meta.has_field('company'):
query_filters.append(['company', '=', filters.get('company')])
From dc7280eef08cec4ce67cfe54b23d65d8bd96de2d Mon Sep 17 00:00:00 2001
From: Afshan <33727827+AfshanKhan@users.noreply.github.com>
Date: Wed, 18 Aug 2021 17:44:40 +0530
Subject: [PATCH 364/386] fix: filtering of items in Sales and Purchase Orders
(#26936)
* fix: filtering of items in Sales and Purchase Orders
* fix: slider
* fix: slider
---
erpnext/public/js/utils.js | 18 +++++++++++++++++-
1 file changed, 17 insertions(+), 1 deletion(-)
diff --git a/erpnext/public/js/utils.js b/erpnext/public/js/utils.js
index db7c034596..f1b9235fe3 100755
--- a/erpnext/public/js/utils.js
+++ b/erpnext/public/js/utils.js
@@ -465,7 +465,23 @@ erpnext.utils.update_child_items = function(opts) {
in_list_view: 1,
read_only: 0,
disabled: 0,
- label: __('Item Code')
+ label: __('Item Code'),
+ get_query: function() {
+ let filters;
+ if (frm.doc.doctype == 'Sales Order') {
+ filters = {"is_sales_item": 1};
+ } else if (frm.doc.doctype == 'Purchase Order') {
+ if (frm.doc.is_subcontracted == "Yes") {
+ filters = {"is_sub_contracted_item": 1};
+ } else {
+ filters = {"is_purchase_item": 1};
+ }
+ }
+ return {
+ query: "erpnext.controllers.queries.item_query",
+ filters: filters
+ };
+ }
}, {
fieldtype:'Link',
fieldname:'uom',
From ef792971f397869e2ae931c995fb8e239845e7e5 Mon Sep 17 00:00:00 2001
From: Subin Tom <36098155+nemesis189@users.noreply.github.com>
Date: Wed, 18 Aug 2021 18:20:04 +0530
Subject: [PATCH 365/386] fix: Add ignore user perms to set_target_warehouse
field in sales invoice (#26987)
* reverting ot v12.7.1
* fix: Ignore user permissions for set_target_warehouse in SI
Co-authored-by: Subin Tom
Co-authored-by: Afshan <33727827+AfshanKhan@users.noreply.github.com>
---
.../doctype/sales_invoice/sales_invoice.json | 725 +++++-------------
1 file changed, 180 insertions(+), 545 deletions(-)
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
index b2be8608db..7dfe77db55 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
@@ -199,9 +199,7 @@
"fieldtype": "Section Break",
"hide_days": 1,
"hide_seconds": 1,
- "options": "fa fa-user",
- "show_days": 1,
- "show_seconds": 1
+ "options": "fa fa-user"
},
{
"allow_on_submit": 1,
@@ -213,9 +211,7 @@
"hide_seconds": 1,
"label": "Title",
"no_copy": 1,
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"bold": 1,
@@ -230,9 +226,7 @@
"options": "ACC-SINV-.YYYY.-\nACC-SINV-RET-.YYYY.-",
"print_hide": 1,
"reqd": 1,
- "set_only_once": 1,
- "show_days": 1,
- "show_seconds": 1
+ "set_only_once": 1
},
{
"bold": 1,
@@ -246,9 +240,7 @@
"oldfieldtype": "Link",
"options": "Customer",
"print_hide": 1,
- "search_index": 1,
- "show_days": 1,
- "show_seconds": 1
+ "search_index": 1
},
{
"bold": 1,
@@ -262,9 +254,7 @@
"label": "Customer Name",
"oldfieldname": "customer_name",
"oldfieldtype": "Data",
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"fieldname": "tax_id",
@@ -273,9 +263,7 @@
"hide_seconds": 1,
"label": "Tax Id",
"print_hide": 1,
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"fieldname": "project",
@@ -287,9 +275,7 @@
"oldfieldname": "project_name",
"oldfieldtype": "Link",
"options": "Project",
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"default": "0",
@@ -300,9 +286,7 @@
"label": "Include Payment (POS)",
"oldfieldname": "is_pos",
"oldfieldtype": "Check",
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"depends_on": "is_pos",
@@ -312,9 +296,7 @@
"hide_seconds": 1,
"label": "POS Profile",
"options": "POS Profile",
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"default": "0",
@@ -324,18 +306,14 @@
"hide_seconds": 1,
"label": "Is Return (Credit Note)",
"no_copy": 1,
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"fieldname": "column_break1",
"fieldtype": "Column Break",
"hide_days": 1,
"hide_seconds": 1,
- "oldfieldtype": "Column Break",
- "show_days": 1,
- "show_seconds": 1
+ "oldfieldtype": "Column Break"
},
{
"fieldname": "company",
@@ -349,9 +327,7 @@
"options": "Company",
"print_hide": 1,
"remember_last_selected_value": 1,
- "reqd": 1,
- "show_days": 1,
- "show_seconds": 1
+ "reqd": 1
},
{
"fieldname": "cost_center",
@@ -359,9 +335,7 @@
"hide_days": 1,
"hide_seconds": 1,
"label": "Cost Center",
- "options": "Cost Center",
- "show_days": 1,
- "show_seconds": 1
+ "options": "Cost Center"
},
{
"bold": 1,
@@ -375,9 +349,7 @@
"oldfieldname": "posting_date",
"oldfieldtype": "Date",
"reqd": 1,
- "search_index": 1,
- "show_days": 1,
- "show_seconds": 1
+ "search_index": 1
},
{
"fieldname": "posting_time",
@@ -388,9 +360,7 @@
"no_copy": 1,
"oldfieldname": "posting_time",
"oldfieldtype": "Time",
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"default": "0",
@@ -400,9 +370,7 @@
"hide_days": 1,
"hide_seconds": 1,
"label": "Edit Posting Date and Time",
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"fieldname": "due_date",
@@ -412,9 +380,7 @@
"label": "Payment Due Date",
"no_copy": 1,
"oldfieldname": "due_date",
- "oldfieldtype": "Date",
- "show_days": 1,
- "show_seconds": 1
+ "oldfieldtype": "Date"
},
{
"fieldname": "amended_from",
@@ -428,9 +394,7 @@
"oldfieldtype": "Link",
"options": "Sales Invoice",
"print_hide": 1,
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"depends_on": "eval:doc.return_against || doc.is_debit_note",
@@ -443,9 +407,7 @@
"options": "Sales Invoice",
"print_hide": 1,
"read_only_depends_on": "eval:doc.is_return",
- "search_index": 1,
- "show_days": 1,
- "show_seconds": 1
+ "search_index": 1
},
{
"default": "0",
@@ -454,9 +416,7 @@
"fieldtype": "Check",
"hide_days": 1,
"hide_seconds": 1,
- "label": "Update Billed Amount in Sales Order",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Update Billed Amount in Sales Order"
},
{
"collapsible": 1,
@@ -465,9 +425,7 @@
"fieldtype": "Section Break",
"hide_days": 1,
"hide_seconds": 1,
- "label": "Customer PO Details",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Customer PO Details"
},
{
"allow_on_submit": 1,
@@ -477,17 +435,13 @@
"hide_seconds": 1,
"label": "Customer's Purchase Order",
"no_copy": 1,
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"fieldname": "column_break_23",
"fieldtype": "Column Break",
"hide_days": 1,
- "hide_seconds": 1,
- "show_days": 1,
- "show_seconds": 1
+ "hide_seconds": 1
},
{
"allow_on_submit": 1,
@@ -495,9 +449,7 @@
"fieldtype": "Date",
"hide_days": 1,
"hide_seconds": 1,
- "label": "Customer's Purchase Order Date",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Customer's Purchase Order Date"
},
{
"collapsible": 1,
@@ -505,9 +457,7 @@
"fieldtype": "Section Break",
"hide_days": 1,
"hide_seconds": 1,
- "label": "Address and Contact",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Address and Contact"
},
{
"fieldname": "customer_address",
@@ -516,9 +466,7 @@
"hide_seconds": 1,
"label": "Customer Address",
"options": "Address",
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"fieldname": "address_display",
@@ -526,9 +474,7 @@
"hide_days": 1,
"hide_seconds": 1,
"label": "Address",
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"fieldname": "contact_person",
@@ -538,9 +484,7 @@
"in_global_search": 1,
"label": "Contact Person",
"options": "Contact",
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"fieldname": "contact_display",
@@ -548,9 +492,7 @@
"hide_days": 1,
"hide_seconds": 1,
"label": "Contact",
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"fieldname": "contact_mobile",
@@ -559,9 +501,7 @@
"hide_days": 1,
"hide_seconds": 1,
"label": "Mobile No",
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"fieldname": "contact_email",
@@ -572,9 +512,7 @@
"label": "Contact Email",
"options": "Email",
"print_hide": 1,
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"fieldname": "territory",
@@ -583,17 +521,13 @@
"hide_seconds": 1,
"label": "Territory",
"options": "Territory",
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"fieldname": "col_break4",
"fieldtype": "Column Break",
"hide_days": 1,
- "hide_seconds": 1,
- "show_days": 1,
- "show_seconds": 1
+ "hide_seconds": 1
},
{
"fieldname": "shipping_address_name",
@@ -602,9 +536,7 @@
"hide_seconds": 1,
"label": "Shipping Address Name",
"options": "Address",
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"fieldname": "shipping_address",
@@ -613,9 +545,7 @@
"hide_seconds": 1,
"label": "Shipping Address",
"print_hide": 1,
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"fieldname": "company_address",
@@ -624,9 +554,7 @@
"hide_seconds": 1,
"label": "Company Address Name",
"options": "Address",
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"fieldname": "company_address_display",
@@ -636,9 +564,7 @@
"hide_seconds": 1,
"label": "Company Address",
"print_hide": 1,
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"collapsible": 1,
@@ -647,9 +573,7 @@
"fieldtype": "Section Break",
"hide_days": 1,
"hide_seconds": 1,
- "label": "Currency and Price List",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Currency and Price List"
},
{
"fieldname": "currency",
@@ -661,9 +585,7 @@
"oldfieldtype": "Select",
"options": "Currency",
"print_hide": 1,
- "reqd": 1,
- "show_days": 1,
- "show_seconds": 1
+ "reqd": 1
},
{
"description": "Rate at which Customer Currency is converted to customer's base currency",
@@ -676,17 +598,13 @@
"oldfieldtype": "Currency",
"precision": "9",
"print_hide": 1,
- "reqd": 1,
- "show_days": 1,
- "show_seconds": 1
+ "reqd": 1
},
{
"fieldname": "column_break2",
"fieldtype": "Column Break",
"hide_days": 1,
"hide_seconds": 1,
- "show_days": 1,
- "show_seconds": 1,
"width": "50%"
},
{
@@ -699,9 +617,7 @@
"oldfieldtype": "Select",
"options": "Price List",
"print_hide": 1,
- "reqd": 1,
- "show_days": 1,
- "show_seconds": 1
+ "reqd": 1
},
{
"fieldname": "price_list_currency",
@@ -712,9 +628,7 @@
"options": "Currency",
"print_hide": 1,
"read_only": 1,
- "reqd": 1,
- "show_days": 1,
- "show_seconds": 1
+ "reqd": 1
},
{
"description": "Rate at which Price list currency is converted to customer's base currency",
@@ -725,9 +639,7 @@
"label": "Price List Exchange Rate",
"precision": "9",
"print_hide": 1,
- "reqd": 1,
- "show_days": 1,
- "show_seconds": 1
+ "reqd": 1
},
{
"default": "0",
@@ -738,18 +650,14 @@
"label": "Ignore Pricing Rule",
"no_copy": 1,
"permlevel": 1,
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"fieldname": "sec_warehouse",
"fieldtype": "Section Break",
"hide_days": 1,
"hide_seconds": 1,
- "label": "Warehouse",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Warehouse"
},
{
"depends_on": "update_stock",
@@ -759,9 +667,7 @@
"hide_seconds": 1,
"label": "Source Warehouse",
"options": "Warehouse",
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"fieldname": "items_section",
@@ -770,9 +676,7 @@
"hide_seconds": 1,
"label": "Items",
"oldfieldtype": "Section Break",
- "options": "fa fa-shopping-cart",
- "show_days": 1,
- "show_seconds": 1
+ "options": "fa fa-shopping-cart"
},
{
"default": "0",
@@ -783,18 +687,14 @@
"label": "Update Stock",
"oldfieldname": "update_stock",
"oldfieldtype": "Check",
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"fieldname": "scan_barcode",
"fieldtype": "Data",
"hide_days": 1,
"hide_seconds": 1,
- "label": "Scan Barcode",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Scan Barcode"
},
{
"allow_bulk_edit": 1,
@@ -806,18 +706,14 @@
"oldfieldname": "entries",
"oldfieldtype": "Table",
"options": "Sales Invoice Item",
- "reqd": 1,
- "show_days": 1,
- "show_seconds": 1
+ "reqd": 1
},
{
"fieldname": "pricing_rule_details",
"fieldtype": "Section Break",
"hide_days": 1,
"hide_seconds": 1,
- "label": "Pricing Rules",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Pricing Rules"
},
{
"fieldname": "pricing_rules",
@@ -826,9 +722,7 @@
"hide_seconds": 1,
"label": "Pricing Rule Detail",
"options": "Pricing Rule Detail",
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"fieldname": "packing_list",
@@ -837,9 +731,7 @@
"hide_seconds": 1,
"label": "Packing List",
"options": "fa fa-suitcase",
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"fieldname": "packed_items",
@@ -848,9 +740,7 @@
"hide_seconds": 1,
"label": "Packed Items",
"options": "Packed Item",
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"fieldname": "product_bundle_help",
@@ -858,9 +748,7 @@
"hide_days": 1,
"hide_seconds": 1,
"label": "Product Bundle Help",
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"collapsible": 1,
@@ -870,9 +758,7 @@
"fieldtype": "Section Break",
"hide_days": 1,
"hide_seconds": 1,
- "label": "Time Sheet List",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Time Sheet List"
},
{
"fieldname": "timesheets",
@@ -881,9 +767,7 @@
"hide_seconds": 1,
"label": "Time Sheets",
"options": "Sales Invoice Timesheet",
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"default": "0",
@@ -894,17 +778,13 @@
"label": "Total Billing Amount",
"options": "currency",
"print_hide": 1,
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"fieldname": "section_break_30",
"fieldtype": "Section Break",
"hide_days": 1,
- "hide_seconds": 1,
- "show_days": 1,
- "show_seconds": 1
+ "hide_seconds": 1
},
{
"fieldname": "total_qty",
@@ -912,9 +792,7 @@
"hide_days": 1,
"hide_seconds": 1,
"label": "Total Quantity",
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"fieldname": "base_total",
@@ -924,9 +802,7 @@
"label": "Total (Company Currency)",
"options": "Company:company:default_currency",
"print_hide": 1,
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"fieldname": "base_net_total",
@@ -939,17 +815,13 @@
"options": "Company:company:default_currency",
"print_hide": 1,
"read_only": 1,
- "reqd": 1,
- "show_days": 1,
- "show_seconds": 1
+ "reqd": 1
},
{
"fieldname": "column_break_32",
"fieldtype": "Column Break",
"hide_days": 1,
- "hide_seconds": 1,
- "show_days": 1,
- "show_seconds": 1
+ "hide_seconds": 1
},
{
"fieldname": "total",
@@ -958,9 +830,7 @@
"hide_seconds": 1,
"label": "Total",
"options": "currency",
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"fieldname": "net_total",
@@ -970,9 +840,7 @@
"label": "Net Total",
"options": "currency",
"print_hide": 1,
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"fieldname": "total_net_weight",
@@ -981,9 +849,7 @@
"hide_seconds": 1,
"label": "Total Net Weight",
"print_hide": 1,
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"fieldname": "taxes_section",
@@ -991,9 +857,7 @@
"hide_days": 1,
"hide_seconds": 1,
"oldfieldtype": "Section Break",
- "options": "fa fa-money",
- "show_days": 1,
- "show_seconds": 1
+ "options": "fa fa-money"
},
{
"fieldname": "taxes_and_charges",
@@ -1004,17 +868,13 @@
"oldfieldname": "charge",
"oldfieldtype": "Link",
"options": "Sales Taxes and Charges Template",
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"fieldname": "column_break_38",
"fieldtype": "Column Break",
"hide_days": 1,
- "hide_seconds": 1,
- "show_days": 1,
- "show_seconds": 1
+ "hide_seconds": 1
},
{
"fieldname": "shipping_rule",
@@ -1024,9 +884,7 @@
"label": "Shipping Rule",
"oldfieldtype": "Button",
"options": "Shipping Rule",
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"fieldname": "tax_category",
@@ -1035,17 +893,13 @@
"hide_seconds": 1,
"label": "Tax Category",
"options": "Tax Category",
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"fieldname": "section_break_40",
"fieldtype": "Section Break",
"hide_days": 1,
- "hide_seconds": 1,
- "show_days": 1,
- "show_seconds": 1
+ "hide_seconds": 1
},
{
"fieldname": "taxes",
@@ -1055,9 +909,7 @@
"label": "Sales Taxes and Charges",
"oldfieldname": "other_charges",
"oldfieldtype": "Table",
- "options": "Sales Taxes and Charges",
- "show_days": 1,
- "show_seconds": 1
+ "options": "Sales Taxes and Charges"
},
{
"collapsible": 1,
@@ -1065,9 +917,7 @@
"fieldtype": "Section Break",
"hide_days": 1,
"hide_seconds": 1,
- "label": "Tax Breakup",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Tax Breakup"
},
{
"fieldname": "other_charges_calculation",
@@ -1078,17 +928,13 @@
"no_copy": 1,
"oldfieldtype": "HTML",
"print_hide": 1,
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"fieldname": "section_break_43",
"fieldtype": "Section Break",
"hide_days": 1,
- "hide_seconds": 1,
- "show_days": 1,
- "show_seconds": 1
+ "hide_seconds": 1
},
{
"fieldname": "base_total_taxes_and_charges",
@@ -1100,17 +946,13 @@
"oldfieldtype": "Currency",
"options": "Company:company:default_currency",
"print_hide": 1,
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"fieldname": "column_break_47",
"fieldtype": "Column Break",
"hide_days": 1,
- "hide_seconds": 1,
- "show_days": 1,
- "show_seconds": 1
+ "hide_seconds": 1
},
{
"fieldname": "total_taxes_and_charges",
@@ -1120,9 +962,7 @@
"label": "Total Taxes and Charges",
"options": "currency",
"print_hide": 1,
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"collapsible": 1,
@@ -1130,9 +970,7 @@
"fieldtype": "Section Break",
"hide_days": 1,
"hide_seconds": 1,
- "label": "Loyalty Points Redemption",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Loyalty Points Redemption"
},
{
"depends_on": "redeem_loyalty_points",
@@ -1142,9 +980,7 @@
"hide_seconds": 1,
"label": "Loyalty Points",
"no_copy": 1,
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"depends_on": "redeem_loyalty_points",
@@ -1156,9 +992,7 @@
"no_copy": 1,
"options": "Company:company:default_currency",
"print_hide": 1,
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"default": "0",
@@ -1168,17 +1002,13 @@
"hide_seconds": 1,
"label": "Redeem Loyalty Points",
"no_copy": 1,
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"fieldname": "column_break_77",
"fieldtype": "Column Break",
"hide_days": 1,
- "hide_seconds": 1,
- "show_days": 1,
- "show_seconds": 1
+ "hide_seconds": 1
},
{
"fetch_from": "customer.loyalty_program",
@@ -1190,9 +1020,7 @@
"no_copy": 1,
"options": "Loyalty Program",
"print_hide": 1,
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"depends_on": "redeem_loyalty_points",
@@ -1202,9 +1030,7 @@
"hide_seconds": 1,
"label": "Redemption Account",
"no_copy": 1,
- "options": "Account",
- "show_days": 1,
- "show_seconds": 1
+ "options": "Account"
},
{
"depends_on": "redeem_loyalty_points",
@@ -1214,9 +1040,7 @@
"hide_seconds": 1,
"label": "Redemption Cost Center",
"no_copy": 1,
- "options": "Cost Center",
- "show_days": 1,
- "show_seconds": 1
+ "options": "Cost Center"
},
{
"collapsible": 1,
@@ -1225,9 +1049,7 @@
"fieldtype": "Section Break",
"hide_days": 1,
"hide_seconds": 1,
- "label": "Additional Discount",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Additional Discount"
},
{
"default": "Grand Total",
@@ -1237,9 +1059,7 @@
"hide_seconds": 1,
"label": "Apply Additional Discount On",
"options": "\nGrand Total\nNet Total",
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"fieldname": "base_discount_amount",
@@ -1249,17 +1069,13 @@
"label": "Additional Discount Amount (Company Currency)",
"options": "Company:company:default_currency",
"print_hide": 1,
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"fieldname": "column_break_51",
"fieldtype": "Column Break",
"hide_days": 1,
- "hide_seconds": 1,
- "show_days": 1,
- "show_seconds": 1
+ "hide_seconds": 1
},
{
"fieldname": "additional_discount_percentage",
@@ -1267,9 +1083,7 @@
"hide_days": 1,
"hide_seconds": 1,
"label": "Additional Discount Percentage",
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"fieldname": "discount_amount",
@@ -1278,9 +1092,7 @@
"hide_seconds": 1,
"label": "Additional Discount Amount",
"options": "currency",
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"fieldname": "totals",
@@ -1289,9 +1101,7 @@
"hide_seconds": 1,
"oldfieldtype": "Section Break",
"options": "fa fa-money",
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"fieldname": "base_grand_total",
@@ -1304,9 +1114,7 @@
"options": "Company:company:default_currency",
"print_hide": 1,
"read_only": 1,
- "reqd": 1,
- "show_days": 1,
- "show_seconds": 1
+ "reqd": 1
},
{
"depends_on": "eval:!doc.disable_rounded_total",
@@ -1318,9 +1126,7 @@
"no_copy": 1,
"options": "Company:company:default_currency",
"print_hide": 1,
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"depends_on": "eval:!doc.disable_rounded_total",
@@ -1333,9 +1139,7 @@
"oldfieldtype": "Currency",
"options": "Company:company:default_currency",
"print_hide": 1,
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"description": "In Words will be visible once you save the Sales Invoice.",
@@ -1348,9 +1152,7 @@
"oldfieldname": "in_words",
"oldfieldtype": "Data",
"print_hide": 1,
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"fieldname": "column_break5",
@@ -1359,8 +1161,6 @@
"hide_seconds": 1,
"oldfieldtype": "Column Break",
"print_hide": 1,
- "show_days": 1,
- "show_seconds": 1,
"width": "50%"
},
{
@@ -1375,9 +1175,7 @@
"oldfieldtype": "Currency",
"options": "currency",
"read_only": 1,
- "reqd": 1,
- "show_days": 1,
- "show_seconds": 1
+ "reqd": 1
},
{
"depends_on": "eval:!doc.disable_rounded_total",
@@ -1389,9 +1187,7 @@
"no_copy": 1,
"options": "currency",
"print_hide": 1,
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"bold": 1,
@@ -1404,9 +1200,7 @@
"oldfieldname": "rounded_total_export",
"oldfieldtype": "Currency",
"options": "currency",
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"fieldname": "in_words",
@@ -1418,9 +1212,7 @@
"oldfieldname": "in_words_export",
"oldfieldtype": "Data",
"print_hide": 1,
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"fieldname": "total_advance",
@@ -1432,9 +1224,7 @@
"oldfieldtype": "Currency",
"options": "party_account_currency",
"print_hide": 1,
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"fieldname": "outstanding_amount",
@@ -1447,9 +1237,7 @@
"oldfieldtype": "Currency",
"options": "party_account_currency",
"print_hide": 1,
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"collapsible": 1,
@@ -1461,9 +1249,7 @@
"label": "Advance Payments",
"oldfieldtype": "Section Break",
"options": "fa fa-money",
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"default": "0",
@@ -1471,9 +1257,7 @@
"fieldtype": "Check",
"hide_days": 1,
"hide_seconds": 1,
- "label": "Allocate Advances Automatically (FIFO)",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Allocate Advances Automatically (FIFO)"
},
{
"depends_on": "eval:!doc.allocate_advances_automatically",
@@ -1482,9 +1266,7 @@
"hide_days": 1,
"hide_seconds": 1,
"label": "Get Advances Received",
- "options": "set_advances",
- "show_days": 1,
- "show_seconds": 1
+ "options": "set_advances"
},
{
"fieldname": "advances",
@@ -1495,9 +1277,7 @@
"oldfieldname": "advance_adjustment_details",
"oldfieldtype": "Table",
"options": "Sales Invoice Advance",
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"collapsible": 1,
@@ -1506,9 +1286,7 @@
"fieldtype": "Section Break",
"hide_days": 1,
"hide_seconds": 1,
- "label": "Payment Terms",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Payment Terms"
},
{
"depends_on": "eval:(!doc.is_pos && !doc.is_return)",
@@ -1519,9 +1297,7 @@
"label": "Payment Terms Template",
"no_copy": 1,
"options": "Payment Terms Template",
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"depends_on": "eval:(!doc.is_pos && !doc.is_return)",
@@ -1532,9 +1308,7 @@
"label": "Payment Schedule",
"no_copy": 1,
"options": "Payment Schedule",
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"depends_on": "eval:doc.is_pos===1||(doc.advances && doc.advances.length>0)",
@@ -1543,9 +1317,7 @@
"hide_days": 1,
"hide_seconds": 1,
"label": "Payments",
- "options": "fa fa-money",
- "show_days": 1,
- "show_seconds": 1
+ "options": "fa fa-money"
},
{
"depends_on": "is_pos",
@@ -1558,9 +1330,7 @@
"oldfieldname": "cash_bank_account",
"oldfieldtype": "Link",
"options": "Account",
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"depends_on": "eval:doc.is_pos===1",
@@ -1570,17 +1340,13 @@
"hide_seconds": 1,
"label": "Sales Invoice Payment",
"options": "Sales Invoice Payment",
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"fieldname": "section_break_84",
"fieldtype": "Section Break",
"hide_days": 1,
- "hide_seconds": 1,
- "show_days": 1,
- "show_seconds": 1
+ "hide_seconds": 1
},
{
"fieldname": "base_paid_amount",
@@ -1591,17 +1357,13 @@
"no_copy": 1,
"options": "Company:company:default_currency",
"print_hide": 1,
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"fieldname": "column_break_86",
"fieldtype": "Column Break",
"hide_days": 1,
- "hide_seconds": 1,
- "show_days": 1,
- "show_seconds": 1
+ "hide_seconds": 1
},
{
"depends_on": "eval: doc.is_pos || doc.redeem_loyalty_points",
@@ -1615,17 +1377,13 @@
"oldfieldtype": "Currency",
"options": "currency",
"print_hide": 1,
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"fieldname": "section_break_88",
"fieldtype": "Section Break",
"hide_days": 1,
- "hide_seconds": 1,
- "show_days": 1,
- "show_seconds": 1
+ "hide_seconds": 1
},
{
"depends_on": "is_pos",
@@ -1637,17 +1395,13 @@
"no_copy": 1,
"options": "Company:company:default_currency",
"print_hide": 1,
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"fieldname": "column_break_90",
"fieldtype": "Column Break",
"hide_days": 1,
- "hide_seconds": 1,
- "show_days": 1,
- "show_seconds": 1
+ "hide_seconds": 1
},
{
"depends_on": "is_pos",
@@ -1658,9 +1412,7 @@
"label": "Change Amount",
"no_copy": 1,
"options": "currency",
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"depends_on": "is_pos",
@@ -1670,9 +1422,7 @@
"hide_seconds": 1,
"label": "Account for Change Amount",
"options": "Account",
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"collapsible": 1,
@@ -1683,8 +1433,6 @@
"hide_days": 1,
"hide_seconds": 1,
"label": "Write Off",
- "show_days": 1,
- "show_seconds": 1,
"width": "50%"
},
{
@@ -1695,9 +1443,7 @@
"label": "Write Off Amount",
"no_copy": 1,
"options": "currency",
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"fieldname": "base_write_off_amount",
@@ -1708,9 +1454,7 @@
"no_copy": 1,
"options": "Company:company:default_currency",
"print_hide": 1,
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"default": "0",
@@ -1720,17 +1464,13 @@
"hide_days": 1,
"hide_seconds": 1,
"label": "Write Off Outstanding Amount",
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"fieldname": "column_break_74",
"fieldtype": "Column Break",
"hide_days": 1,
- "hide_seconds": 1,
- "show_days": 1,
- "show_seconds": 1
+ "hide_seconds": 1
},
{
"fieldname": "write_off_account",
@@ -1739,9 +1479,7 @@
"hide_seconds": 1,
"label": "Write Off Account",
"options": "Account",
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"fieldname": "write_off_cost_center",
@@ -1750,9 +1488,7 @@
"hide_seconds": 1,
"label": "Write Off Cost Center",
"options": "Cost Center",
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"collapsible": 1,
@@ -1762,9 +1498,7 @@
"hide_days": 1,
"hide_seconds": 1,
"label": "Terms and Conditions",
- "oldfieldtype": "Section Break",
- "show_days": 1,
- "show_seconds": 1
+ "oldfieldtype": "Section Break"
},
{
"fieldname": "tc_name",
@@ -1775,9 +1509,7 @@
"oldfieldname": "tc_name",
"oldfieldtype": "Link",
"options": "Terms and Conditions",
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"fieldname": "terms",
@@ -1786,9 +1518,7 @@
"hide_seconds": 1,
"label": "Terms and Conditions Details",
"oldfieldname": "terms",
- "oldfieldtype": "Text Editor",
- "show_days": 1,
- "show_seconds": 1
+ "oldfieldtype": "Text Editor"
},
{
"collapsible": 1,
@@ -1796,9 +1526,7 @@
"fieldtype": "Section Break",
"hide_days": 1,
"hide_seconds": 1,
- "label": "Printing Settings",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Printing Settings"
},
{
"allow_on_submit": 1,
@@ -1810,9 +1538,7 @@
"oldfieldname": "letter_head",
"oldfieldtype": "Select",
"options": "Letter Head",
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"allow_on_submit": 1,
@@ -1822,9 +1548,7 @@
"hide_days": 1,
"hide_seconds": 1,
"label": "Group same items",
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"fieldname": "language",
@@ -1833,17 +1557,13 @@
"hide_seconds": 1,
"label": "Print Language",
"print_hide": 1,
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"fieldname": "column_break_84",
"fieldtype": "Column Break",
"hide_days": 1,
- "hide_seconds": 1,
- "show_days": 1,
- "show_seconds": 1
+ "hide_seconds": 1
},
{
"allow_on_submit": 1,
@@ -1857,9 +1577,7 @@
"oldfieldtype": "Link",
"options": "Print Heading",
"print_hide": 1,
- "report_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "report_hide": 1
},
{
"collapsible": 1,
@@ -1868,9 +1586,7 @@
"fieldtype": "Section Break",
"hide_days": 1,
"hide_seconds": 1,
- "label": "More Information",
- "show_days": 1,
- "show_seconds": 1
+ "label": "More Information"
},
{
"fieldname": "inter_company_invoice_reference",
@@ -1879,9 +1595,7 @@
"hide_seconds": 1,
"label": "Inter Company Invoice Reference",
"options": "Purchase Invoice",
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"fieldname": "customer_group",
@@ -1891,9 +1605,7 @@
"hide_seconds": 1,
"label": "Customer Group",
"options": "Customer Group",
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"fieldname": "campaign",
@@ -1904,9 +1616,7 @@
"oldfieldname": "campaign",
"oldfieldtype": "Link",
"options": "Campaign",
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"default": "0",
@@ -1916,17 +1626,13 @@
"hide_seconds": 1,
"label": "Is Discounted",
"no_copy": 1,
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"fieldname": "col_break23",
"fieldtype": "Column Break",
"hide_days": 1,
"hide_seconds": 1,
- "show_days": 1,
- "show_seconds": 1,
"width": "50%"
},
{
@@ -1940,9 +1646,7 @@
"no_copy": 1,
"options": "\nDraft\nReturn\nCredit Note Issued\nSubmitted\nPaid\nUnpaid\nUnpaid and Discounted\nOverdue and Discounted\nOverdue\nCancelled\nInternal Transfer",
"print_hide": 1,
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"fieldname": "source",
@@ -1953,9 +1657,7 @@
"oldfieldname": "source",
"oldfieldtype": "Select",
"options": "Lead Source",
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"collapsible": 1,
@@ -1966,9 +1668,7 @@
"label": "Accounting Details",
"oldfieldtype": "Section Break",
"options": "fa fa-file-text",
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"fieldname": "debit_to",
@@ -1981,9 +1681,7 @@
"options": "Account",
"print_hide": 1,
"reqd": 1,
- "search_index": 1,
- "show_days": 1,
- "show_seconds": 1
+ "search_index": 1
},
{
"fieldname": "party_account_currency",
@@ -1995,9 +1693,7 @@
"no_copy": 1,
"options": "Currency",
"print_hide": 1,
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"default": "No",
@@ -2009,9 +1705,7 @@
"oldfieldname": "is_opening",
"oldfieldtype": "Select",
"options": "No\nYes",
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"fieldname": "c_form_applicable",
@@ -2021,9 +1715,7 @@
"label": "C-Form Applicable",
"no_copy": 1,
"options": "No\nYes",
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"fieldname": "c_form_no",
@@ -2034,9 +1726,7 @@
"no_copy": 1,
"options": "C-Form",
"print_hide": 1,
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"fieldname": "column_break8",
@@ -2044,9 +1734,7 @@
"hide_days": 1,
"hide_seconds": 1,
"oldfieldtype": "Column Break",
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"fieldname": "remarks",
@@ -2057,9 +1745,7 @@
"no_copy": 1,
"oldfieldname": "remarks",
"oldfieldtype": "Text",
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"collapsible": 1,
@@ -2071,9 +1757,7 @@
"label": "Commission",
"oldfieldtype": "Section Break",
"options": "fa fa-group",
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"fieldname": "sales_partner",
@@ -2084,9 +1768,7 @@
"oldfieldname": "sales_partner",
"oldfieldtype": "Link",
"options": "Sales Partner",
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"fieldname": "column_break10",
@@ -2095,8 +1777,6 @@
"hide_seconds": 1,
"oldfieldtype": "Column Break",
"print_hide": 1,
- "show_days": 1,
- "show_seconds": 1,
"width": "50%"
},
{
@@ -2107,9 +1787,7 @@
"label": "Commission Rate (%)",
"oldfieldname": "commission_rate",
"oldfieldtype": "Currency",
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"fieldname": "total_commission",
@@ -2120,9 +1798,7 @@
"oldfieldname": "total_commission",
"oldfieldtype": "Currency",
"options": "Company:company:default_currency",
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"collapsible": 1,
@@ -2132,9 +1808,7 @@
"hide_days": 1,
"hide_seconds": 1,
"label": "Sales Team",
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"allow_on_submit": 1,
@@ -2146,9 +1820,7 @@
"oldfieldname": "sales_team",
"oldfieldtype": "Table",
"options": "Sales Team",
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"collapsible": 1,
@@ -2156,9 +1828,7 @@
"fieldtype": "Section Break",
"hide_days": 1,
"hide_seconds": 1,
- "label": "Subscription Section",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Subscription Section"
},
{
"allow_on_submit": 1,
@@ -2168,9 +1838,7 @@
"hide_seconds": 1,
"label": "From Date",
"no_copy": 1,
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"allow_on_submit": 1,
@@ -2180,17 +1848,13 @@
"hide_seconds": 1,
"label": "To Date",
"no_copy": 1,
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"fieldname": "column_break_140",
"fieldtype": "Column Break",
"hide_days": 1,
- "hide_seconds": 1,
- "show_days": 1,
- "show_seconds": 1
+ "hide_seconds": 1
},
{
"allow_on_submit": 1,
@@ -2202,9 +1866,7 @@
"no_copy": 1,
"options": "Auto Repeat",
"print_hide": 1,
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"allow_on_submit": 1,
@@ -2213,9 +1875,7 @@
"fieldtype": "Button",
"hide_days": 1,
"hide_seconds": 1,
- "label": "Update Auto Repeat Reference",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Update Auto Repeat Reference"
},
{
"fieldname": "against_income_account",
@@ -2228,9 +1888,7 @@
"oldfieldname": "against_income_account",
"oldfieldtype": "Small Text",
"print_hide": 1,
- "report_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "report_hide": 1
},
{
"collapsible": 1,
@@ -2238,17 +1896,13 @@
"fieldtype": "Section Break",
"hide_days": 1,
"hide_seconds": 1,
- "label": "Accounting Dimensions",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Accounting Dimensions"
},
{
"fieldname": "dimension_col_break",
"fieldtype": "Column Break",
"hide_days": 1,
- "hide_seconds": 1,
- "show_days": 1,
- "show_seconds": 1
+ "hide_seconds": 1
},
{
"default": "0",
@@ -2256,9 +1910,7 @@
"fieldname": "is_consolidated",
"fieldtype": "Check",
"label": "Is Consolidated",
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"default": "0",
@@ -2268,18 +1920,14 @@
"hide_days": 1,
"hide_seconds": 1,
"label": "Is Internal Customer",
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"fetch_from": "company.tax_id",
"fieldname": "company_tax_id",
"fieldtype": "Data",
"label": "Company Tax ID",
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"depends_on": "eval:doc.is_internal_customer",
@@ -2287,9 +1935,7 @@
"fieldname": "unrealized_profit_loss_account",
"fieldtype": "Link",
"label": "Unrealized Profit / Loss Account",
- "options": "Account",
- "show_days": 1,
- "show_seconds": 1
+ "options": "Account"
},
{
"depends_on": "eval:doc.is_internal_customer",
@@ -2299,41 +1945,32 @@
"fieldtype": "Link",
"label": "Represents Company",
"options": "Company",
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"fieldname": "column_break_55",
- "fieldtype": "Column Break",
- "show_days": 1,
- "show_seconds": 1
+ "fieldtype": "Column Break"
},
{
"depends_on": "eval: doc.is_internal_customer && doc.update_stock",
"fieldname": "set_target_warehouse",
"fieldtype": "Link",
+ "ignore_user_permissions": 1,
"label": "Set Target Warehouse",
- "options": "Warehouse",
- "show_days": 1,
- "show_seconds": 1
+ "options": "Warehouse"
},
{
"default": "0",
"fieldname": "is_debit_note",
"fieldtype": "Check",
- "label": "Is Debit Note",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Is Debit Note"
},
{
"default": "0",
"depends_on": "grand_total",
"fieldname": "disable_rounded_total",
"fieldtype": "Check",
- "label": "Disable Rounded Total",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Disable Rounded Total"
},
{
"fieldname": "additional_discount_account",
@@ -2362,9 +1999,7 @@
"fieldtype": "Check",
"hidden": 1,
"label": "Ignore Default Payment Terms Template",
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
}
],
"icon": "fa fa-file-text",
@@ -2377,7 +2012,7 @@
"link_fieldname": "consolidated_invoice"
}
],
- "modified": "2021-08-07 23:02:20.445127",
+ "modified": "2021-08-17 19:00:32.230701",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice",
From 44434ff70fdb68ae3dce8c9e837350e51533dcf0 Mon Sep 17 00:00:00 2001
From: Frappe PR Bot
Date: Wed, 18 Aug 2021 18:33:06 +0530
Subject: [PATCH 366/386] fix: date_unchanged calculation in "Update Items"
(#26992) (#27011)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Branch corrected https://github.com/frappe/erpnext/pull/26058
ERPNext generates "Cannot set quantity less than delivered quantity" error even the delivered qty is zero when user clicks "Update Items".
"date_unchanged" variable gets false value because of new_date is string.
"getdate(new_date)" corrects the date comparison.

(cherry picked from commit d8a7abcd02f674bf6c4270a817ae9762a0b57140)
Co-authored-by: Türker Tunalı
---
erpnext/controllers/accounts_controller.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index 4c79a5cb5f..26eb5bb337 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -1863,7 +1863,7 @@ def update_child_qty_rate(parent_doctype, trans_items, parent_doctype_name, chil
qty_unchanged = prev_qty == new_qty
uom_unchanged = prev_uom == new_uom
conversion_factor_unchanged = prev_con_fac == new_con_fac
- date_unchanged = prev_date == new_date if prev_date and new_date else False # in case of delivery note etc
+ date_unchanged = prev_date == getdate(new_date) if prev_date and new_date else False # in case of delivery note etc
if rate_unchanged and qty_unchanged and conversion_factor_unchanged and uom_unchanged and date_unchanged:
continue
From ecd6584c50718adb6bae1da3de0d66a2b7d3985b Mon Sep 17 00:00:00 2001
From: Afshan <33727827+AfshanKhan@users.noreply.github.com>
Date: Thu, 19 Aug 2021 12:18:27 +0530
Subject: [PATCH 367/386] fix: assigning values to rows in sales register
reports (#26546)
* fix: assigning values to rows in sales register reports
* fix: check for is_internal_customer for unrealized_profit_loss_account
---
erpnext/accounts/doctype/sales_invoice/sales_invoice.json | 1 +
.../item_wise_sales_register/item_wise_sales_register.py | 3 ++-
erpnext/accounts/report/sales_register/sales_register.py | 5 +++--
3 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
index 7dfe77db55..b65b101051 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
@@ -1934,6 +1934,7 @@
"description": "Unrealized Profit / Loss account for intra-company transfers",
"fieldname": "unrealized_profit_loss_account",
"fieldtype": "Link",
+ "ignore_user_permissions": 1,
"label": "Unrealized Profit / Loss Account",
"options": "Account"
},
diff --git a/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py b/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py
index 2e794da842..08065a204e 100644
--- a/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py
+++ b/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py
@@ -76,7 +76,7 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum
'company': d.company,
'sales_order': d.sales_order,
'delivery_note': d.delivery_note,
- 'income_account': d.unrealized_profit_loss_account or d.income_account,
+ 'income_account': d.unrealized_profit_loss_account if d.is_internal_customer == 1 else d.income_account,
'cost_center': d.cost_center,
'stock_qty': d.stock_qty,
'stock_uom': d.stock_uom
@@ -380,6 +380,7 @@ def get_items(filters, additional_query_columns):
`tabSales Invoice Item`.name, `tabSales Invoice Item`.parent,
`tabSales Invoice`.posting_date, `tabSales Invoice`.debit_to,
`tabSales Invoice`.unrealized_profit_loss_account,
+ `tabSales Invoice`.is_internal_customer,
`tabSales Invoice`.project, `tabSales Invoice`.customer, `tabSales Invoice`.remarks,
`tabSales Invoice`.territory, `tabSales Invoice`.company, `tabSales Invoice`.base_net_total,
`tabSales Invoice Item`.item_code, `tabSales Invoice Item`.description,
diff --git a/erpnext/accounts/report/sales_register/sales_register.py b/erpnext/accounts/report/sales_register/sales_register.py
index 909959323f..f38bd78c0d 100644
--- a/erpnext/accounts/report/sales_register/sales_register.py
+++ b/erpnext/accounts/report/sales_register/sales_register.py
@@ -84,7 +84,7 @@ def _execute(filters, additional_table_columns=None, additional_query_columns=No
# Add amount in unrealized account
for account in unrealized_profit_loss_accounts:
row.update({
- frappe.scrub(account): flt(internal_invoice_map.get((inv.name, account)))
+ frappe.scrub(account+"_unrealized"): flt(internal_invoice_map.get((inv.name, account)))
})
# net total
@@ -258,6 +258,7 @@ def get_columns(invoice_list, additional_table_columns):
unrealized_profit_loss_accounts = frappe.db.sql_list("""SELECT distinct unrealized_profit_loss_account
from `tabSales Invoice` where docstatus = 1 and name in (%s)
+ and is_internal_customer = 1
and ifnull(unrealized_profit_loss_account, '') != ''
order by unrealized_profit_loss_account""" %
', '.join(['%s']*len(invoice_list)), tuple(inv.name for inv in invoice_list))
@@ -284,7 +285,7 @@ def get_columns(invoice_list, additional_table_columns):
for account in unrealized_profit_loss_accounts:
unrealized_profit_loss_account_columns.append({
"label": account,
- "fieldname": frappe.scrub(account),
+ "fieldname": frappe.scrub(account+"_unrealized"),
"fieldtype": "Currency",
"options": "currency",
"width": 120
From 4551d7d6029b6f587f6c99d4f8df5519241c6a86 Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Thu, 19 Aug 2021 13:41:10 +0530
Subject: [PATCH 368/386] chore: mass trailing whitespace and EOF fixes
---
erpnext/.stylelintrc | 2 +-
.../account_balance_timeline.js | 2 +-
erpnext/accounts/deferred_revenue.py | 2 -
.../accounting_dimension.js | 2 +-
.../test_accounting_dimension.py | 2 -
.../accounting_dimension_filter.js | 2 +-
.../accounting_period/accounting_period.py | 2 +-
.../accounts_settings/accounts_settings.js | 2 +-
.../accounts_settings/accounts_settings.py | 4 +-
.../regional/united_states.js | 2 +-
erpnext/accounts/doctype/bank/bank.js | 2 +-
erpnext/accounts/doctype/bank/bank.py | 2 +-
.../bank_account/bank_account_dashboard.py | 2 +-
.../doctype/bank_clearance/bank_clearance.js | 2 +-
.../bank_clearance_detail.py | 2 +-
.../doctype/bank_guarantee/bank_guarantee.py | 2 +-
.../bank_transaction/bank_transaction.py | 1 -
.../bank_transaction/bank_transaction_list.js | 2 +-
.../bank_transaction_upload.py | 2 +-
.../c_form_invoice_detail.py | 2 +-
.../cash_flow_mapping/cash_flow_mapping.py | 2 -
.../cashier_closing/cashier_closing.py | 2 +-
.../cheque_print_template.js | 10 +--
.../doctype/cost_center/cost_center.py | 2 +-
.../cost_center/cost_center_dashboard.py | 2 +-
.../doctype/cost_center/cost_center_tree.js | 2 +-
.../doctype/cost_center/test_cost_center.py | 3 -
.../doctype/coupon_code/coupon_code.py | 2 +-
.../doctype/coupon_code/test_coupon_code.py | 3 -
.../discounted_invoice/discounted_invoice.py | 2 +-
.../doctype/dunning/dunning_dashboard.py | 2 +-
.../accounts/doctype/dunning/test_dunning.py | 2 +-
.../exchange_rate_revaluation.js | 4 +-
.../exchange_rate_revaluation.py | 4 +-
.../doctype/finance_book/test_finance_book.py | 2 +-
.../invoice_discounting_dashboard.py | 2 +-
.../invoice_discounting_list.js | 2 +-
.../doctype/journal_entry/regional/india.js | 2 +-
.../journal_entry/test_journal_entry.py | 2 +-
.../journal_entry_template.js | 2 +-
.../mode_of_payment/mode_of_payment.js | 2 +-
.../mode_of_payment/mode_of_payment.py | 1 -
.../monthly_distribution.py | 2 +-
.../monthly_distribution_dashboard.py | 2 +-
.../opening_invoice_creation_tool.js | 2 +-
.../opening_invoice_creation_tool.py | 1 -
.../doctype/payment_entry/payment_entry.py | 6 +-
.../payment_entry/payment_entry_list.js | 2 +-
.../test_payment_against_purchase_invoice.js | 2 +-
.../payment_entry/tests/test_payment_entry.js | 2 +-
.../tests/test_payment_entry_write_off.js | 2 +-
.../payment_gateway_account.py | 10 +--
.../doctype/payment_order/payment_order.js | 2 +-
.../payment_order/payment_order_dashboard.py | 2 +-
.../payment_order/test_payment_order.py | 2 +-
.../payment_reconciliation.py | 2 +-
.../payment_request/payment_request.py | 2 +-
.../payment_request/test_payment_request.py | 2 +-
.../doctype/payment_term/payment_term.js | 2 +-
.../payment_terms_template.js | 2 +-
.../payment_terms_template_dashboard.py | 2 +-
.../period_closing_voucher.py | 4 +-
.../test_period_closing_voucher.py | 2 +-
.../pos_closing_entry/pos_closing_entry.js | 6 +-
.../pos_invoice_merge_log.js | 6 +-
.../pos_invoice_merge_log.py | 2 +-
.../test_pos_invoice_merge_log.py | 1 -
.../pos_opening_entry/pos_opening_entry.js | 2 +-
.../pos_opening_entry/pos_opening_entry.py | 2 +-
.../test_pos_opening_entry.py | 6 +-
.../doctype/pos_settings/pos_settings.py | 2 +-
.../doctype/pricing_rule/test_pricing_rule.py | 2 +-
.../pricing_rule/tests/test_pricing_rule.js | 1 -
.../process_deferred_accounting.py | 2 +-
.../test_process_deferred_accounting.py | 2 +-
.../process_statement_of_accounts.py | 2 +-
.../promotional_scheme/promotional_scheme.js | 2 +-
.../promotional_scheme_dashboard.py | 2 +-
.../test_promotional_scheme.py | 12 +--
.../purchase_invoice/purchase_invoice.js | 2 +-
.../purchase_invoice_dashboard.py | 2 +-
.../purchase_invoice/purchase_invoice_list.js | 2 +-
.../purchase_invoice/test_purchase_invoice.js | 1 -
.../purchase_invoice_advance.py | 2 +-
.../purchase_taxes_and_charges.py | 2 +-
...se_taxes_and_charges_template_dashboard.py | 2 +-
...est_purchase_taxes_and_charges_template.js | 1 -
.../sales_invoice/regional/india_list.js | 8 +-
.../doctype/sales_invoice/regional/italy.js | 2 +-
.../sales_invoice/sales_invoice_dashboard.py | 2 +-
.../sales_invoice/tests/test_sales_invoice.js | 1 -
.../tests/test_sales_invoice_with_margin.js | 1 -
.../tests/test_sales_invoice_with_payment.js | 1 -
...test_sales_invoice_with_payment_request.js | 1 -
.../test_sales_invoice_with_serialize_item.js | 1 -
.../sales_invoice_advance.py | 2 +-
.../sales_taxes_and_charges.py | 2 +-
...es_taxes_and_charges_template_dashboard.py | 2 +-
.../test_sales_taxes_and_charges_template.js | 1 -
.../doctype/share_transfer/share_transfer.js | 2 +-
.../doctype/share_transfer/share_transfer.py | 2 +-
.../shipping_rule/test_shipping_rule.js | 1 -
.../tests/test_shipping_rule_for_buying.js | 1 -
.../shipping_rule_condition.py | 2 +-
.../doctype/subscription/subscription_list.js | 2 +-
.../doctype/subscription/test_subscription.py | 2 -
.../subscription_plan/subscription_plan.js | 2 +-
.../subscription_plan/subscription_plan.py | 2 +-
erpnext/accounts/doctype/tax_rule/tax_rule.py | 2 +-
.../tax_withholding_category.py | 4 +-
.../test_tax_withholding_category.py | 2 +-
.../bank_and_cash_payment_voucher.html | 2 +-
.../gst_e_invoice/gst_e_invoice.html | 2 +-
.../journal_auditing_voucher.html | 2 +-
.../payment_receipt_voucher.html | 1 -
.../purchase_auditing_voucher.html | 2 +-
.../sales_auditing_voucher.html | 2 +-
.../account_balance/test_account_balance.py | 5 --
.../accounts_payable/accounts_payable.js | 1 -
.../accounts_payable_summary.js | 1 -
.../accounts_payable_summary.py | 1 -
.../accounts_receivable.js | 1 -
.../test_accounts_receivable.py | 1 -
.../accounts_receivable_summary.py | 2 +-
.../report/balance_sheet/balance_sheet.py | 2 +-
.../bank_clearance_summary.js | 2 +-
.../bank_clearance_summary.py | 12 +--
.../bank_reconciliation_statement.js | 2 +-
.../billed_items_to_be_received.py | 2 +-
.../budget_variance_report.js | 1 -
.../budget_variance_report.py | 5 +-
.../accounts/report/cash_flow/cash_flow.html | 2 +-
.../accounts/report/cash_flow/cash_flow.js | 2 +-
.../consolidated_financial_statement.js | 6 +-
.../delivered_items_to_be_billed.py | 2 +-
.../report/general_ledger/general_ledger.js | 1 -
.../report/general_ledger/general_ledger.py | 4 +-
.../gross_and_net_profit_report.html | 2 +-
.../gross_and_net_profit_report.py | 2 +-
.../item_wise_sales_register.py | 4 -
erpnext/accounts/report/non_billed_report.py | 2 +-
.../payment_period_based_on_invoice_date.py | 2 +-
.../report/pos_register/pos_register.py | 30 ++++----
.../profitability_analysis.html | 2 +-
.../purchase_invoice_trends.js | 2 +-
.../purchase_invoice_trends.py | 2 +-
.../purchase_register/purchase_register.js | 2 +-
.../received_items_to_be_billed.py | 2 +-
.../sales_invoice_trends.js | 2 +-
.../sales_payment_summary.js | 2 +-
.../test_sales_payment_summary.py | 2 +-
.../report/sales_register/sales_register.js | 1 -
.../supplier_ledger_summary.py | 2 +-
.../report/trial_balance/trial_balance.js | 3 -
.../report/trial_balance/trial_balance.py | 2 +-
.../trial_balance_for_party.py | 2 +-
.../unpaid_expense_claim.py | 4 +-
erpnext/agriculture/doctype/crop/crop.js | 2 +-
.../doctype/crop/crop_dashboard.py | 2 +-
erpnext/agriculture/doctype/crop/test_crop.js | 2 +-
erpnext/agriculture/doctype/crop/test_crop.py | 2 +-
.../doctype/crop_cycle/test_crop_cycle.js | 2 +-
.../agriculture/doctype/disease/disease.py | 2 +-
.../doctype/disease/test_disease.js | 1 -
.../doctype/disease/test_disease.py | 2 +-
.../doctype/fertilizer/fertilizer.py | 2 +-
.../doctype/fertilizer/test_fertilizer.py | 2 +-
.../doctype/plant_analysis/plant_analysis.py | 2 +-
.../doctype/soil_analysis/soil_analysis.py | 2 +-
.../doctype/soil_texture/test_soil_texture.py | 2 +-
.../doctype/water_analysis/water_analysis.py | 2 +-
erpnext/agriculture/setup.py | 2 +-
erpnext/assets/dashboard_fixtures.py | 2 +-
erpnext/assets/doctype/asset/asset.js | 4 +-
.../assets/doctype/asset/asset_dashboard.py | 2 +-
erpnext/assets/doctype/asset/asset_list.js | 2 +-
erpnext/assets/doctype/asset/test_asset.py | 2 +-
.../doctype/asset_category/asset_category.py | 12 +--
.../asset_category/test_asset_category.py | 8 +-
.../asset_maintenance/asset_maintenance.js | 2 +-
.../asset_maintenance/asset_maintenance.py | 2 +-
.../test_asset_maintenance.py | 6 +-
.../asset_maintenance_log.js | 2 +-
.../doctype/asset_movement/asset_movement.js | 2 +-
.../doctype/asset_movement/asset_movement.py | 16 ++--
.../doctype/asset_repair/asset_repair.js | 4 +-
.../doctype/asset_repair/asset_repair.py | 10 +--
.../doctype/asset_repair/asset_repair_list.js | 1 -
.../doctype/asset_repair/test_asset_repair.py | 8 +-
.../test_asset_value_adjustment.py | 2 +-
.../assets/doctype/location/location_tree.js | 2 +-
.../fixed_asset_register.js | 2 +-
.../fixed_asset_register.py | 4 +-
.../buying_settings/buying_settings.js | 2 +-
.../doctype/purchase_order/purchase_order.py | 2 +-
.../doctype/purchase_order/regional/india.js | 2 +-
.../purchase_order/test_purchase_order.py | 2 +-
.../tests/test_purchase_order.js | 2 +-
.../tests/test_purchase_order_get_items.js | 2 +-
...hase_order_with_discount_on_grand_total.js | 2 +-
..._purchase_order_with_item_wise_discount.js | 2 +-
.../test_purchase_order_with_multi_uom.js | 2 +-
.../test_purchase_order_with_shipping_rule.js | 2 +-
...t_purchase_order_with_taxes_and_charges.js | 2 +-
.../purchase_order_item.py | 2 +-
.../purchase_order_item_supplied.py | 2 +-
.../purchase_receipt_item_supplied.py | 2 +-
.../request_for_quotation.py | 2 +-
.../request_for_quotation_dashboard.py | 2 +-
.../tests/test_request_for_quotation.js | 2 +-
.../test_request_for_quotation_for_status.js | 2 +-
.../buying/doctype/supplier/regional/india.js | 2 +-
.../buying/doctype/supplier/test_supplier.js | 2 +-
.../supplier_item_group.py | 2 +-
.../supplier_quotation/supplier_quotation.py | 2 +-
.../tests/test_supplier_quotation.js | 2 +-
...pplier_quotation_for_item_wise_discount.js | 2 +-
...upplier_quotation_for_taxes_and_charges.js | 2 +-
.../supplier_scorecard/supplier_scorecard.js | 2 -
.../supplier_scorecard_dashboard.py | 2 +-
.../test_supplier_scorecard.py | 1 -
.../test_supplier_scorecard_criteria.py | 2 +-
.../supplier_scorecard_period.py | 1 -
.../supplier_scorecard_standing.py | 2 +-
.../supplier_scorecard_variable.py | 2 +-
.../test_supplier_scorecard_variable.py | 2 +-
.../procurement_tracker.py | 2 +-
.../test_procurement_tracker.py | 2 +-
.../purchase_order_analysis.py | 1 -
.../purchase_order_trends.js | 2 +-
.../purchase_order_trends.py | 2 +-
.../subcontract_order_summary.py | 2 +-
.../test_subcontracted_item_to_be_received.py | 2 +-
...tracted_raw_materials_to_be_transferred.py | 2 +-
.../supplier_quotation_comparison.html | 2 +-
.../supplier_quotation_comparison.js | 2 +-
.../supplier_quotation_comparison.py | 2 +-
erpnext/buying/utils.py | 1 -
erpnext/commands/__init__.py | 2 +-
erpnext/controllers/accounts_controller.py | 22 +++---
erpnext/controllers/item_variant.py | 1 -
erpnext/controllers/subcontracting.py | 2 +-
.../crm/doctype/appointment/appointment.py | 1 -
.../appointment_booking_settings.js | 2 +-
erpnext/crm/doctype/contract/contract.js | 4 +-
erpnext/crm/doctype/contract/contract_list.js | 2 +-
.../contract_template/contract_template.py | 6 +-
erpnext/crm/doctype/lead/lead.py | 2 +-
erpnext/crm/doctype/lead/lead_dashboard.py | 2 +-
erpnext/crm/doctype/lead/test_lead.py | 2 +-
.../crm/doctype/opportunity/opportunity.js | 2 +-
.../crm/doctype/opportunity/opportunity.py | 2 +-
.../opportunity/opportunity_dashboard.py | 2 +-
.../doctype/opportunity/test_opportunity.py | 2 +-
.../social_media_post/social_media_post.js | 6 +-
.../campaign_efficiency.js | 1 -
.../campaign_efficiency.py | 2 +-
.../lead_conversion_time.js | 2 -
.../crm/report/lead_details/lead_details.js | 2 +-
.../crm/report/lead_details/lead_details.py | 7 +-
.../lost_opportunity/lost_opportunity.js | 2 +-
.../lost_opportunity/lost_opportunity.py | 26 +++----
.../prospects_engaged_but_not_converted.py | 2 +-
erpnext/demo/domains.py | 2 +-
erpnext/demo/user/education.py | 12 +--
erpnext/domains/agriculture.py | 2 +-
erpnext/domains/education.py | 2 +-
erpnext/domains/manufacturing.py | 2 +-
erpnext/domains/non_profit.py | 2 +-
erpnext/domains/services.py | 2 +-
.../doctype/academic_term/academic_term.py | 4 +-
.../academic_term/academic_term_dashboard.py | 2 +-
.../academic_term/test_academic_term.js | 2 +-
.../doctype/academic_year/academic_year.js | 2 +-
.../academic_year/academic_year_dashboard.py | 2 +-
.../academic_year/test_academic_year.js | 2 +-
erpnext/education/doctype/article/article.js | 2 +-
erpnext/education/doctype/article/article.py | 2 +-
.../assessment_criteria.py | 2 +-
.../test_assessment_criteria.js | 2 +-
.../test_assessment_criteria_group.js | 2 +-
.../assessment_group_dashboard.py | 2 +-
.../assessment_group/assessment_group_tree.js | 4 +-
.../assessment_group/test_assessment_group.js | 2 +-
.../assessment_plan/assessment_plan.js | 2 +-
.../assessment_plan_dashboard.py | 2 +-
.../assessment_result/assessment_result.js | 2 +-
.../assessment_result/assessment_result.py | 4 -
.../assessment_result_dashboard.py | 2 +-
.../test_assessment_result.js | 2 +-
.../test_assessment_result.py | 1 -
.../assessment_result_tool.py | 2 +-
.../test_assessment_result_tool.js | 2 +-
erpnext/education/doctype/course/course.js | 2 +-
erpnext/education/doctype/course/course.py | 2 +-
.../doctype/course/course_dashboard.py | 2 +-
.../education/doctype/course/test_course.js | 2 +-
.../course_activity/course_activity.py | 2 +-
.../course_enrollment_dashboard.py | 2 +-
.../test_course_enrollment.py | 3 -
.../course_schedule/course_schedule.js | 2 +-
.../course_schedule/course_schedule.py | 13 ++--
.../course_schedule_dashboard.py | 2 +-
.../course_schedule/test_course_schedule.py | 20 ++---
.../course_scheduling_tool.js | 2 +-
.../education_settings/education_settings.py | 2 +-
.../doctype/fee_schedule/fee_schedule.js | 2 +-
.../fee_schedule/fee_schedule_dashboard.py | 2 +-
.../doctype/fee_structure/fee_structure.js | 2 +-
.../doctype/fee_structure/fee_structure.py | 6 +-
.../fee_structure/fee_structure_dashboard.py | 2 +-
erpnext/education/doctype/fees/fees.py | 2 +-
erpnext/education/doctype/fees/fees_list.js | 2 +-
.../doctype/grading_scale/grading_scale.py | 2 +-
.../grading_scale/test_grading_scale.js | 2 +-
.../doctype/guardian/test_guardian.js | 2 +-
.../doctype/instructor/instructor.js | 2 +-
.../instructor/instructor_dashboard.py | 2 +-
erpnext/education/doctype/program/program.js | 4 +-
erpnext/education/doctype/program/program.py | 2 +-
.../doctype/program/program_dashboard.py | 2 +-
.../education/doctype/program/test_program.js | 2 +-
.../education/doctype/program/test_program.py | 2 +-
.../program_enrollment/program_enrollment.js | 2 +-
.../program_enrollment/program_enrollment.py | 1 -
.../program_enrollment_dashboard.py | 2 +-
.../test_program_enrollment.py | 2 +-
.../education/doctype/question/question.py | 2 +-
erpnext/education/doctype/quiz/quiz.js | 2 +-
erpnext/education/doctype/quiz/quiz.py | 2 +-
erpnext/education/doctype/room/room.js | 2 +-
.../education/doctype/room/room_dashboard.py | 2 +-
erpnext/education/doctype/student/student.js | 2 +-
.../education/doctype/student/student_list.js | 2 +-
.../education/doctype/student/test_student.py | 2 +-
.../templates/student_admission_row.html | 2 +-
.../test_student_admission.js | 2 +-
.../student_applicant/student_applicant.js | 2 +-
.../student_applicant/student_applicant.py | 2 +-
.../student_applicant_list.js | 2 +-
.../tests/test_student_applicant.js | 2 +-
.../test_student_applicant_dummy_data.js | 2 +-
.../tests/test_student_applicant_options.js | 2 +-
.../student_attendance/student_attendance.js | 2 +-
.../student_attendance_dashboard.py | 2 +-
.../student_attendance_list.js | 2 +-
.../test_student_attendance.js | 2 +-
.../student_attendance_tool.py | 2 +-
.../test_student_attendance_tool.js | 2 +-
.../doctype/student_group/student_group.js | 2 +-
.../doctype/student_group/student_group.py | 1 -
.../student_group/student_group_dashboard.py | 2 +-
.../student_group/test_student_group.js | 2 +-
.../student_group_creation_tool.js | 2 +-
.../student_group_creation_tool.py | 2 +-
.../test_student_group_creation_tool.js | 2 +-
.../student_group_student.py | 2 +-
.../student_leave_application_dashboard.py | 2 +-
.../test_student_leave_application.js | 2 +-
.../test_student_leave_application.py | 2 +-
.../doctype/student_log/test_student_log.js | 2 +-
.../student_report_generation_tool.html | 74 +++++++++----------
erpnext/education/doctype/topic/topic.js | 2 +-
erpnext/education/doctype/topic/topic.py | 2 +-
.../program_wise_fee_collection.py | 1 -
.../student_batch_wise_attendance.js | 2 +-
.../student_batch_wise_attendance.py | 2 +-
.../student_monthly_attendance_sheet.js | 2 +-
.../student_applicant/student_applicant.js | 2 +-
.../amazon_mws_settings.js | 1 -
.../doctype/amazon_mws_settings/xml_utils.py | 2 +-
.../exotel_settings/exotel_settings.py | 2 +-
.../mpesa_settings/account_balance.html | 2 +-
.../doctype/mpesa_settings/mpesa_connector.py | 2 +-
.../mpesa_settings/mpesa_custom_fields.py | 2 +-
.../doctype/mpesa_settings/mpesa_settings.py | 2 +-
.../mpesa_settings/test_mpesa_settings.py | 2 +-
.../doctype/plaid_settings/plaid_connector.py | 2 +-
.../doctype/plaid_settings/plaid_settings.js | 2 +-
.../doctype/plaid_settings/plaid_settings.py | 2 +-
.../tally_migration/tally_migration.js | 2 +-
.../woocommerce_settings.py | 4 +-
.../stripe_integration.py | 2 +-
erpnext/erpnext_integrations/utils.py | 2 +-
.../department_wise_patient_appointments.js | 2 +-
.../department_wise_patient_appointments.py | 2 +-
.../appointment_type/appointment_type.js | 2 +-
.../test_clinical_procedure.py | 2 +-
.../clinical_procedure_template.js | 1 -
.../clinical_procedure_template.py | 1 -
.../doctype/exercise_type/exercise_type.py | 1 -
.../doctype/fee_validity/fee_validity.py | 2 +-
.../doctype/fee_validity/test_fee_validity.py | 2 +-
.../healthcare_practitioner.js | 1 -
.../test_healthcare_service_unit_type.py | 2 +-
.../test_inpatient_medication_entry.py | 2 +-
.../test_inpatient_medication_order.py | 1 -
.../test_patient_appointment.py | 2 +-
.../patient_assessment/patient_assessment.py | 3 -
.../patient_encounter/patient_encounter.py | 2 +-
.../patient_history_settings.py | 2 +-
.../test_patient_medical_record.py | 2 +-
.../therapy_plan_template.py | 2 +-
.../therapy_session/therapy_session.js | 2 +-
.../doctype/therapy_type/test_therapy_type.py | 2 +-
.../doctype/vital_signs/vital_signs.py | 1 -
.../page/patient_history/patient_history.html | 2 +-
.../patient_progress/patient_progress.html | 2 +-
.../page/patient_progress/patient_progress.js | 2 +-
.../page/patient_progress/patient_progress.py | 1 -
.../patient_progress_sidebar.html | 2 +-
.../inpatient_medication_orders.py | 2 +-
.../patient_appointment_analytics.py | 2 +-
erpnext/healthcare/setup.py | 2 +-
.../patient_registration.js | 2 +-
.../hotels/doctype/hotel_room/hotel_room.py | 2 +-
.../hotel_room_reservation_calendar.js | 2 +-
.../hotel_room_occupancy.py | 2 +-
erpnext/hr/doctype/appraisal/appraisal.js | 2 +-
.../hr/doctype/appraisal/test_appraisal.js | 1 -
.../doctype/appraisal_goal/appraisal_goal.py | 2 +-
.../appraisal_template_dashboard.py | 2 +-
.../test_appraisal_template.js | 1 -
.../appraisal_template_goal.py | 2 +-
.../doctype/attendance/attendance_calendar.js | 2 +-
.../hr/doctype/attendance/test_attendance.js | 2 +-
.../attendance_request_dashboard.py | 2 +-
erpnext/hr/doctype/branch/branch.py | 2 +-
erpnext/hr/doctype/branch/test_branch.js | 2 +-
erpnext/hr/doctype/branch/test_branch.py | 2 +-
.../test_daily_work_summary.js | 2 +-
.../hr/doctype/department/department_tree.js | 2 +-
.../hr/doctype/department/test_department.js | 2 +-
.../hr/doctype/department/test_department.py | 2 +-
erpnext/hr/doctype/designation/designation.py | 2 +-
.../doctype/designation/test_designation.js | 2 +-
.../doctype/designation/test_designation.py | 2 +-
erpnext/hr/doctype/employee/employee.py | 2 +-
erpnext/hr/doctype/employee/employee_tree.js | 2 +-
erpnext/hr/doctype/employee/test_employee.js | 2 +-
.../employee_advance/test_employee_advance.py | 2 +-
.../employee_attendance_tool.css | 2 +-
.../employee_attendance_tool.js | 2 -
.../test_employee_attendance_tool.js | 2 +-
.../employee_checkin/employee_checkin.py | 1 -
.../employee_checkin/test_employee_checkin.py | 4 +-
.../employee_education/employee_education.py | 2 +-
.../employee_external_work_history.py | 2 +-
.../employee_grade_dashboard.py | 2 +-
.../employee_grievance/employee_grievance.py | 1 -
.../employee_grievance_list.js | 2 +-
.../test_employee_grievance.py | 1 -
.../employee_group/test_employee_group.py | 2 +-
.../employee_internal_work_history.py | 2 +-
.../employee_onboarding.py | 1 -
.../test_employee_onboarding.py | 2 +-
.../employee_onboarding_template_dashboard.py | 2 +-
.../employee_referral/employee_referral.py | 1 -
.../employee_referral_dashboard.py | 2 +-
.../employee_referral_list.js | 2 +-
.../test_employee_referral.py | 2 +-
.../test_employee_separation.py | 2 +-
.../employee_separation_template_dashboard.py | 2 +-
.../employment_type/employment_type.py | 2 +-
.../employment_type/test_employment_type.js | 2 +-
.../employment_type/test_employment_type.py | 2 +-
.../hr/doctype/expense_claim/expense_claim.js | 2 +-
.../expense_claim/expense_claim_dashboard.py | 2 +-
.../expense_claim/test_expense_claim.js | 1 -
.../expense_claim/test_expense_claim.py | 2 +-
.../expense_claim_detail.py | 2 +-
.../expense_claim_type/expense_claim_type.py | 2 +-
.../test_expense_claim_type.js | 1 -
erpnext/hr/doctype/holiday/holiday.py | 2 +-
.../holiday_list/holiday_list_dashboard.py | 2 +-
.../doctype/holiday_list/test_holiday_list.js | 2 +-
erpnext/hr/doctype/hr_settings/hr_settings.js | 2 +-
erpnext/hr/doctype/hr_settings/hr_settings.py | 1 -
.../hr/doctype/job_applicant/job_applicant.js | 2 +-
.../hr/doctype/job_applicant/job_applicant.py | 1 -
.../job_applicant/job_applicant_dashboard.py | 2 +-
.../job_applicant/test_job_applicant.js | 1 -
.../hr/doctype/job_offer/test_job_offer.js | 2 +-
.../hr/doctype/job_offer/test_job_offer.py | 2 +-
.../job_opening/job_opening_dashboard.py | 2 +-
.../templates/job_opening_row.html | 6 +-
.../doctype/job_opening/test_job_opening.js | 1 -
.../leave_allocation/leave_allocation.js | 2 +-
.../leave_allocation_dashboard.py | 2 +-
.../leave_allocation/test_leave_allocation.js | 2 +-
.../leave_application_calendar.js | 2 +-
.../leave_application_dashboard.py | 2 +-
.../leave_application_email_template.html | 2 +-
.../test_leave_application.js | 2 +-
.../leave_block_list_dashboard.py | 2 +-
.../leave_block_list/test_leave_block_list.js | 2 +-
.../leave_block_list_allow.py | 2 +-
.../leave_block_list_date.py | 2 +-
.../leave_control_panel.js | 2 +-
.../test_leave_control_panel.js | 2 +-
.../leave_encashment/leave_encashment.py | 2 +-
.../leave_ledger_entry/leave_ledger_entry.py | 2 +-
.../leave_period/leave_period_dashboard.py | 2 +-
.../doctype/leave_period/test_leave_period.py | 2 +-
.../leave_policy/leave_policy_dashboard.py | 2 +-
.../doctype/leave_policy/test_leave_policy.py | 2 +-
.../leave_policy_assignment_dashboard.py | 2 +-
.../leave_policy_assignment_list.js | 2 +-
.../test_leave_policy_assignment.py | 2 -
.../leave_type/leave_type_dashboard.py | 2 +-
.../hr/doctype/leave_type/test_leave_type.js | 2 +-
.../hr/doctype/leave_type/test_leave_type.py | 2 +-
.../shift_assignment_calendar.js | 2 +-
.../shift_assignment/test_shift_assignment.py | 2 +-
.../hr/doctype/shift_request/shift_request.py | 2 +-
.../shift_request/shift_request_dashboard.py | 2 +-
.../shift_request/test_shift_request.py | 2 +-
.../staffing_plan/staffing_plan_dashboard.py | 2 +-
.../staffing_plan/test_staffing_plan.py | 2 +-
.../training_event/test_training_event.py | 2 +-
.../tests/test_training_event.js | 2 +-
.../doctype/training_event/training_event.js | 1 -
.../training_event_dashboard.py | 2 +-
.../test_training_feedback.js | 1 -
.../test_training_feedback.py | 2 +-
.../training_feedback/training_feedback.js | 2 +-
.../training_feedback/training_feedback.py | 1 -
.../training_program/training_program.js | 2 +-
.../training_program_dashboard.py | 2 +-
.../training_result/training_result.js | 2 +-
.../test_training_result.js | 1 -
.../hr/doctype/vehicle/vehicle_dashboard.py | 2 +-
.../doctype/vehicle_log/test_vehicle_log.py | 2 +-
erpnext/hr/doctype/vehicle_log/vehicle_log.js | 1 -
.../training_feedback/training_feedback.html | 2 +-
.../training_scheduled.html | 2 +-
.../organizational_chart.js | 2 +-
.../organizational_chart.py | 2 +-
erpnext/hr/page/team_updates/team_updates.py | 2 +-
.../standard_appointment_letter.html | 2 +-
.../daily_work_summary_replies.py | 2 +-
.../employee_advance_summary.js | 1 -
.../employee_analytics/employee_analytics.py | 1 -
.../employee_birthday/employee_birthday.js | 4 +-
.../recruitment_analytics.js | 2 +-
.../vehicle_expenses/vehicle_expenses.js | 1 -
erpnext/hr/utils.py | 2 +-
.../job_application/job_application.js | 2 +-
.../top_10_pledged_loan_securities.js | 2 +-
.../top_10_pledged_loan_securities.py | 2 +-
.../doctype/loan/loan_dashboard.py | 2 +-
.../loan_management/doctype/loan/test_loan.py | 2 +-
.../loan_application_dashboard.py | 2 +-
.../loan_disbursement/loan_disbursement.py | 2 -
.../loan_interest_accrual.py | 1 -
.../doctype/loan_repayment/loan_repayment.py | 3 -
.../loan_security/loan_security_dashboard.py | 2 +-
.../loan_security_pledge.js | 2 +-
.../loan_security_price.py | 9 ---
.../loan_security_shortfall.py | 1 -
.../loan_security_type_dashboard.py | 2 +-
.../loan_security_unpledge.py | 5 --
.../doctype/loan_type/loan_type.py | 1 -
.../doctype/loan_type/loan_type_dashboard.py | 2 +-
.../doctype/loan_write_off/loan_write_off.py | 2 -
.../process_loan_interest_accrual.py | 1 -
...process_loan_interest_accrual_dashboard.py | 2 +-
...ocess_loan_security_shortfall_dashboard.py | 2 +-
erpnext/loan_management/loan_common.js | 2 +-
.../applicant_wise_loan_security_exposure.py | 2 +-
.../loan_interest_report.py | 2 +-
.../loan_repayment_and_closure.py | 2 +-
.../loan_security_exposure.py | 3 -
.../maintenance_schedule.js | 9 +--
.../maintenance_schedule.py | 14 ++--
.../test_maintenance_schedule.py | 4 +-
.../maintenance_visit/maintenance_visit.py | 4 +-
.../doctype/blanket_order/blanket_order.js | 2 -
.../doctype/blanket_order/blanket_order.py | 2 +-
.../blanket_order/test_blanket_order.py | 2 +-
.../doctype/bom/bom_item_preview.html | 2 +-
erpnext/manufacturing/doctype/bom/bom_tree.js | 2 +-
erpnext/manufacturing/doctype/bom/test_bom.js | 2 +-
.../bom_explosion_item/bom_explosion_item.py | 2 +-
.../doctype/bom_item/bom_item.py | 2 +-
.../doctype/bom_operation/bom_operation.py | 2 +-
.../bom_update_tool/bom_update_tool.js | 2 +-
.../doctype/job_card/job_card.js | 2 +-
.../doctype/job_card/job_card_list.js | 2 +-
.../doctype/job_card/test_job_card.py | 2 +-
.../manufacturing_settings.js | 2 +-
.../manufacturing_settings.py | 2 +-
.../doctype/operation/operation.js | 2 +-
.../doctype/operation/test_operation.py | 2 +-
.../production_plan_dashboard.py | 2 +-
.../production_plan_item.py | 2 +-
.../production_plan_sales_order.py | 2 +-
.../doctype/routing/routing_dashboard.py | 2 +-
.../work_order/work_order_dashboard.py | 2 +-
.../work_order/work_order_preview.html | 2 +-
.../work_order_item/work_order_item.py | 2 +-
.../doctype/workstation/workstation.js | 2 +-
.../bom_operations_time.py | 2 -
.../bom_stock_report/bom_stock_report.html | 2 +-
.../cost_of_poor_quality_report.py | 2 +-
.../downtime_analysis/downtime_analysis.py | 2 +-
.../exponential_smoothing_forecasting.py | 2 +-
.../job_card_summary/job_card_summary.py | 2 +-
.../production_analytics.py | 4 -
.../quality_inspection_summary.py | 2 +-
.../work_order_stock_report.py | 8 +-
.../work_order_summary/work_order_summary.py | 2 +-
.../doctype/chapter_member/chapter_member.py | 2 -
.../non_profit/doctype/donation/donation.py | 1 -
.../doctype/donation/donation_dashboard.py | 2 +-
.../doctype/donation/test_donation.py | 2 +-
erpnext/non_profit/doctype/donor/donor.py | 1 -
.../grant_application/grant_application.py | 2 +-
erpnext/non_profit/doctype/member/member.js | 2 +-
.../doctype/membership/test_membership.py | 2 +-
.../membership_type/membership_type.py | 2 +-
.../non_profit_settings.py | 2 +-
.../grant_application/grant_application.js | 2 +-
.../grant_application/grant_application.py | 2 -
...ry_settings_to_daily_work_summary_group.py | 2 +-
.../v10_0/rename_offer_letter_to_job_offer.py | 2 +-
.../rename_price_to_rate_in_pricing_rule.py | 2 +-
.../add_default_email_template_for_leave.py | 1 -
.../add_expense_claim_default_account.py | 2 +-
.../add_healthcare_service_unit_tree_root.py | 1 -
.../v11_0/add_index_on_nestedset_doctypes.py | 2 +-
erpnext/patches/v11_0/add_market_segments.py | 2 +-
erpnext/patches/v11_0/add_sales_stages.py | 2 +-
...eck_buying_selling_in_currency_exchange.py | 2 +-
.../create_salary_structure_assignments.py | 2 +-
.../v11_0/drop_column_max_days_allowed.py | 2 +-
.../v11_0/ewaybill_fields_gst_india.py | 2 +-
erpnext/patches/v11_0/hr_ux_cleanups.py | 1 -
..._asset_finance_book_against_old_entries.py | 2 +-
.../v11_0/make_location_from_warehouse.py | 1 -
...efaults_to_child_table_for_multicompany.py | 2 +-
.../move_leave_approvers_from_employee.py | 2 +-
.../patches/v11_0/refactor_autoname_naming.py | 2 +-
.../patches/v11_0/refactor_naming_series.py | 2 +-
.../v11_0/rename_asset_adjustment_doctype.py | 2 +-
erpnext/patches/v11_0/rename_bom_wo_fields.py | 2 +-
.../patches/v11_0/rename_health_insurance.py | 2 +-
.../rename_overproduction_percent_field.py | 2 +-
.../renamed_from_to_fields_in_project.py | 2 +-
.../patches/v11_0/set_missing_gst_hsn_code.py | 2 +-
.../v11_0/set_salary_component_properties.py | 2 +-
.../set_user_permissions_for_department.py | 4 +-
...ip_user_permission_check_for_department.py | 2 +-
.../update_account_type_in_party_type.py | 2 +-
.../update_allow_transfer_for_manufacture.py | 2 +-
...e_backflush_subcontract_rm_based_on_bom.py | 2 +-
.../v11_0/update_brand_in_item_price.py | 2 +-
.../v11_0/update_department_lft_rgt.py | 2 +-
erpnext/patches/v11_1/delete_bom_browser.py | 2 +-
.../patches/v11_1/make_job_card_time_logs.py | 2 +-
.../move_customer_lead_to_dynamic_column.py | 2 +-
.../patches/v11_1/rename_depends_on_lwp.py | 2 +-
.../v11_1/renamed_delayed_item_report.py | 2 +-
...s_for_material_request_type_manufacture.py | 2 +-
erpnext/patches/v11_1/set_variant_based_on.py | 2 +-
.../v11_1/update_bank_transaction_status.py | 2 +-
...pdate_default_supplier_in_item_defaults.py | 2 +-
.../v11_1/woocommerce_set_creation_user.py | 2 +-
.../add_company_link_to_einvoice_settings.py | 2 +-
...default_buying_selling_terms_in_company.py | 2 +-
...ocument_type_field_for_italy_einvoicing.py | 2 +-
.../v12_0/add_einvoice_status_field.py | 8 +-
...add_einvoice_summary_report_permissions.py | 2 +-
.../v12_0/add_eway_bill_in_delivery_note.py | 2 +-
.../v12_0/add_ewaybill_validity_field.py | 2 +-
.../add_export_type_field_in_party_master.py | 2 -
.../add_gst_category_in_delivery_note.py | 2 +-
.../v12_0/add_item_name_in_work_orders.py | 2 +-
.../add_permission_in_lower_deduction.py | 2 +-
...counting_dimensions_in_missing_doctypes.py | 2 +-
.../create_default_energy_point_rules.py | 2 +-
.../create_irs_1099_field_united_states.py | 2 +-
.../create_itc_reversal_custom_fields.py | 2 +-
.../v12_0/create_taxable_value_field.py | 2 +-
.../v12_0/delete_priority_property_setter.py | 2 +-
.../v12_0/fix_quotation_expired_status.py | 12 +--
...arget_distribution_from_parent_to_child.py | 2 +-
.../v12_0/recalculate_requested_qty_in_bin.py | 2 +-
.../remove_bank_remittance_custom_fields.py | 2 +-
.../remove_denied_leaves_from_leave_ledger.py | 2 +-
.../remove_duplicate_leave_ledger_entries.py | 2 +-
.../v12_0/rename_account_type_doctype.py | 2 +-
..._account_field_in_journal_entry_account.py | 2 +-
.../v12_0/rename_lost_reason_detail.py | 2 +-
.../v12_0/rename_pos_closing_doctype.py | 6 +-
.../patches/v12_0/rename_tolerance_fields.py | 2 +-
...counting_with_accounts_in_home_settings.py | 2 +-
...ock_ledger_entries_for_target_warehouse.py | 3 -
...eferred_accounting_in_accounts_settings.py | 2 +-
..._center_in_child_table_of_expense_claim.py | 2 +-
.../set_cwip_and_delete_asset_settings.py | 4 +-
.../v12_0/set_default_homepage_type.py | 2 +-
.../v12_0/set_default_payroll_based_on.py | 2 +-
...se_account_in_landed_cost_voucher_taxes.py | 2 +-
erpnext/patches/v12_0/set_gst_category.py | 2 -
...ian_import_supplier_invoice_permissions.py | 2 +-
erpnext/patches/v12_0/set_multi_uom_in_rfq.py | 2 +-
.../patches/v12_0/set_payment_entry_status.py | 2 +-
.../patches/v12_0/set_priority_for_support.py | 2 +-
...qty_field_in_sales_order_for_work_order.py | 2 +-
.../set_production_capacity_in_workstation.py | 2 +-
erpnext/patches/v12_0/set_quotation_status.py | 2 +-
.../v12_0/set_updated_purpose_in_pick_list.py | 2 +-
.../patches/v12_0/setup_einvoice_fields.py | 4 +-
.../patches/v12_0/stock_entry_enhancements.py | 2 +-
.../patches/v12_0/unhide_cost_center_field.py | 2 +-
...te_appointment_reminder_scheduler_entry.py | 2 +-
erpnext/patches/v12_0/update_bom_in_so_mr.py | 2 +-
...e_end_date_and_status_in_email_campaign.py | 2 +-
.../v12_0/update_ewaybill_field_position.py | 2 +-
erpnext/patches/v12_0/update_gst_category.py | 2 +-
.../update_healthcare_refactored_changes.py | 2 +-
.../v12_0/update_is_cancelled_field.py | 2 +-
.../v12_0/update_item_tax_template_company.py | 2 +-
...r_fields_in_acc_dimension_custom_fields.py | 2 +-
.../update_price_list_currency_in_bom.py | 2 +-
.../update_state_code_for_daman_and_diu.py | 2 +-
.../v12_0/update_uom_conversion_factor.py | 2 +-
erpnext/patches/v13_0/add_doctype_to_sla.py | 2 +-
.../add_naming_series_to_old_projects.py | 1 -
.../v13_0/change_default_pos_print_format.py | 2 +-
.../v13_0/check_is_income_tax_component.py | 2 +-
.../convert_qi_parameter_to_link_field.py | 2 +-
...are_custom_fields_in_stock_entry_detail.py | 2 +-
..._based_on_employee_current_leave_policy.py | 3 -
.../v13_0/create_uae_pos_invoice_fields.py | 2 +-
.../v13_0/delete_old_purchase_reports.py | 2 +-
.../patches/v13_0/delete_old_sales_reports.py | 2 +-
.../patches/v13_0/delete_orphaned_tables.py | 8 +-
.../delete_report_requested_items_to_order.py | 2 +-
.../v13_0/drop_razorpay_payload_column.py | 2 +-
.../fix_non_unique_represents_company.py | 2 +-
.../germany_fill_debtor_creditor_number.py | 2 +-
.../item_reposting_for_incorrect_sl_and_gl.py | 2 +-
.../loyalty_points_entry_for_pos_invoice.py | 4 +-
.../v13_0/make_non_standard_user_type.py | 2 +-
.../v13_0/move_branch_code_to_bank_account.py | 2 +-
...itional_salary_encashment_and_incentive.py | 1 -
.../rename_issue_status_hold_to_on_hold.py | 2 +-
...bership_settings_to_non_profit_settings.py | 2 +-
...eplace_pos_page_with_point_of_sale_page.py | 2 +-
.../v13_0/replace_pos_payment_mode_table.py | 2 +-
.../set_company_in_leave_ledger_entry.py | 2 +-
...ment_channel_in_payment_gateway_account.py | 2 +-
.../v13_0/set_pos_closing_as_failed.py | 2 +-
.../v13_0/set_training_event_attendance.py | 2 +-
erpnext/patches/v13_0/set_youtube_video_id.py | 2 +-
..._custom_roles_for_some_regional_reports.py | 2 +-
..._history_settings_for_standard_doctypes.py | 2 +-
.../patches/v13_0/stock_entry_enhancements.py | 8 +-
.../update_actual_start_and_end_date_in_wo.py | 2 +-
...update_amt_in_work_order_required_items.py | 1 -
.../patches/v13_0/update_deferred_settings.py | 2 +-
.../v13_0/update_export_type_for_gst.py | 6 +-
.../patches/v13_0/update_job_card_details.py | 2 +-
.../v13_0/update_project_template_tasks.py | 2 +-
...date_reason_for_resignation_in_employee.py | 1 -
.../v13_0/update_returned_qty_in_pr_dn.py | 2 +-
erpnext/patches/v13_0/update_subscription.py | 2 +-
...date_subscription_status_in_memberships.py | 2 +-
.../patches/v13_0/update_tds_check_field.py | 2 +-
.../patches/v13_0/update_timesheet_changes.py | 2 +-
.../updates_for_multi_currency_payroll.py | 4 +-
...oles_from_gst_report_non_indian_account.py | 2 +-
erpnext/patches/v8_1/setup_gst_india.py | 2 +-
.../test_additional_salary.py | 2 +-
.../employee_benefit_application.py | 2 +-
.../employee_tax_exemption_sub_category.py | 2 +-
erpnext/payroll/doctype/gratuity/gratuity.js | 2 +-
erpnext/payroll/doctype/gratuity/gratuity.py | 1 -
.../doctype/gratuity/gratuity_dashboard.py | 2 +-
.../doctype/gratuity_rule/gratuity_rule.js | 2 +-
.../gratuity_rule/gratuity_rule_dashboard.py | 2 +-
.../payroll_entry/payroll_entry_dashboard.py | 2 +-
.../payroll_period_dashboard.py | 2 +-
.../doctype/salary_slip/test_salary_slip.js | 2 +-
.../condition_and_formula_help.html | 2 +-
.../salary_structure/salary_structure.py | 1 -
.../salary_structure_dashboard.py | 2 +-
.../salary_structure_assignment.py | 4 +-
erpnext/payroll/notification/as | 2 +-
.../report/bank_remittance/bank_remittance.js | 1 -
.../income_tax_deductions.js | 2 +-
.../salary_payments_based_on_payment_mode.js | 2 +-
erpnext/portal/doctype/homepage/homepage.py | 1 -
.../test_product_configurator.py | 2 +-
.../doctype/activity_cost/activity_cost.js | 2 +-
.../doctype/activity_cost/activity_cost.py | 2 +-
.../activity_cost/test_activity_cost.py | 2 +-
.../doctype/activity_type/activity_type.py | 2 +-
.../activity_type/test_activity_type.py | 2 +-
.../doctype/project/project_dashboard.html | 2 +-
.../project_template/project_template.py | 2 +-
.../project_template/test_project_template.py | 2 +-
.../doctype/project_type/project_type.js | 2 +-
.../doctype/project_type/project_type.py | 2 +-
.../doctype/project_update/project_update.py | 2 +-
.../project_update/test_project_update.py | 2 +-
erpnext/projects/doctype/task/task_tree.js | 2 +-
.../projects/doctype/timesheet/timesheet.css | 2 +-
.../projects/doctype/timesheet/timesheet.js | 2 +-
.../projects/doctype/timesheet/timesheet.py | 6 +-
.../doctype/timesheet/timesheet_calendar.js | 4 +-
.../doctype/timesheet/timesheet_dashboard.py | 2 +-
.../doctype/timesheet/timesheet_list.js | 6 +-
erpnext/projects/report/billing_summary.py | 2 +-
.../daily_timesheet_summary.py | 6 +-
.../test_delayed_tasks_summary.py | 6 +-
.../employee_billing_summary.py | 2 +-
.../test_employee_util.py | 2 +-
.../project_billing_summary.py | 2 +-
.../project_profitability.py | 2 +-
erpnext/projects/web_form/tasks/tasks.js | 2 +-
erpnext/projects/web_form/tasks/tasks.py | 2 +-
erpnext/public/images/erpnext-favicon.svg | 2 +-
erpnext/public/images/erpnext-logo.svg | 2 +-
erpnext/public/images/pos.svg | 2 +-
.../js/education/assessment_result_tool.html | 2 +-
.../public/js/education/student_button.html | 8 +-
erpnext/public/js/erpnext.bundle.js | 1 -
erpnext/public/js/financial_statements.js | 2 -
erpnext/public/js/hierarchy-chart.bundle.js | 2 +-
.../hierarchy_chart_desktop.js | 2 +-
.../hierarchy_chart/hierarchy_chart_mobile.js | 2 +-
.../public/js/hub/components/ReviewArea.vue | 2 +-
.../js/hub/components/ReviewTimelineItem.vue | 1 -
erpnext/public/js/hub/pages/FeaturedItems.vue | 2 +-
erpnext/public/js/hub/pages/Publish.vue | 2 +-
erpnext/public/js/hub/pages/Seller.vue | 4 +-
erpnext/public/js/hub/vue-plugins.js | 2 +-
erpnext/public/js/leaflet/leaflet.draw.js | 2 +-
erpnext/public/js/leaflet/leaflet.js | 2 +-
erpnext/public/js/projects/timer.js | 2 +-
erpnext/public/js/setup_wizard.js | 2 +-
erpnext/public/js/stock_analytics.js | 1 -
.../public/js/templates/item_quick_entry.html | 2 +-
.../public/js/templates/item_selector.html | 2 +-
erpnext/public/js/templates/node_card.html | 2 +-
.../public/js/utils/dimension_tree_filter.js | 2 +-
erpnext/public/scss/hierarchy_chart.scss | 2 +-
erpnext/public/scss/shopping_cart.scss | 1 -
erpnext/public/scss/website.scss | 2 +-
.../doctype/quality_action/quality_action.js | 2 +-
.../doctype/quality_action/quality_action.py | 2 +-
.../quality_action/test_quality_action.py | 2 +-
.../quality_feedback/quality_feedback.py | 1 -
.../test_quality_feedback_template.py | 2 +-
.../doctype/quality_goal/quality_goal.py | 2 +-
.../doctype/quality_goal/test_quality_goal.py | 2 +-
.../quality_meeting/quality_meeting.py | 2 +-
.../quality_meeting/quality_meeting_list.js | 2 +-
.../quality_meeting/test_quality_meeting.py | 2 +-
.../quality_procedure/quality_procedure.js | 2 +-
.../quality_procedure/quality_procedure.py | 2 +-
.../quality_procedure_tree.js | 2 +-
.../test_quality_procedure.py | 2 +-
.../doctype/quality_review/quality_review.js | 2 +-
.../doctype/quality_review/quality_review.py | 2 +-
.../quality_review/quality_review_list.js | 2 +-
.../quality_review/test_quality_review.py | 2 +-
erpnext/regional/address_template/setup.py | 2 +-
.../address_template/templates/germany.html | 2 +-
.../e_invoice_settings/e_invoice_settings.py | 1 -
.../doctype/gst_hsn_code/gst_hsn_code.js | 2 +-
.../doctype/gst_hsn_code/gst_hsn_code.py | 2 +-
.../gstr_3b_report/gstr_3b_report.html | 2 +-
.../import_supplier_invoice.js | 2 +-
.../lower_deduction_certificate.py | 4 +-
.../test_tax_exemption_80g_certificate.py | 2 +-
.../germany/utils/datev/datev_constants.py | 2 +-
erpnext/regional/india/e_invoice/einvoice.js | 2 +-
erpnext/regional/india/e_invoice/utils.py | 2 +-
erpnext/regional/india/taxes.js | 1 -
erpnext/regional/india/utils.py | 6 +-
erpnext/regional/italy/__init__.py | 2 +-
erpnext/regional/report/datev/datev.py | 4 +-
.../e_invoice_summary/e_invoice_summary.py | 40 +++++-----
.../electronic_invoice_register.js | 2 +-
.../regional/report/eway_bill/eway_bill.py | 2 +-
.../gst_purchase_register.js | 2 +-
.../gst_purchase_register.py | 1 -
.../hsn_wise_summary_of_outward_supplies.py | 2 -
.../india_gst_common/india_gst_common.js | 2 +-
erpnext/regional/report/irs_1099/irs_1099.py | 2 +-
.../professional_tax_deductions.js | 2 +-
.../professional_tax_deductions.py | 2 +-
.../provident_fund_deductions.js | 2 +-
.../provident_fund_deductions.py | 2 +-
.../report/uae_vat_201/uae_vat_201.html | 2 +-
.../vat_audit_report/vat_audit_report.py | 2 +-
erpnext/regional/south_africa/setup.py | 6 +-
erpnext/regional/turkey/setup.py | 2 +-
.../restaurant/restaurant_dashboard.py | 2 +-
.../doctype/restaurant/test_restaurant.js | 2 +-
.../restaurant_menu/restaurant_menu.py | 2 -
erpnext/selling/doctype/customer/customer.js | 1 -
.../doctype/customer/regional/india.js | 2 +-
.../doctype/industry_type/industry_type.js | 8 +-
.../doctype/industry_type/industry_type.py | 2 +-
.../industry_type/test_industry_type.py | 2 +-
.../installation_note_item.py | 2 +-
.../product_bundle/test_product_bundle.js | 1 -
.../doctype/quotation/quotation_dashboard.py | 2 +-
..._quotation_with_discount_on_grand_total.js | 1 -
.../test_quotation_with_item_wise_discount.js | 1 -
.../tests/test_quotation_with_margin.js | 1 -
.../tests/test_quotation_with_multi_uom.js | 1 -
.../test_quotation_with_taxes_and_charges.js | 1 -
.../sales_order/sales_order_dashboard.py | 2 +-
.../doctype/sales_order/test_sales_order.py | 4 +-
.../tests/test_sales_order_with_margin.js | 1 -
...sales_order_with_multiple_delivery_date.js | 2 +-
.../sales_order_item/sales_order_item.py | 2 +-
.../selling/doctype/sales_team/sales_team.py | 2 +-
.../selling_settings/selling_settings.js | 2 +-
.../selling/doctype/sms_center/sms_center.py | 1 -
.../page/point_of_sale/point_of_sale.py | 2 +-
.../page/point_of_sale/pos_controller.js | 5 +-
.../page/point_of_sale/pos_item_cart.js | 2 +-
.../page/point_of_sale/pos_item_details.js | 6 +-
.../page/point_of_sale/pos_item_selector.js | 2 +-
.../page/point_of_sale/pos_number_pad.js | 2 +-
.../page/point_of_sale/pos_past_order_list.js | 2 +-
.../point_of_sale/pos_past_order_summary.js | 2 +-
.../page/sales_funnel/sales_funnel.css | 2 +-
.../selling/page/sales_funnel/sales_funnel.py | 4 +-
.../address_and_contacts.py | 2 +-
.../available_stock_for_packing_items.py | 2 +-
.../customer_acquisition_and_loyalty.js | 2 +-
.../item_wise_sales_history.js | 2 +-
.../item_wise_sales_history.py | 2 +-
.../quotation_trends/quotation_trends.js | 1 -
.../report/sales_analytics/sales_analytics.js | 2 -
.../sales_order_analysis.py | 2 +-
.../sales_order_trends/sales_order_trends.js | 2 +-
.../sales_partner_commission_summary.py | 2 +-
.../item_group_wise_sales_target_variance.py | 2 +-
...ner_target_variance_based_on_item_group.js | 4 +-
...ner_target_variance_based_on_item_group.py | 1 -
.../sales_partner_transaction_summary.py | 2 +-
.../sales_person_commission_summary.py | 6 +-
...son_target_variance_based_on_item_group.js | 4 +-
...son_target_variance_based_on_item_group.py | 2 +-
.../sales_person_wise_transaction_summary.js | 2 +-
...ory_target_variance_based_on_item_group.js | 4 +-
erpnext/selling/sales_common.js | 4 +-
erpnext/setup/default_energy_point_rules.py | 1 -
erpnext/setup/default_success_action.py | 1 -
erpnext/setup/doctype/brand/brand.js | 8 +-
erpnext/setup/doctype/brand/brand.py | 2 +-
erpnext/setup/doctype/brand/test_brand.py | 2 +-
erpnext/setup/doctype/company/company.js | 1 -
erpnext/setup/doctype/company/company.py | 2 +-
.../doctype/company/company_dashboard.py | 2 +-
erpnext/setup/doctype/company/company_tree.js | 2 +-
erpnext/setup/doctype/company/test_company.py | 1 -
.../doctype/company/tests/test_company.js | 2 +-
.../company/tests/test_company_production.js | 2 +-
.../doctype/customer_group/customer_group.py | 2 +-
.../customer_group/customer_group_tree.js | 2 +-
.../customer_group/test_customer_group.py | 2 +-
.../doctype/email_digest/email_digest.js | 2 +-
erpnext/setup/doctype/email_digest/quotes.py | 1 -
.../email_digest/templates/default.html | 8 +-
.../doctype/item_group/item_group_tree.js | 2 +-
.../doctype/print_heading/print_heading.js | 8 +-
.../doctype/print_heading/print_heading.py | 2 +-
.../print_heading/test_print_heading.py | 2 +-
.../quotation_lost_reason.js | 8 +-
.../quotation_lost_reason.py | 2 +-
.../test_quotation_lost_reason.py | 2 +-
.../sales_person/sales_person_dashboard.py | 2 +-
.../doctype/sales_person/sales_person_tree.js | 2 +-
.../supplier_group/supplier_group_tree.js | 2 +-
.../doctype/target_detail/target_detail.py | 2 +-
.../terms_and_conditions.js | 8 +-
.../terms_and_conditions.py | 4 +-
erpnext/setup/doctype/territory/territory.js | 2 +-
erpnext/setup/doctype/territory/territory.py | 2 +-
.../setup/doctype/territory/territory_tree.js | 2 +-
.../test_transaction_deletion_record.py | 6 +-
.../transaction_deletion_record.js | 8 +-
.../transaction_deletion_record_list.js | 2 +-
erpnext/setup/doctype/uom/uom.js | 8 +-
erpnext/setup/doctype/uom/uom.py | 2 +-
.../website_item_group/website_item_group.py | 2 +-
.../setup_wizard/operations/sample_data.py | 2 +-
.../setup_wizard/operations/taxes_setup.py | 4 +-
.../shopping_cart_settings.py | 2 +-
.../test_shopping_cart_settings.py | 4 +-
erpnext/shopping_cart/product_info.py | 2 +-
erpnext/shopping_cart/search.py | 2 +-
erpnext/shopping_cart/utils.py | 2 +-
.../web_template/hero_slider/hero_slider.html | 2 +-
.../item_card_group/item_card_group.html | 2 +-
erpnext/startup/filters.py | 2 +-
erpnext/startup/leaderboard.py | 2 +-
erpnext/stock/dashboard/item_dashboard.html | 2 +-
.../dashboard/warehouse_capacity_dashboard.py | 2 +-
.../warehouse_wise_stock_value.js | 2 +-
.../warehouse_wise_stock_value.py | 2 +-
erpnext/stock/doctype/batch/test_batch.js | 1 -
.../delivery_note/delivery_note_dashboard.py | 2 +-
.../doctype/delivery_note/regional/india.js | 1 -
.../delivery_note/test_delivery_note.js | 1 -
.../delivery_note/test_delivery_note.py | 2 +-
.../test_delivery_note_with_margin.js | 1 -
.../delivery_note_item/delivery_note_item.py | 2 +-
.../doctype/delivery_trip/delivery_trip.py | 2 +-
.../dispatch_notification_template.html | 2 +-
erpnext/stock/doctype/item/item.py | 2 +-
erpnext/stock/doctype/item/regional/india.js | 2 +-
.../stock/doctype/item/templates/item.html | 2 +-
.../doctype/item/templates/item_row.html | 2 +-
erpnext/stock/doctype/item/tests/test_item.js | 2 +-
.../item_attribute/test_item_attribute.py | 1 -
.../item_customer_detail.py | 2 +-
.../item_manufacturer/item_manufacturer.py | 2 +-
.../item_quality_inspection_parameter.py | 2 +-
.../doctype/item_reorder/item_reorder.py | 2 +-
.../doctype/item_supplier/item_supplier.py | 2 +-
erpnext/stock/doctype/item_tax/item_tax.py | 2 +-
.../item_website_specification.py | 2 +-
.../landed_cost_item/landed_cost_item.py | 2 +-
.../landed_cost_purchase_receipt.py | 2 +-
.../landed_cost_taxes_and_charges.py | 2 +-
.../material_request_dashboard.py | 2 +-
.../tests/test_material_request.js | 1 -
.../tests/test_material_request_from_bom.js | 1 -
.../test_material_request_type_manufacture.js | 1 -
...st_material_request_type_material_issue.js | 1 -
...material_request_type_material_transfer.js | 1 -
.../material_request_item.py | 2 +-
.../packing_slip_item/packing_slip_item.py | 2 +-
erpnext/stock/doctype/pick_list/pick_list.js | 2 +-
.../doctype/pick_list/pick_list_dashboard.py | 2 +-
.../stock/doctype/price_list/price_list.css | 2 +-
.../stock/doctype/price_list/price_list.js | 2 +-
.../stock/doctype/price_list/price_list.py | 2 +-
.../doctype/price_list/test_price_list.py | 2 +-
.../doctype/price_list/test_price_list_uom.js | 2 +-
.../purchase_receipt/regional/india.js | 2 +-
.../doctype/putaway_rule/putaway_rule.py | 2 +-
.../doctype/putaway_rule/test_putaway_rule.py | 2 +-
.../quality_inspection/quality_inspection.js | 2 +-
.../quality_inspection_reading.py | 2 +-
.../quality_inspection_template.py | 2 +-
.../stock/doctype/serial_no/test_serial_no.py | 2 +-
erpnext/stock/doctype/shipment/shipment.js | 8 +-
.../stock/doctype/shipment/shipment_list.js | 2 +-
.../stock/doctype/shipment/test_shipment.py | 6 +-
.../test_stock_entry_for_material_issue.js | 1 -
..._for_material_issue_with_serialize_item.js | 1 -
.../test_stock_entry_for_material_receipt.js | 1 -
...for_material_receipt_for_serialize_item.js | 1 -
.../test_stock_entry_for_material_transfer.js | 1 -
...y_for_material_transfer_for_manufacture.js | 1 -
.../tests/test_stock_entry_for_repack.js | 1 -
.../tests/test_stock_entry_for_subcontract.js | 1 -
.../stock_entry_detail/stock_entry_detail.py | 2 +-
.../test_stock_reconciliation.js | 1 -
.../test_stock_reconciliation.py | 1 -
.../uom_conversion_detail.py | 2 +-
.../stock/doctype/warehouse/test_warehouse.js | 2 +-
.../stock/doctype/warehouse/test_warehouse.py | 2 +-
erpnext/stock/doctype/warehouse/warehouse.js | 8 +-
.../stock/doctype/warehouse/warehouse_tree.js | 2 +-
.../stock/landed_taxes_and_charges_common.js | 1 -
.../warehouse_capacity_summary.html | 2 +-
.../warehouse_capacity_summary_header.html | 2 +-
.../batch_item_expiry_status.py | 4 +-
.../cogs_by_item_group/cogs_by_item_group.py | 4 +-
.../delayed_item_report.py | 2 +-
.../delayed_order_report.py | 2 +-
.../delivery_note_trends.js | 1 -
.../delivery_note_trends.py | 2 +-
...incorrect_balance_qty_after_transaction.py | 2 +-
.../incorrect_serial_no_valuation.py | 2 +-
.../incorrect_stock_value_report.py | 2 +-
.../item_price_stock/item_price_stock.js | 2 +-
.../item_shortage_report.py | 2 -
.../itemwise_recommended_reorder_level.js | 2 +-
.../purchase_receipt_trends.js | 1 -
.../purchase_receipt_trends.py | 2 +-
.../serial_no_ledger/serial_no_ledger.py | 1 -
.../stock/report/stock_ageing/stock_ageing.js | 2 +-
.../report/stock_analytics/stock_analytics.py | 4 -
.../stock_and_account_value_comparison.py | 2 +-
.../stock_projected_qty.py | 2 +-
.../stock_qty_vs_serial_no_count.py | 8 +-
.../supplier_wise_sales_analytics.js | 2 +-
.../total_stock_summary.js | 2 +-
erpnext/support/doctype/issue/issue.js | 2 +-
erpnext/support/doctype/issue/test_issue.py | 10 +--
.../doctype/issue_priority/issue_priority.py | 2 +-
.../issue_priority/test_issue_priority.py | 2 +-
.../service_level_agreement.py | 2 +-
.../service_level_agreement_dashboard.py | 2 +-
.../test_service_level_agreement.py | 2 +-
.../first_response_time_for_issues.py | 2 +-
.../report/issue_analytics/issue_analytics.py | 2 +-
.../issue_analytics/test_issue_analytics.py | 4 +-
.../report/issue_summary/issue_summary.py | 1 -
erpnext/support/web_form/issues/issues.js | 2 +-
.../telephony/doctype/call_log/call_log.py | 1 -
.../incoming_call_settings.js | 1 -
.../templates/emails/birthday_reminder.html | 2 +-
.../emails/daily_project_summary.html | 2 +-
.../templates/emails/daily_work_summary.html | 2 +-
.../emails/request_for_quotation.html | 2 +-
erpnext/templates/emails/training_event.html | 2 +-
.../templates/generators/item/item_inquiry.js | 2 +-
.../generators/item/item_specifications.html | 2 +-
erpnext/templates/generators/item_group.html | 2 +-
erpnext/templates/generators/job_opening.html | 6 +-
.../generators/student_admission.html | 2 +-
.../includes/cart/address_picker_card.html | 2 +-
.../includes/cart/cart_address_picker.html | 1 -
.../includes/cart/cart_items_dropdown.html | 2 +-
erpnext/templates/includes/course/macros.html | 2 +-
.../includes/itemised_tax_breakup.html | 2 +-
erpnext/templates/includes/macros.html | 2 +-
.../includes/navbar/navbar_items.html | 2 +-
.../includes/order/order_macros.html | 2 +-
erpnext/templates/includes/projects.css | 2 +-
.../includes/projects/project_search_box.html | 2 +-
.../templates/includes/salary_slip_log.html | 2 +-
.../templates/includes/topic/topic_row.html | 4 +-
erpnext/templates/pages/cart_terms.html | 2 +-
erpnext/templates/pages/courses.html | 2 +-
erpnext/templates/pages/courses.py | 1 -
erpnext/templates/pages/home.css | 2 +-
erpnext/templates/pages/home.html | 2 +-
.../integrations/gocardless_checkout.html | 2 +-
.../pages/integrations/gocardless_checkout.py | 2 +-
.../integrations/gocardless_confirmation.html | 2 +-
.../integrations/gocardless_confirmation.py | 2 +-
.../pages/material_request_info.html | 2 +-
.../templates/pages/material_request_info.py | 6 +-
.../pages/non_profit/join-chapter.html | 2 +-
.../pages/non_profit/leave-chapter.html | 2 +-
erpnext/templates/pages/order.py | 4 +-
erpnext/templates/pages/product_search.py | 1 -
erpnext/templates/pages/projects.js | 2 +-
erpnext/templates/pages/task_info.html | 2 +-
erpnext/templates/pages/task_info.py | 6 +-
erpnext/templates/pages/timelog_info.html | 2 +-
erpnext/templates/pages/timelog_info.py | 4 +-
.../includes/item_table_qty.html | 1 -
erpnext/tests/test_regional.py | 2 +-
erpnext/tests/test_subcontracting.py | 2 +-
erpnext/tests/ui/setup_wizard.js | 2 +-
erpnext/tests/ui_test_helpers.py | 2 +-
erpnext/utilities/activation.py | 26 +++----
erpnext/utilities/bot.py | 2 +-
.../doctype/rename_tool/rename_tool.py | 1 -
erpnext/utilities/doctype/video/video_list.js | 2 +-
.../doctype/video_settings/video_settings.py | 2 +-
erpnext/utilities/hierarchy_chart.py | 2 +-
.../youtube_interactions.py | 2 +-
.../utilities/web_form/addresses/addresses.js | 2 +-
erpnext/www/all-products/index.html | 2 +-
erpnext/www/all-products/item_row.html | 1 -
erpnext/www/all-products/not_found.html | 2 +-
erpnext/www/book_appointment/index.css | 2 +-
erpnext/www/book_appointment/index.html | 2 +-
.../www/book_appointment/verify/index.html | 4 +-
erpnext/www/book_appointment/verify/index.py | 2 +-
erpnext/www/lms/content.py | 2 +-
erpnext/www/lms/course.html | 2 +-
erpnext/www/lms/index.py | 2 +-
erpnext/www/lms/macros/card.html | 2 +-
erpnext/www/lms/macros/hero.html | 2 +-
erpnext/www/lms/profile.py | 2 +-
erpnext/www/lms/program.html | 2 +-
erpnext/www/lms/program.py | 2 +-
erpnext/www/lms/topic.html | 2 +-
erpnext/www/lms/topic.py | 2 +-
erpnext/www/support/index.html | 2 +-
erpnext/www/support/index.py | 24 +++---
1190 files changed, 1352 insertions(+), 1604 deletions(-)
diff --git a/erpnext/.stylelintrc b/erpnext/.stylelintrc
index 1e05d1fb41..30075f13d0 100644
--- a/erpnext/.stylelintrc
+++ b/erpnext/.stylelintrc
@@ -6,4 +6,4 @@
"scss/at-rule-no-unknown": true,
"no-descending-specificity": null
}
-}
\ No newline at end of file
+}
diff --git a/erpnext/accounts/dashboard_chart_source/account_balance_timeline/account_balance_timeline.js b/erpnext/accounts/dashboard_chart_source/account_balance_timeline/account_balance_timeline.js
index e12eae9c1c..d8a83e53dc 100644
--- a/erpnext/accounts/dashboard_chart_source/account_balance_timeline/account_balance_timeline.js
+++ b/erpnext/accounts/dashboard_chart_source/account_balance_timeline/account_balance_timeline.js
@@ -19,4 +19,4 @@ frappe.dashboards.chart_sources["Account Balance Timeline"] = {
reqd: 1
},
]
-};
\ No newline at end of file
+};
diff --git a/erpnext/accounts/deferred_revenue.py b/erpnext/accounts/deferred_revenue.py
index 335e8a15ab..0c81d83ed8 100644
--- a/erpnext/accounts/deferred_revenue.py
+++ b/erpnext/accounts/deferred_revenue.py
@@ -450,5 +450,3 @@ def get_deferred_booking_accounts(doctype, voucher_detail_no, dr_or_cr):
return debit_account
else:
return credit_account
-
-
diff --git a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.js b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.js
index 65c5ff1cea..2fa1d53c60 100644
--- a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.js
+++ b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.js
@@ -60,4 +60,4 @@ frappe.ui.form.on('Accounting Dimension Detail', {
let row = locals[cdt][cdn];
row.reference_document = frm.doc.document_type;
}
-});
\ No newline at end of file
+});
diff --git a/erpnext/accounts/doctype/accounting_dimension/test_accounting_dimension.py b/erpnext/accounts/doctype/accounting_dimension/test_accounting_dimension.py
index e657a9ae34..4f3ee7643a 100644
--- a/erpnext/accounts/doctype/accounting_dimension/test_accounting_dimension.py
+++ b/erpnext/accounts/doctype/accounting_dimension/test_accounting_dimension.py
@@ -113,5 +113,3 @@ def disable_dimension():
dimension2 = frappe.get_doc("Accounting Dimension", "Location")
dimension2.disabled = 1
dimension2.save()
-
-
diff --git a/erpnext/accounts/doctype/accounting_dimension_filter/accounting_dimension_filter.js b/erpnext/accounts/doctype/accounting_dimension_filter/accounting_dimension_filter.js
index 74b7b51676..9dd882a311 100644
--- a/erpnext/accounts/doctype/accounting_dimension_filter/accounting_dimension_filter.js
+++ b/erpnext/accounts/doctype/accounting_dimension_filter/accounting_dimension_filter.js
@@ -79,4 +79,4 @@ frappe.ui.form.on('Allowed Dimension', {
row.accounting_dimension = frm.doc.accounting_dimension;
frm.refresh_field("dimensions");
}
-});
\ No newline at end of file
+});
diff --git a/erpnext/accounts/doctype/accounting_period/accounting_period.py b/erpnext/accounts/doctype/accounting_period/accounting_period.py
index 63b5dbbd3e..739d8f6bc6 100644
--- a/erpnext/accounts/doctype/accounting_period/accounting_period.py
+++ b/erpnext/accounts/doctype/accounting_period/accounting_period.py
@@ -56,4 +56,4 @@ class AccountingPeriod(Document):
self.append('closed_documents', {
"document_type": doctype_for_closing.document_type,
"closed": doctype_for_closing.closed
- })
\ No newline at end of file
+ })
diff --git a/erpnext/accounts/doctype/accounts_settings/accounts_settings.js b/erpnext/accounts/doctype/accounts_settings/accounts_settings.js
index 541901c9ab..e44af3a916 100644
--- a/erpnext/accounts/doctype/accounts_settings/accounts_settings.js
+++ b/erpnext/accounts/doctype/accounts_settings/accounts_settings.js
@@ -48,4 +48,4 @@ frappe.tour['Accounts Settings'] = [
title: "Unlink Advance Payment on Cancellation of Order",
description: __("Similar to the previous option, this unlinks any advance payments made against Purchase/Sales Orders.")
}
-];
\ No newline at end of file
+];
diff --git a/erpnext/accounts/doctype/accounts_settings/accounts_settings.py b/erpnext/accounts/doctype/accounts_settings/accounts_settings.py
index 5544913292..62c97f24d5 100644
--- a/erpnext/accounts/doctype/accounts_settings/accounts_settings.py
+++ b/erpnext/accounts/doctype/accounts_settings/accounts_settings.py
@@ -37,7 +37,7 @@ class AccountsSettings(Document):
def toggle_discount_accounting_fields(self):
enable_discount_accounting = cint(self.enable_discount_accounting)
-
+
for doctype in ["Sales Invoice Item", "Purchase Invoice Item"]:
make_property_setter(doctype, "discount_account", "hidden", not(enable_discount_accounting), "Check", validate_fields_for_doctype=False)
if enable_discount_accounting:
@@ -52,4 +52,4 @@ class AccountsSettings(Document):
else:
make_property_setter(doctype, "additional_discount_account", "mandatory_depends_on", "", "Code", validate_fields_for_doctype=False)
- make_property_setter("Item", "default_discount_account", "hidden", not(enable_discount_accounting), "Check", validate_fields_for_doctype=False)
\ No newline at end of file
+ make_property_setter("Item", "default_discount_account", "hidden", not(enable_discount_accounting), "Check", validate_fields_for_doctype=False)
diff --git a/erpnext/accounts/doctype/accounts_settings/regional/united_states.js b/erpnext/accounts/doctype/accounts_settings/regional/united_states.js
index d47d6e5803..3e38386481 100644
--- a/erpnext/accounts/doctype/accounts_settings/regional/united_states.js
+++ b/erpnext/accounts/doctype/accounts_settings/regional/united_states.js
@@ -5,4 +5,4 @@ frappe.ui.form.on('Accounts Settings', {
frm.set_df_property("frozen_accounts_modifier", "label", "Role Allowed to Close Books & Make Changes to Closed Periods");
frm.set_df_property("credit_controller", "label", "Credit Manager");
}
-});
\ No newline at end of file
+});
diff --git a/erpnext/accounts/doctype/bank/bank.js b/erpnext/accounts/doctype/bank/bank.js
index 19041a3f73..059e1d3158 100644
--- a/erpnext/accounts/doctype/bank/bank.js
+++ b/erpnext/accounts/doctype/bank/bank.js
@@ -120,4 +120,4 @@ erpnext.integrations.refreshPlaidLink = class refreshPlaidLink {
plaid_success(token, response) {
frappe.show_alert({ message: __('Plaid Link Updated'), indicator: 'green' });
}
-};
\ No newline at end of file
+};
diff --git a/erpnext/accounts/doctype/bank/bank.py b/erpnext/accounts/doctype/bank/bank.py
index 41aae14362..99fa21c8f9 100644
--- a/erpnext/accounts/doctype/bank/bank.py
+++ b/erpnext/accounts/doctype/bank/bank.py
@@ -13,4 +13,4 @@ class Bank(Document):
load_address_and_contact(self)
def on_trash(self):
- delete_contact_and_address('Bank', self.name)
\ No newline at end of file
+ delete_contact_and_address('Bank', self.name)
diff --git a/erpnext/accounts/doctype/bank_account/bank_account_dashboard.py b/erpnext/accounts/doctype/bank_account/bank_account_dashboard.py
index a959cea98f..c7ea152299 100644
--- a/erpnext/accounts/doctype/bank_account/bank_account_dashboard.py
+++ b/erpnext/accounts/doctype/bank_account/bank_account_dashboard.py
@@ -26,4 +26,4 @@ def get_data():
'items': ['Journal Entry']
}
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/accounts/doctype/bank_clearance/bank_clearance.js b/erpnext/accounts/doctype/bank_clearance/bank_clearance.js
index ba3f2face6..63cc46518f 100644
--- a/erpnext/accounts/doctype/bank_clearance/bank_clearance.js
+++ b/erpnext/accounts/doctype/bank_clearance/bank_clearance.js
@@ -8,7 +8,7 @@ frappe.ui.form.on("Bank Clearance", {
onload: function(frm) {
- let default_bank_account = frappe.defaults.get_user_default("Company")?
+ let default_bank_account = frappe.defaults.get_user_default("Company")?
locals[":Company"][frappe.defaults.get_user_default("Company")]["default_bank_account"]: "";
frm.set_value("account", default_bank_account);
diff --git a/erpnext/accounts/doctype/bank_clearance_detail/bank_clearance_detail.py b/erpnext/accounts/doctype/bank_clearance_detail/bank_clearance_detail.py
index ecc536733f..59299f81e5 100644
--- a/erpnext/accounts/doctype/bank_clearance_detail/bank_clearance_detail.py
+++ b/erpnext/accounts/doctype/bank_clearance_detail/bank_clearance_detail.py
@@ -6,4 +6,4 @@ import frappe
from frappe.model.document import Document
class BankClearanceDetail(Document):
- pass
\ No newline at end of file
+ pass
diff --git a/erpnext/accounts/doctype/bank_guarantee/bank_guarantee.py b/erpnext/accounts/doctype/bank_guarantee/bank_guarantee.py
index 88e1055beb..a0aac6ab17 100644
--- a/erpnext/accounts/doctype/bank_guarantee/bank_guarantee.py
+++ b/erpnext/accounts/doctype/bank_guarantee/bank_guarantee.py
@@ -25,6 +25,6 @@ class BankGuarantee(Document):
def get_vouchar_detials(column_list, doctype, docname):
column_list = json.loads(column_list)
for col in column_list:
- sanitize_searchfield(col)
+ sanitize_searchfield(col)
return frappe.db.sql(''' select {columns} from `tab{doctype}` where name=%s'''
.format(columns=", ".join(column_list), doctype=doctype), docname, as_dict=1)[0]
diff --git a/erpnext/accounts/doctype/bank_transaction/bank_transaction.py b/erpnext/accounts/doctype/bank_transaction/bank_transaction.py
index 5246baa02b..31cfb2da1d 100644
--- a/erpnext/accounts/doctype/bank_transaction/bank_transaction.py
+++ b/erpnext/accounts/doctype/bank_transaction/bank_transaction.py
@@ -105,4 +105,3 @@ def unclear_reference_payment(doctype, docname):
frappe.db.set_value(doc.payment_document, doc.payment_entry, "clearance_date", None)
return doc.payment_entry
-
diff --git a/erpnext/accounts/doctype/bank_transaction/bank_transaction_list.js b/erpnext/accounts/doctype/bank_transaction/bank_transaction_list.js
index 2ecc2b0cda..bff41d5539 100644
--- a/erpnext/accounts/doctype/bank_transaction/bank_transaction_list.js
+++ b/erpnext/accounts/doctype/bank_transaction/bank_transaction_list.js
@@ -10,4 +10,4 @@ frappe.listview_settings['Bank Transaction'] = {
return [__("Reconciled"), "green", "unallocated_amount,=,0"];
}
}
-};
\ No newline at end of file
+};
diff --git a/erpnext/accounts/doctype/bank_transaction/bank_transaction_upload.py b/erpnext/accounts/doctype/bank_transaction/bank_transaction_upload.py
index 33ae45439e..dc3b867470 100644
--- a/erpnext/accounts/doctype/bank_transaction/bank_transaction_upload.py
+++ b/erpnext/accounts/doctype/bank_transaction/bank_transaction_upload.py
@@ -77,4 +77,4 @@ def get_bank_mapping(bank_account):
mapping = {row.file_field:row.bank_transaction_field for row in bank.bank_transaction_mapping}
- return mapping
\ No newline at end of file
+ return mapping
diff --git a/erpnext/accounts/doctype/c_form_invoice_detail/c_form_invoice_detail.py b/erpnext/accounts/doctype/c_form_invoice_detail/c_form_invoice_detail.py
index ee5098bea1..20e423a610 100644
--- a/erpnext/accounts/doctype/c_form_invoice_detail/c_form_invoice_detail.py
+++ b/erpnext/accounts/doctype/c_form_invoice_detail/c_form_invoice_detail.py
@@ -6,4 +6,4 @@ import frappe
from frappe.model.document import Document
class CFormInvoiceDetail(Document):
- pass
\ No newline at end of file
+ pass
diff --git a/erpnext/accounts/doctype/cash_flow_mapping/cash_flow_mapping.py b/erpnext/accounts/doctype/cash_flow_mapping/cash_flow_mapping.py
index 28d84b4442..b1ad2972be 100644
--- a/erpnext/accounts/doctype/cash_flow_mapping/cash_flow_mapping.py
+++ b/erpnext/accounts/doctype/cash_flow_mapping/cash_flow_mapping.py
@@ -18,5 +18,3 @@ class CashFlowMapping(Document):
frappe._('You can only select a maximum of one option from the list of check boxes.'),
title='Error'
)
-
-
diff --git a/erpnext/accounts/doctype/cashier_closing/cashier_closing.py b/erpnext/accounts/doctype/cashier_closing/cashier_closing.py
index 7ad1d3ab83..081c6fa471 100644
--- a/erpnext/accounts/doctype/cashier_closing/cashier_closing.py
+++ b/erpnext/accounts/doctype/cashier_closing/cashier_closing.py
@@ -33,4 +33,4 @@ class CashierClosing(Document):
def validate_time(self):
if self.from_time >= self.time:
- frappe.throw(_("From Time Should Be Less Than To Time"))
\ No newline at end of file
+ frappe.throw(_("From Time Should Be Less Than To Time"))
diff --git a/erpnext/accounts/doctype/cheque_print_template/cheque_print_template.js b/erpnext/accounts/doctype/cheque_print_template/cheque_print_template.js
index 6a430eb02b..d10c61858f 100644
--- a/erpnext/accounts/doctype/cheque_print_template/cheque_print_template.js
+++ b/erpnext/accounts/doctype/cheque_print_template/cheque_print_template.js
@@ -10,10 +10,10 @@ frappe.ui.form.on('Cheque Print Template', {
function() {
erpnext.cheque_print.view_cheque_print(frm);
}).addClass("btn-primary");
-
+
$(frm.fields_dict.cheque_print_preview.wrapper).empty()
-
-
+
+
var template = '';
-
+
$(frappe.render(template, frm.doc)).appendTo(frm.fields_dict.cheque_print_preview.wrapper)
-
+
if (frm.doc.scanned_cheque) {
$(frm.fields_dict.cheque_print_preview.wrapper).find("#cheque_preview").css('background-image', 'url(' + frm.doc.scanned_cheque + ')');
}
diff --git a/erpnext/accounts/doctype/cost_center/cost_center.py b/erpnext/accounts/doctype/cost_center/cost_center.py
index 8a5473f3a1..981fec308c 100644
--- a/erpnext/accounts/doctype/cost_center/cost_center.py
+++ b/erpnext/accounts/doctype/cost_center/cost_center.py
@@ -129,4 +129,4 @@ def get_name_with_number(new_account, account_number):
def check_if_distributed_cost_center_enabled(cost_center_list):
value_list = frappe.get_list("Cost Center", {"name": ["in", cost_center_list]}, "enable_distributed_cost_center", as_list=1)
- return next((True for x in value_list if x[0]), False)
\ No newline at end of file
+ return next((True for x in value_list if x[0]), False)
diff --git a/erpnext/accounts/doctype/cost_center/cost_center_dashboard.py b/erpnext/accounts/doctype/cost_center/cost_center_dashboard.py
index 788ac8be83..24cf3ea068 100644
--- a/erpnext/accounts/doctype/cost_center/cost_center_dashboard.py
+++ b/erpnext/accounts/doctype/cost_center/cost_center_dashboard.py
@@ -12,4 +12,4 @@ def get_data():
'items': ['Budget Variance Report', 'General Ledger']
}
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/accounts/doctype/cost_center/cost_center_tree.js b/erpnext/accounts/doctype/cost_center/cost_center_tree.js
index fde41233c4..1d482c58f1 100644
--- a/erpnext/accounts/doctype/cost_center/cost_center_tree.js
+++ b/erpnext/accounts/doctype/cost_center/cost_center_tree.js
@@ -51,4 +51,4 @@ frappe.treeview_settings["Cost Center"] = {
}
-}
\ No newline at end of file
+}
diff --git a/erpnext/accounts/doctype/cost_center/test_cost_center.py b/erpnext/accounts/doctype/cost_center/test_cost_center.py
index b5fc7e3b49..7779ccefc2 100644
--- a/erpnext/accounts/doctype/cost_center/test_cost_center.py
+++ b/erpnext/accounts/doctype/cost_center/test_cost_center.py
@@ -62,6 +62,3 @@ def create_cost_center(**args):
cc.is_group = args.is_group or 0
cc.parent_cost_center = args.parent_cost_center or "_Test Company - _TC"
cc.insert()
-
-
-
diff --git a/erpnext/accounts/doctype/coupon_code/coupon_code.py b/erpnext/accounts/doctype/coupon_code/coupon_code.py
index 55c119315e..92a816d25e 100644
--- a/erpnext/accounts/doctype/coupon_code/coupon_code.py
+++ b/erpnext/accounts/doctype/coupon_code/coupon_code.py
@@ -17,7 +17,7 @@ class CouponCode(Document):
self.coupon_code =''.join(i for i in self.coupon_name if not i.isdigit())[0:8].upper()
elif self.coupon_type == "Gift Card":
self.coupon_code = frappe.generate_hash()[:10].upper()
-
+
def validate(self):
if self.coupon_type == "Gift Card":
self.maximum_use = 1
diff --git a/erpnext/accounts/doctype/coupon_code/test_coupon_code.py b/erpnext/accounts/doctype/coupon_code/test_coupon_code.py
index 5af12cde06..06987a8a4a 100644
--- a/erpnext/accounts/doctype/coupon_code/test_coupon_code.py
+++ b/erpnext/accounts/doctype/coupon_code/test_coupon_code.py
@@ -124,6 +124,3 @@ class TestCouponCode(unittest.TestCase):
so.submit()
self.assertEqual(frappe.db.get_value("Coupon Code", "SAVE30", "used"), 1)
-
-
-
diff --git a/erpnext/accounts/doctype/discounted_invoice/discounted_invoice.py b/erpnext/accounts/doctype/discounted_invoice/discounted_invoice.py
index 109737f727..93dfcc14bd 100644
--- a/erpnext/accounts/doctype/discounted_invoice/discounted_invoice.py
+++ b/erpnext/accounts/doctype/discounted_invoice/discounted_invoice.py
@@ -7,4 +7,4 @@ from __future__ import unicode_literals
from frappe.model.document import Document
class DiscountedInvoice(Document):
- pass
\ No newline at end of file
+ pass
diff --git a/erpnext/accounts/doctype/dunning/dunning_dashboard.py b/erpnext/accounts/doctype/dunning/dunning_dashboard.py
index 19a73ddfa4..33c6ab080c 100644
--- a/erpnext/accounts/doctype/dunning/dunning_dashboard.py
+++ b/erpnext/accounts/doctype/dunning/dunning_dashboard.py
@@ -14,4 +14,4 @@ def get_data():
'items': ['Payment Entry', 'Journal Entry']
}
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/accounts/doctype/dunning/test_dunning.py b/erpnext/accounts/doctype/dunning/test_dunning.py
index 7fc2e4b306..67692ecc47 100644
--- a/erpnext/accounts/doctype/dunning/test_dunning.py
+++ b/erpnext/accounts/doctype/dunning/test_dunning.py
@@ -143,4 +143,4 @@ def create_dunning_type_with_zero_interest_rate():
'closing_text': 'We kindly request that you pay the outstanding amount immediately, and late fees.'
}
)
- dunning_type.save()
+ dunning_type.save()
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 b7b6020caa..926a442f80 100644
--- a/erpnext/accounts/doctype/exchange_rate_revaluation/exchange_rate_revaluation.js
+++ b/erpnext/accounts/doctype/exchange_rate_revaluation/exchange_rate_revaluation.js
@@ -31,7 +31,7 @@ frappe.ui.form.on('Exchange Rate Revaluation', {
}, __('Create'));
}
}
- });
+ });
}
},
@@ -128,4 +128,4 @@ var get_account_details = function(frm, cdt, cdn) {
frm.events.get_total_gain_loss(frm);
}
});
-};
\ No newline at end of file
+};
diff --git a/erpnext/accounts/doctype/exchange_rate_revaluation/exchange_rate_revaluation.py b/erpnext/accounts/doctype/exchange_rate_revaluation/exchange_rate_revaluation.py
index f2b0a8c08a..dbbcedcadf 100644
--- a/erpnext/accounts/doctype/exchange_rate_revaluation/exchange_rate_revaluation.py
+++ b/erpnext/accounts/doctype/exchange_rate_revaluation/exchange_rate_revaluation.py
@@ -44,7 +44,7 @@ class ExchangeRateRevaluation(Document):
if total_amt != total_debit:
return True
-
+
return False
@frappe.whitelist()
@@ -205,4 +205,4 @@ def get_account_details(account, company, posting_date, party_type=None, party=N
"new_balance_in_base_currency": new_balance_in_base_currency
}
- return account_details
\ No newline at end of file
+ return account_details
diff --git a/erpnext/accounts/doctype/finance_book/test_finance_book.py b/erpnext/accounts/doctype/finance_book/test_finance_book.py
index 502765812a..cd8e204f4c 100644
--- a/erpnext/accounts/doctype/finance_book/test_finance_book.py
+++ b/erpnext/accounts/doctype/finance_book/test_finance_book.py
@@ -19,7 +19,7 @@ class TestFinanceBook(unittest.TestCase):
finance_book = frappe.get_doc("Finance Book", "_Test Finance Book")
return finance_book
-
+
def test_finance_book(self):
finance_book = self.create_finance_book()
diff --git a/erpnext/accounts/doctype/invoice_discounting/invoice_discounting_dashboard.py b/erpnext/accounts/doctype/invoice_discounting/invoice_discounting_dashboard.py
index 6523cd3cdb..6d35ca2439 100644
--- a/erpnext/accounts/doctype/invoice_discounting/invoice_discounting_dashboard.py
+++ b/erpnext/accounts/doctype/invoice_discounting/invoice_discounting_dashboard.py
@@ -17,4 +17,4 @@ def get_data():
'items': ['Payment Entry', 'Journal Entry']
}
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/accounts/doctype/invoice_discounting/invoice_discounting_list.js b/erpnext/accounts/doctype/invoice_discounting/invoice_discounting_list.js
index a72023d8e1..4895efcd4c 100644
--- a/erpnext/accounts/doctype/invoice_discounting/invoice_discounting_list.js
+++ b/erpnext/accounts/doctype/invoice_discounting/invoice_discounting_list.js
@@ -18,4 +18,4 @@ frappe.listview_settings['Invoice Discounting'] = {
return [__("Canceled"), "red", "status,=,Canceled"];
}
}
-};
\ No newline at end of file
+};
diff --git a/erpnext/accounts/doctype/journal_entry/regional/india.js b/erpnext/accounts/doctype/journal_entry/regional/india.js
index 75a69ac0cf..c5f5520479 100644
--- a/erpnext/accounts/doctype/journal_entry/regional/india.js
+++ b/erpnext/accounts/doctype/journal_entry/regional/india.js
@@ -14,4 +14,4 @@ frappe.ui.form.on("Journal Entry", {
};
});
}
-});
\ No newline at end of file
+});
diff --git a/erpnext/accounts/doctype/journal_entry/test_journal_entry.py b/erpnext/accounts/doctype/journal_entry/test_journal_entry.py
index 5f003e022a..5835d462ae 100644
--- a/erpnext/accounts/doctype/journal_entry/test_journal_entry.py
+++ b/erpnext/accounts/doctype/journal_entry/test_journal_entry.py
@@ -100,7 +100,7 @@ class TestJournalEntry(unittest.TestCase):
"debit_in_account_currency": 0 if diff > 0 else abs(diff),
"credit_in_account_currency": diff if diff > 0 else 0
})
-
+
jv.append("accounts", {
"account": "Stock Adjustment - TCP1",
"cost_center": "Main - TCP1",
diff --git a/erpnext/accounts/doctype/journal_entry_template/journal_entry_template.js b/erpnext/accounts/doctype/journal_entry_template/journal_entry_template.js
index cbb9fc4b0f..1c19c1d225 100644
--- a/erpnext/accounts/doctype/journal_entry_template/journal_entry_template.js
+++ b/erpnext/accounts/doctype/journal_entry_template/journal_entry_template.js
@@ -88,4 +88,4 @@ frappe.ui.form.on("Journal Entry Template", {
frappe.model.clear_table(frm.doc, "accounts");
frm.refresh_field("accounts");
}
-});
\ No newline at end of file
+});
diff --git a/erpnext/accounts/doctype/mode_of_payment/mode_of_payment.js b/erpnext/accounts/doctype/mode_of_payment/mode_of_payment.js
index 7a06d3572a..103fa96d02 100644
--- a/erpnext/accounts/doctype/mode_of_payment/mode_of_payment.js
+++ b/erpnext/accounts/doctype/mode_of_payment/mode_of_payment.js
@@ -14,4 +14,4 @@ frappe.ui.form.on('Mode of Payment', {
};
});
},
-});
\ No newline at end of file
+});
diff --git a/erpnext/accounts/doctype/mode_of_payment/mode_of_payment.py b/erpnext/accounts/doctype/mode_of_payment/mode_of_payment.py
index 32473694c8..cea921e999 100644
--- a/erpnext/accounts/doctype/mode_of_payment/mode_of_payment.py
+++ b/erpnext/accounts/doctype/mode_of_payment/mode_of_payment.py
@@ -39,4 +39,3 @@ class ModeofPayment(Document):
message = "POS Profile " + frappe.bold(", ".join(pos_profiles)) + " contains \
Mode of Payment " + frappe.bold(str(self.name)) + ". Please remove them to disable this mode."
frappe.throw(_(message), title="Not Allowed")
-
diff --git a/erpnext/accounts/doctype/monthly_distribution/monthly_distribution.py b/erpnext/accounts/doctype/monthly_distribution/monthly_distribution.py
index bff6422732..ad8623fb4e 100644
--- a/erpnext/accounts/doctype/monthly_distribution/monthly_distribution.py
+++ b/erpnext/accounts/doctype/monthly_distribution/monthly_distribution.py
@@ -55,4 +55,4 @@ def get_percentage(doc, start_date, period):
if d.month in months:
percentage += d.percentage_allocation
- return percentage
\ No newline at end of file
+ return percentage
diff --git a/erpnext/accounts/doctype/monthly_distribution/monthly_distribution_dashboard.py b/erpnext/accounts/doctype/monthly_distribution/monthly_distribution_dashboard.py
index a679499815..912bd9e331 100644
--- a/erpnext/accounts/doctype/monthly_distribution/monthly_distribution_dashboard.py
+++ b/erpnext/accounts/doctype/monthly_distribution/monthly_distribution_dashboard.py
@@ -20,4 +20,4 @@ def get_data():
'items': ['Budget']
}
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.js b/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.js
index a8c07d6bb9..7eb5c4234d 100644
--- a/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.js
+++ b/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.js
@@ -162,4 +162,4 @@ frappe.ui.form.on('Opening Invoice Creation Tool Item', {
invoices_add: (frm) => {
frm.trigger('update_invoice_table');
}
-});
\ No newline at end of file
+});
diff --git a/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py b/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py
index d76d909962..9914b45dfc 100644
--- a/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py
+++ b/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py
@@ -241,4 +241,3 @@ def get_temporary_opening_account(company=None):
frappe.throw(_("Please add a Temporary Opening account in Chart of Accounts"))
return accounts[0].name
-
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py
index 831b270858..d2dffde5cd 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.py
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py
@@ -185,7 +185,7 @@ class PaymentEntry(AccountsController):
for field, value in iteritems(ref_details):
if d.exchange_gain_loss:
# for cases where gain/loss is booked into invoice
- # exchange_gain_loss is calculated from invoice & populated
+ # exchange_gain_loss is calculated from invoice & populated
# and row.exchange_rate is already set to payment entry's exchange rate
# refer -> `update_reference_in_payment_entry()` in utils.py
continue
@@ -417,7 +417,7 @@ class PaymentEntry(AccountsController):
net_total_for_tds = 0
if reference.reference_doctype == 'Purchase Order':
net_total_for_tds += flt(frappe.db.get_value('Purchase Order', reference.reference_name, 'net_total'))
-
+
if net_total_for_tds:
net_total = net_total_for_tds
@@ -841,7 +841,7 @@ class PaymentEntry(AccountsController):
if account_details:
row.update(account_details)
-
+
if not row.get('amount'):
# if no difference amount
return
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry_list.js b/erpnext/accounts/doctype/payment_entry/payment_entry_list.js
index e6d83b9f68..2d76fe69ef 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry_list.js
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry_list.js
@@ -11,4 +11,4 @@ frappe.listview_settings['Payment Entry'] = {
};
}
}
-};
\ No newline at end of file
+};
diff --git a/erpnext/accounts/doctype/payment_entry/tests/test_payment_against_purchase_invoice.js b/erpnext/accounts/doctype/payment_entry/tests/test_payment_against_purchase_invoice.js
index 14aa0736d4..e8db2c3159 100644
--- a/erpnext/accounts/doctype/payment_entry/tests/test_payment_against_purchase_invoice.js
+++ b/erpnext/accounts/doctype/payment_entry/tests/test_payment_against_purchase_invoice.js
@@ -57,4 +57,4 @@ QUnit.test("test payment entry", function(assert) {
() => frappe.timeout(3),
() => done()
]);
-});
\ No newline at end of file
+});
diff --git a/erpnext/accounts/doctype/payment_entry/tests/test_payment_entry.js b/erpnext/accounts/doctype/payment_entry/tests/test_payment_entry.js
index 0c76343fa9..34af79fcd1 100644
--- a/erpnext/accounts/doctype/payment_entry/tests/test_payment_entry.js
+++ b/erpnext/accounts/doctype/payment_entry/tests/test_payment_entry.js
@@ -25,4 +25,4 @@ QUnit.test("test payment entry", function(assert) {
() => frappe.timeout(0.3),
() => done()
]);
-});
\ No newline at end of file
+});
diff --git a/erpnext/accounts/doctype/payment_entry/tests/test_payment_entry_write_off.js b/erpnext/accounts/doctype/payment_entry/tests/test_payment_entry_write_off.js
index 9849d76727..8c7f6f47dd 100644
--- a/erpnext/accounts/doctype/payment_entry/tests/test_payment_entry_write_off.js
+++ b/erpnext/accounts/doctype/payment_entry/tests/test_payment_entry_write_off.js
@@ -64,4 +64,4 @@ QUnit.test("test payment entry", function(assert) {
},
() => done()
]);
-});
\ No newline at end of file
+});
diff --git a/erpnext/accounts/doctype/payment_gateway_account/payment_gateway_account.py b/erpnext/accounts/doctype/payment_gateway_account/payment_gateway_account.py
index fd213a47a1..3529c16a1c 100644
--- a/erpnext/accounts/doctype/payment_gateway_account/payment_gateway_account.py
+++ b/erpnext/accounts/doctype/payment_gateway_account/payment_gateway_account.py
@@ -9,19 +9,19 @@ from frappe.model.document import Document
class PaymentGatewayAccount(Document):
def autoname(self):
self.name = self.payment_gateway + " - " + self.currency
-
+
def validate(self):
self.currency = frappe.db.get_value("Account", self.payment_account, "account_currency")
-
+
self.update_default_payment_gateway()
self.set_as_default_if_not_set()
-
+
def update_default_payment_gateway(self):
if self.is_default:
frappe.db.sql("""update `tabPayment Gateway Account` set is_default = 0
where is_default = 1 """)
-
+
def set_as_default_if_not_set(self):
- if not frappe.db.get_value("Payment Gateway Account",
+ if not frappe.db.get_value("Payment Gateway Account",
{"is_default": 1, "name": ("!=", self.name)}, "name"):
self.is_default = 1
diff --git a/erpnext/accounts/doctype/payment_order/payment_order.js b/erpnext/accounts/doctype/payment_order/payment_order.js
index d12e474c5b..aa373bc2fc 100644
--- a/erpnext/accounts/doctype/payment_order/payment_order.js
+++ b/erpnext/accounts/doctype/payment_order/payment_order.js
@@ -136,4 +136,4 @@ frappe.ui.form.on('Payment Order', {
dialog.show();
},
-});
\ No newline at end of file
+});
diff --git a/erpnext/accounts/doctype/payment_order/payment_order_dashboard.py b/erpnext/accounts/doctype/payment_order/payment_order_dashboard.py
index 6b93f926cd..a4f335833e 100644
--- a/erpnext/accounts/doctype/payment_order/payment_order_dashboard.py
+++ b/erpnext/accounts/doctype/payment_order/payment_order_dashboard.py
@@ -9,4 +9,4 @@ def get_data():
'items': ['Payment Entry', 'Journal Entry']
}
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/accounts/doctype/payment_order/test_payment_order.py b/erpnext/accounts/doctype/payment_order/test_payment_order.py
index 5fdde07faa..9ba57aef30 100644
--- a/erpnext/accounts/doctype/payment_order/test_payment_order.py
+++ b/erpnext/accounts/doctype/payment_order/test_payment_order.py
@@ -46,4 +46,4 @@ def create_payment_order_against_payment_entry(ref_doc, order_type):
doc = make_payment_order(ref_doc.name, payment_order)
doc.save()
doc.submit()
- return doc
\ No newline at end of file
+ return doc
diff --git a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
index d788d91855..acfe1fef2e 100644
--- a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
+++ b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
@@ -307,4 +307,4 @@ def reconcile_dr_cr_note(dr_cr_notes, company):
]
})
jv.flags.ignore_mandatory = True
- jv.submit()
\ No newline at end of file
+ jv.submit()
diff --git a/erpnext/accounts/doctype/payment_request/payment_request.py b/erpnext/accounts/doctype/payment_request/payment_request.py
index 438951db62..f83cb375fc 100644
--- a/erpnext/accounts/doctype/payment_request/payment_request.py
+++ b/erpnext/accounts/doctype/payment_request/payment_request.py
@@ -541,4 +541,4 @@ def make_payment_order(source_name, target_doc=None):
}
}, target_doc, set_missing_values)
- return doclist
\ No newline at end of file
+ return doclist
diff --git a/erpnext/accounts/doctype/payment_request/test_payment_request.py b/erpnext/accounts/doctype/payment_request/test_payment_request.py
index 5eba62c0b3..ad6ff6f555 100644
--- a/erpnext/accounts/doctype/payment_request/test_payment_request.py
+++ b/erpnext/accounts/doctype/payment_request/test_payment_request.py
@@ -138,4 +138,4 @@ class TestPaymentRequest(unittest.TestCase):
# Try to make Payment Request more than SO amount, should give validation
pr2.grand_total = 900
- self.assertRaises(frappe.ValidationError, pr2.save)
\ No newline at end of file
+ self.assertRaises(frappe.ValidationError, pr2.save)
diff --git a/erpnext/accounts/doctype/payment_term/payment_term.js b/erpnext/accounts/doctype/payment_term/payment_term.js
index acd0144c2e..feecf93484 100644
--- a/erpnext/accounts/doctype/payment_term/payment_term.js
+++ b/erpnext/accounts/doctype/payment_term/payment_term.js
@@ -19,4 +19,4 @@ frappe.ui.form.on('Payment Term', {
frm.set_df_property("discount", "description", description);
}
}
-});
\ No newline at end of file
+});
diff --git a/erpnext/accounts/doctype/payment_terms_template/payment_terms_template.js b/erpnext/accounts/doctype/payment_terms_template/payment_terms_template.js
index 84c8d09b16..ea18adefa3 100644
--- a/erpnext/accounts/doctype/payment_terms_template/payment_terms_template.js
+++ b/erpnext/accounts/doctype/payment_terms_template/payment_terms_template.js
@@ -3,6 +3,6 @@
frappe.ui.form.on('Payment Terms Template', {
setup: function(frm) {
-
+
}
});
diff --git a/erpnext/accounts/doctype/payment_terms_template/payment_terms_template_dashboard.py b/erpnext/accounts/doctype/payment_terms_template/payment_terms_template_dashboard.py
index c705097ac6..5c8cb4fbdc 100644
--- a/erpnext/accounts/doctype/payment_terms_template/payment_terms_template_dashboard.py
+++ b/erpnext/accounts/doctype/payment_terms_template/payment_terms_template_dashboard.py
@@ -30,4 +30,4 @@ def get_data():
'items': ['Customer Group', 'Supplier Group']
}
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.py b/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.py
index 9cfb47876c..a6e3bd98e7 100644
--- a/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.py
+++ b/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.py
@@ -51,7 +51,7 @@ class PeriodClosingVoucher(AccountsController):
def make_gl_entries(self):
gl_entries = []
- net_pl_balance = 0
+ net_pl_balance = 0
pl_accounts = self.get_pl_balances()
@@ -79,7 +79,7 @@ class PeriodClosingVoucher(AccountsController):
from erpnext.accounts.general_ledger import make_gl_entries
make_gl_entries(gl_entries)
-
+
def get_pnl_gl_entry(self, net_pl_balance):
cost_center = frappe.db.get_value("Company", self.company, "cost_center")
gl_entry = self.get_gl_dict({
diff --git a/erpnext/accounts/doctype/period_closing_voucher/test_period_closing_voucher.py b/erpnext/accounts/doctype/period_closing_voucher/test_period_closing_voucher.py
index 2f29372b01..f17a5c51a0 100644
--- a/erpnext/accounts/doctype/period_closing_voucher/test_period_closing_voucher.py
+++ b/erpnext/accounts/doctype/period_closing_voucher/test_period_closing_voucher.py
@@ -139,7 +139,7 @@ def create_company():
'company_name': "Test PCV Company",
'country': 'United States',
'default_currency': 'USD'
- })
+ })
company.insert(ignore_if_duplicate = True)
return company.name
diff --git a/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.js b/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.js
index 6418d73090..264d4a68b0 100644
--- a/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.js
+++ b/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.js
@@ -20,9 +20,9 @@ frappe.ui.form.on('POS Closing Entry', {
frm.set_query("pos_opening_entry", function(doc) {
return { filters: { 'status': 'Open', 'docstatus': 1 } };
});
-
+
if (frm.doc.docstatus === 0 && !frm.doc.amended_from) frm.set_value("period_end_date", frappe.datetime.now_datetime());
-
+
frappe.realtime.on('closing_process_complete', async function(data) {
await frm.reload_doc();
if (frm.doc.status == 'Failed' && frm.doc.error_message && data.user == frappe.session.user) {
@@ -43,7 +43,7 @@ frappe.ui.form.on('POS Closing Entry', {
const issue = 'issue ';
frm.dashboard.set_headline(
__('POS Closing failed while running in a background process. You can resolve the {0} and retry the process again.', [issue]));
-
+
$('#jump_to_error').on('click', (e) => {
e.preventDefault();
frappe.utils.scroll_to(
diff --git a/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.js b/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.js
index cd08efc55f..2f8081b95c 100644
--- a/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.js
+++ b/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.js
@@ -5,10 +5,10 @@ frappe.ui.form.on('POS Invoice Merge Log', {
setup: function(frm) {
frm.set_query("pos_invoice", "pos_invoices", doc => {
return{
- filters: {
+ filters: {
'docstatus': 1,
- 'customer': doc.customer,
- 'consolidated_invoice': ''
+ 'customer': doc.customer,
+ 'consolidated_invoice': ''
}
}
});
diff --git a/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py b/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py
index 08e072e204..e50d437ba6 100644
--- a/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py
+++ b/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py
@@ -354,4 +354,4 @@ def safe_load_json(message):
except Exception:
json_message = message
- return json_message
\ No newline at end of file
+ return json_message
diff --git a/erpnext/accounts/doctype/pos_invoice_merge_log/test_pos_invoice_merge_log.py b/erpnext/accounts/doctype/pos_invoice_merge_log/test_pos_invoice_merge_log.py
index 040a815fab..1b9659409c 100644
--- a/erpnext/accounts/doctype/pos_invoice_merge_log/test_pos_invoice_merge_log.py
+++ b/erpnext/accounts/doctype/pos_invoice_merge_log/test_pos_invoice_merge_log.py
@@ -147,4 +147,3 @@ class TestPOSInvoiceMergeLog(unittest.TestCase):
frappe.set_user("Administrator")
frappe.db.sql("delete from `tabPOS Profile`")
frappe.db.sql("delete from `tabPOS Invoice`")
-
diff --git a/erpnext/accounts/doctype/pos_opening_entry/pos_opening_entry.js b/erpnext/accounts/doctype/pos_opening_entry/pos_opening_entry.js
index 372e75649b..d23f348f04 100644
--- a/erpnext/accounts/doctype/pos_opening_entry/pos_opening_entry.js
+++ b/erpnext/accounts/doctype/pos_opening_entry/pos_opening_entry.js
@@ -53,4 +53,4 @@ frappe.ui.form.on('POS Opening Entry', {
});
}
}
-});
\ No newline at end of file
+});
diff --git a/erpnext/accounts/doctype/pos_opening_entry/pos_opening_entry.py b/erpnext/accounts/doctype/pos_opening_entry/pos_opening_entry.py
index 0023a84a46..3318fefab1 100644
--- a/erpnext/accounts/doctype/pos_opening_entry/pos_opening_entry.py
+++ b/erpnext/accounts/doctype/pos_opening_entry/pos_opening_entry.py
@@ -38,4 +38,4 @@ class POSOpeningEntry(StatusUpdater):
frappe.throw(msg.format(", ".join(invalid_modes)), title=_("Missing Account"))
def on_submit(self):
- self.set_status(update=True)
\ No newline at end of file
+ self.set_status(update=True)
diff --git a/erpnext/accounts/doctype/pos_opening_entry/test_pos_opening_entry.py b/erpnext/accounts/doctype/pos_opening_entry/test_pos_opening_entry.py
index 2e36391714..c115be5ae9 100644
--- a/erpnext/accounts/doctype/pos_opening_entry/test_pos_opening_entry.py
+++ b/erpnext/accounts/doctype/pos_opening_entry/test_pos_opening_entry.py
@@ -21,8 +21,8 @@ def create_opening_entry(pos_profile, user):
balance_details.append(frappe._dict({
'mode_of_payment': d.mode_of_payment
}))
-
+
entry.set("balance_details", balance_details)
entry.submit()
-
- return entry.as_dict()
+
+ return entry.as_dict()
diff --git a/erpnext/accounts/doctype/pos_settings/pos_settings.py b/erpnext/accounts/doctype/pos_settings/pos_settings.py
index 913f49829c..d925dd9d86 100644
--- a/erpnext/accounts/doctype/pos_settings/pos_settings.py
+++ b/erpnext/accounts/doctype/pos_settings/pos_settings.py
@@ -8,4 +8,4 @@ from frappe.model.document import Document
class POSSettings(Document):
def validate(self):
- pass
\ No newline at end of file
+ pass
diff --git a/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py b/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py
index 3173db13af..680370b6af 100644
--- a/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py
+++ b/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py
@@ -615,4 +615,4 @@ def delete_existing_pricing_rules():
for doctype in ["Pricing Rule", "Pricing Rule Item Code",
"Pricing Rule Item Group", "Pricing Rule Brand"]:
- frappe.db.sql("delete from `tab{0}`".format(doctype))
\ No newline at end of file
+ frappe.db.sql("delete from `tab{0}`".format(doctype))
diff --git a/erpnext/accounts/doctype/pricing_rule/tests/test_pricing_rule.js b/erpnext/accounts/doctype/pricing_rule/tests/test_pricing_rule.js
index 8155e7d799..8279b59cb4 100644
--- a/erpnext/accounts/doctype/pricing_rule/tests/test_pricing_rule.js
+++ b/erpnext/accounts/doctype/pricing_rule/tests/test_pricing_rule.js
@@ -26,4 +26,3 @@ QUnit.test("test pricing rule", function(assert) {
() => done()
]);
});
-
diff --git a/erpnext/accounts/doctype/process_deferred_accounting/process_deferred_accounting.py b/erpnext/accounts/doctype/process_deferred_accounting/process_deferred_accounting.py
index 0eac73236e..5e7583a974 100644
--- a/erpnext/accounts/doctype/process_deferred_accounting/process_deferred_accounting.py
+++ b/erpnext/accounts/doctype/process_deferred_accounting/process_deferred_accounting.py
@@ -31,4 +31,4 @@ class ProcessDeferredAccounting(Document):
'against_voucher': self.name
})
- make_reverse_gl_entries(gl_entries=gl_entries)
\ No newline at end of file
+ make_reverse_gl_entries(gl_entries=gl_entries)
diff --git a/erpnext/accounts/doctype/process_deferred_accounting/test_process_deferred_accounting.py b/erpnext/accounts/doctype/process_deferred_accounting/test_process_deferred_accounting.py
index e08a0e5cc2..03c269ac76 100644
--- a/erpnext/accounts/doctype/process_deferred_accounting/test_process_deferred_accounting.py
+++ b/erpnext/accounts/doctype/process_deferred_accounting/test_process_deferred_accounting.py
@@ -45,4 +45,4 @@ class TestProcessDeferredAccounting(unittest.TestCase):
["Sales - _TC", 0.0, 33.85, "2019-01-31"]
]
- check_gl_entries(self, si.name, expected_gle, "2019-01-10")
\ No newline at end of file
+ check_gl_entries(self, si.name, expected_gle, "2019-01-10")
diff --git a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py
index 500952e38a..a12ea4033d 100644
--- a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py
+++ b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py
@@ -284,4 +284,4 @@ def send_auto_email():
selected = frappe.get_list('Process Statement Of Accounts', filters={'to_date': format_date(today()), 'enable_auto_email': 1})
for entry in selected:
send_emails(entry.name, from_scheduler=True)
- return True
\ No newline at end of file
+ return True
diff --git a/erpnext/accounts/doctype/promotional_scheme/promotional_scheme.js b/erpnext/accounts/doctype/promotional_scheme/promotional_scheme.js
index 890a1871bd..e840c79cd7 100644
--- a/erpnext/accounts/doctype/promotional_scheme/promotional_scheme.js
+++ b/erpnext/accounts/doctype/promotional_scheme/promotional_scheme.js
@@ -48,4 +48,4 @@ frappe.ui.form.on('Promotional Scheme', {
frm.doc.apply_on === key ? 1 : 0);
}
}
-});
\ No newline at end of file
+});
diff --git a/erpnext/accounts/doctype/promotional_scheme/promotional_scheme_dashboard.py b/erpnext/accounts/doctype/promotional_scheme/promotional_scheme_dashboard.py
index 28c4c61b9f..54fedb7738 100644
--- a/erpnext/accounts/doctype/promotional_scheme/promotional_scheme_dashboard.py
+++ b/erpnext/accounts/doctype/promotional_scheme/promotional_scheme_dashboard.py
@@ -9,4 +9,4 @@ def get_data():
'items': ['Pricing Rule']
}
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/accounts/doctype/promotional_scheme/test_promotional_scheme.py b/erpnext/accounts/doctype/promotional_scheme/test_promotional_scheme.py
index 7354ef036c..286f7cf6ed 100644
--- a/erpnext/accounts/doctype/promotional_scheme/test_promotional_scheme.py
+++ b/erpnext/accounts/doctype/promotional_scheme/test_promotional_scheme.py
@@ -11,25 +11,25 @@ class TestPromotionalScheme(unittest.TestCase):
ps = make_promotional_scheme()
price_rules = frappe.get_all('Pricing Rule', fields = ["promotional_scheme_id", "name", "creation"],
filters = {'promotional_scheme': ps.name})
- self.assertTrue(len(price_rules),1)
+ self.assertTrue(len(price_rules),1)
price_doc_details = frappe.db.get_value('Pricing Rule', price_rules[0].name, ['customer', 'min_qty', 'discount_percentage'], as_dict = 1)
self.assertTrue(price_doc_details.customer, '_Test Customer')
self.assertTrue(price_doc_details.min_qty, 4)
self.assertTrue(price_doc_details.discount_percentage, 20)
ps.price_discount_slabs[0].min_qty = 6
- ps.append('customer', {
+ ps.append('customer', {
'customer': "_Test Customer 2"})
ps.save()
price_rules = frappe.get_all('Pricing Rule', fields = ["promotional_scheme_id", "name"],
filters = {'promotional_scheme': ps.name})
- self.assertTrue(len(price_rules), 2)
+ self.assertTrue(len(price_rules), 2)
price_doc_details = frappe.db.get_value('Pricing Rule', price_rules[1].name, ['customer', 'min_qty', 'discount_percentage'], as_dict = 1)
self.assertTrue(price_doc_details.customer, '_Test Customer 2')
self.assertTrue(price_doc_details.min_qty, 6)
self.assertTrue(price_doc_details.discount_percentage, 20)
-
+
price_doc_details = frappe.db.get_value('Pricing Rule', price_rules[0].name, ['customer', 'min_qty', 'discount_percentage'], as_dict = 1)
self.assertTrue(price_doc_details.customer, '_Test Customer')
self.assertTrue(price_doc_details.min_qty, 6)
@@ -38,7 +38,7 @@ class TestPromotionalScheme(unittest.TestCase):
price_rules = frappe.get_all('Pricing Rule', fields = ["promotional_scheme_id", "name"],
filters = {'promotional_scheme': ps.name})
self.assertEqual(price_rules, [])
-
+
def make_promotional_scheme():
ps = frappe.new_doc('Promotional Scheme')
ps.name = '_Test Scheme'
@@ -57,4 +57,4 @@ def make_promotional_scheme():
})
ps.save()
- return ps
\ No newline at end of file
+ return ps
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
index 3b91118402..6c74d2b438 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
@@ -591,4 +591,4 @@ frappe.ui.form.on("Purchase Invoice", {
company: function(frm) {
erpnext.accounts.dimensions.update_dimension(frm, frm.doctype);
},
-})
\ No newline at end of file
+})
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice_dashboard.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice_dashboard.py
index 173939df00..b6467a3d5c 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice_dashboard.py
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice_dashboard.py
@@ -34,4 +34,4 @@ def get_data():
'items': ['Auto Repeat']
},
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice_list.js b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice_list.js
index 914a2457d4..771b49ac62 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice_list.js
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice_list.js
@@ -26,4 +26,4 @@ frappe.listview_settings['Purchase Invoice'] = {
return [__("Paid"), "green", "outstanding_amount,=,0"];
}
}
-};
\ No newline at end of file
+};
diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.js b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.js
index b470051b51..94b3b9ed33 100644
--- a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.js
+++ b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.js
@@ -72,4 +72,3 @@ QUnit.test("test purchase invoice", function(assert) {
() => done()
]);
});
-
diff --git a/erpnext/accounts/doctype/purchase_invoice_advance/purchase_invoice_advance.py b/erpnext/accounts/doctype/purchase_invoice_advance/purchase_invoice_advance.py
index bfaa849200..d157837a7a 100644
--- a/erpnext/accounts/doctype/purchase_invoice_advance/purchase_invoice_advance.py
+++ b/erpnext/accounts/doctype/purchase_invoice_advance/purchase_invoice_advance.py
@@ -7,4 +7,4 @@ import frappe
from frappe.model.document import Document
class PurchaseInvoiceAdvance(Document):
- pass
\ No newline at end of file
+ pass
diff --git a/erpnext/accounts/doctype/purchase_taxes_and_charges/purchase_taxes_and_charges.py b/erpnext/accounts/doctype/purchase_taxes_and_charges/purchase_taxes_and_charges.py
index a7489da316..5854ddee94 100644
--- a/erpnext/accounts/doctype/purchase_taxes_and_charges/purchase_taxes_and_charges.py
+++ b/erpnext/accounts/doctype/purchase_taxes_and_charges/purchase_taxes_and_charges.py
@@ -7,4 +7,4 @@ import frappe
from frappe.model.document import Document
class PurchaseTaxesandCharges(Document):
- pass
\ No newline at end of file
+ pass
diff --git a/erpnext/accounts/doctype/purchase_taxes_and_charges_template/purchase_taxes_and_charges_template_dashboard.py b/erpnext/accounts/doctype/purchase_taxes_and_charges_template/purchase_taxes_and_charges_template_dashboard.py
index 11c220bf2d..db9793d77a 100644
--- a/erpnext/accounts/doctype/purchase_taxes_and_charges_template/purchase_taxes_and_charges_template_dashboard.py
+++ b/erpnext/accounts/doctype/purchase_taxes_and_charges_template/purchase_taxes_and_charges_template_dashboard.py
@@ -19,4 +19,4 @@ def get_data():
'items': ['Supplier Quotation', 'Tax Rule']
}
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/accounts/doctype/purchase_taxes_and_charges_template/test_purchase_taxes_and_charges_template.js b/erpnext/accounts/doctype/purchase_taxes_and_charges_template/test_purchase_taxes_and_charges_template.js
index c73f03b57b..10b05d0594 100644
--- a/erpnext/accounts/doctype/purchase_taxes_and_charges_template/test_purchase_taxes_and_charges_template.js
+++ b/erpnext/accounts/doctype/purchase_taxes_and_charges_template/test_purchase_taxes_and_charges_template.js
@@ -26,4 +26,3 @@ QUnit.test("test sales taxes and charges template", function(assert) {
() => done()
]);
});
-
diff --git a/erpnext/accounts/doctype/sales_invoice/regional/india_list.js b/erpnext/accounts/doctype/sales_invoice/regional/india_list.js
index ada665a0ca..f01325d80b 100644
--- a/erpnext/accounts/doctype/sales_invoice/regional/india_list.js
+++ b/erpnext/accounts/doctype/sales_invoice/regional/india_list.js
@@ -67,7 +67,7 @@ frappe.listview_settings['Sales Invoice'].onload = function (list_view) {
"default": "1-Duplicate",
"options": ["1-Duplicate", "2-Data Entry Error", "3-Order Cancelled", "4-Other"]
},
- {
+ {
"label": "Remark",
"fieldname": "remark",
"fieldtype": "Data",
@@ -82,7 +82,7 @@ frappe.listview_settings['Sales Invoice'].onload = function (list_view) {
const data = d.get_values();
frappe.call({
method: 'erpnext.regional.india.e_invoice.utils.cancel_irns',
- args: {
+ args: {
doctype: list_view.doctype,
docnames,
reason: data.reason.split('-')[0],
@@ -122,7 +122,7 @@ frappe.listview_settings['Sales Invoice'].onload = function (list_view) {
frappe.realtime.on("bulk_einvoice_generation_complete", (data) => {
const { failures, user, invoices } = data;
-
+
if (invoices.length != failures.length) {
frappe.msgprint({
message: __('{0} e-invoices generated successfully', [invoices.length]),
@@ -171,4 +171,4 @@ frappe.listview_settings['Sales Invoice'].onload = function (list_view) {
});
}
});
-};
\ No newline at end of file
+};
diff --git a/erpnext/accounts/doctype/sales_invoice/regional/italy.js b/erpnext/accounts/doctype/sales_invoice/regional/italy.js
index 1c47d3ab9f..21eb8ce661 100644
--- a/erpnext/accounts/doctype/sales_invoice/regional/italy.js
+++ b/erpnext/accounts/doctype/sales_invoice/regional/italy.js
@@ -1,3 +1,3 @@
{% include "erpnext/regional/italy/sales_invoice.js" %}
-erpnext.setup_e_invoice_button('Sales Invoice')
\ No newline at end of file
+erpnext.setup_e_invoice_button('Sales Invoice')
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice_dashboard.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice_dashboard.py
index f1069282ed..3238ead431 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice_dashboard.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice_dashboard.py
@@ -33,4 +33,4 @@ def get_data():
'items': ['Auto Repeat']
},
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/accounts/doctype/sales_invoice/tests/test_sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/tests/test_sales_invoice.js
index e12ac03850..61d78e1fe4 100644
--- a/erpnext/accounts/doctype/sales_invoice/tests/test_sales_invoice.js
+++ b/erpnext/accounts/doctype/sales_invoice/tests/test_sales_invoice.js
@@ -40,4 +40,3 @@ QUnit.test("test sales Invoice", function(assert) {
() => done()
]);
});
-
diff --git a/erpnext/accounts/doctype/sales_invoice/tests/test_sales_invoice_with_margin.js b/erpnext/accounts/doctype/sales_invoice/tests/test_sales_invoice_with_margin.js
index f1cb22a497..cf2d0fbedb 100644
--- a/erpnext/accounts/doctype/sales_invoice/tests/test_sales_invoice_with_margin.js
+++ b/erpnext/accounts/doctype/sales_invoice/tests/test_sales_invoice_with_margin.js
@@ -33,4 +33,3 @@ QUnit.test("test sales invoice with margin", function(assert) {
() => done()
]);
});
-
diff --git a/erpnext/accounts/doctype/sales_invoice/tests/test_sales_invoice_with_payment.js b/erpnext/accounts/doctype/sales_invoice/tests/test_sales_invoice_with_payment.js
index 651bf0aa4c..45d9a14bff 100644
--- a/erpnext/accounts/doctype/sales_invoice/tests/test_sales_invoice_with_payment.js
+++ b/erpnext/accounts/doctype/sales_invoice/tests/test_sales_invoice_with_payment.js
@@ -54,4 +54,3 @@ QUnit.test("test sales Invoice with payment", function(assert) {
() => done()
]);
});
-
diff --git a/erpnext/accounts/doctype/sales_invoice/tests/test_sales_invoice_with_payment_request.js b/erpnext/accounts/doctype/sales_invoice/tests/test_sales_invoice_with_payment_request.js
index b959cf961b..0464e4509f 100644
--- a/erpnext/accounts/doctype/sales_invoice/tests/test_sales_invoice_with_payment_request.js
+++ b/erpnext/accounts/doctype/sales_invoice/tests/test_sales_invoice_with_payment_request.js
@@ -49,4 +49,3 @@ QUnit.test("test sales Invoice with payment request", function(assert) {
() => done()
]);
});
-
diff --git a/erpnext/accounts/doctype/sales_invoice/tests/test_sales_invoice_with_serialize_item.js b/erpnext/accounts/doctype/sales_invoice/tests/test_sales_invoice_with_serialize_item.js
index 2697758d7a..af484d7899 100644
--- a/erpnext/accounts/doctype/sales_invoice/tests/test_sales_invoice_with_serialize_item.js
+++ b/erpnext/accounts/doctype/sales_invoice/tests/test_sales_invoice_with_serialize_item.js
@@ -42,4 +42,3 @@ QUnit.test("test sales Invoice with serialize item", function(assert) {
() => done()
]);
});
-
diff --git a/erpnext/accounts/doctype/sales_invoice_advance/sales_invoice_advance.py b/erpnext/accounts/doctype/sales_invoice_advance/sales_invoice_advance.py
index 1ec517929e..28aeef4d5e 100644
--- a/erpnext/accounts/doctype/sales_invoice_advance/sales_invoice_advance.py
+++ b/erpnext/accounts/doctype/sales_invoice_advance/sales_invoice_advance.py
@@ -7,4 +7,4 @@ import frappe
from frappe.model.document import Document
class SalesInvoiceAdvance(Document):
- pass
\ No newline at end of file
+ pass
diff --git a/erpnext/accounts/doctype/sales_taxes_and_charges/sales_taxes_and_charges.py b/erpnext/accounts/doctype/sales_taxes_and_charges/sales_taxes_and_charges.py
index 8d1df5c19a..b1de9d85fd 100644
--- a/erpnext/accounts/doctype/sales_taxes_and_charges/sales_taxes_and_charges.py
+++ b/erpnext/accounts/doctype/sales_taxes_and_charges/sales_taxes_and_charges.py
@@ -7,4 +7,4 @@ import frappe
from frappe.model.document import Document
class SalesTaxesandCharges(Document):
- pass
\ No newline at end of file
+ pass
diff --git a/erpnext/accounts/doctype/sales_taxes_and_charges_template/sales_taxes_and_charges_template_dashboard.py b/erpnext/accounts/doctype/sales_taxes_and_charges_template/sales_taxes_and_charges_template_dashboard.py
index d825c6fd32..522e282a17 100644
--- a/erpnext/accounts/doctype/sales_taxes_and_charges_template/sales_taxes_and_charges_template_dashboard.py
+++ b/erpnext/accounts/doctype/sales_taxes_and_charges_template/sales_taxes_and_charges_template_dashboard.py
@@ -21,4 +21,4 @@ def get_data():
'items': ['POS Profile', 'Subscription', 'Restaurant', 'Tax Rule']
}
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/accounts/doctype/sales_taxes_and_charges_template/test_sales_taxes_and_charges_template.js b/erpnext/accounts/doctype/sales_taxes_and_charges_template/test_sales_taxes_and_charges_template.js
index d02e70b541..8cd42f63a4 100644
--- a/erpnext/accounts/doctype/sales_taxes_and_charges_template/test_sales_taxes_and_charges_template.js
+++ b/erpnext/accounts/doctype/sales_taxes_and_charges_template/test_sales_taxes_and_charges_template.js
@@ -26,4 +26,3 @@ QUnit.test("test sales taxes and charges template", function(assert) {
() => done()
]);
});
-
diff --git a/erpnext/accounts/doctype/share_transfer/share_transfer.js b/erpnext/accounts/doctype/share_transfer/share_transfer.js
index 1cad4dfae3..6317c9c8c0 100644
--- a/erpnext/accounts/doctype/share_transfer/share_transfer.js
+++ b/erpnext/accounts/doctype/share_transfer/share_transfer.js
@@ -115,4 +115,4 @@ erpnext.share_transfer.make_jv = function (frm) {
frappe.set_route("Form", doc.doctype, doc.name);
}
});
-};
\ No newline at end of file
+};
diff --git a/erpnext/accounts/doctype/share_transfer/share_transfer.py b/erpnext/accounts/doctype/share_transfer/share_transfer.py
index 4024b8155a..3d4543fb05 100644
--- a/erpnext/accounts/doctype/share_transfer/share_transfer.py
+++ b/erpnext/accounts/doctype/share_transfer/share_transfer.py
@@ -299,4 +299,4 @@ def make_jv_entry( company, account, amount, payment_account,\
"party": credit_applicant,
})
journal_entry.set("accounts", account_amt_list)
- return journal_entry.as_dict()
\ No newline at end of file
+ return journal_entry.as_dict()
diff --git a/erpnext/accounts/doctype/shipping_rule/test_shipping_rule.js b/erpnext/accounts/doctype/shipping_rule/test_shipping_rule.js
index 0201f762b3..63ea1bf35f 100644
--- a/erpnext/accounts/doctype/shipping_rule/test_shipping_rule.js
+++ b/erpnext/accounts/doctype/shipping_rule/test_shipping_rule.js
@@ -34,4 +34,3 @@ QUnit.test("test Shipping Rule", function(assert) {
() => done()
]);
});
-
diff --git a/erpnext/accounts/doctype/shipping_rule/tests/test_shipping_rule_for_buying.js b/erpnext/accounts/doctype/shipping_rule/tests/test_shipping_rule_for_buying.js
index ab1b77cd5f..f3668b8b40 100644
--- a/erpnext/accounts/doctype/shipping_rule/tests/test_shipping_rule_for_buying.js
+++ b/erpnext/accounts/doctype/shipping_rule/tests/test_shipping_rule_for_buying.js
@@ -34,4 +34,3 @@ QUnit.test("test Shipping Rule", function(assert) {
() => done()
]);
});
-
diff --git a/erpnext/accounts/doctype/shipping_rule_condition/shipping_rule_condition.py b/erpnext/accounts/doctype/shipping_rule_condition/shipping_rule_condition.py
index dab59db70c..db6ef117c2 100644
--- a/erpnext/accounts/doctype/shipping_rule_condition/shipping_rule_condition.py
+++ b/erpnext/accounts/doctype/shipping_rule_condition/shipping_rule_condition.py
@@ -9,4 +9,4 @@ import frappe
from frappe.model.document import Document
class ShippingRuleCondition(Document):
- pass
\ No newline at end of file
+ pass
diff --git a/erpnext/accounts/doctype/subscription/subscription_list.js b/erpnext/accounts/doctype/subscription/subscription_list.js
index c7325fb9f7..6490ff3776 100644
--- a/erpnext/accounts/doctype/subscription/subscription_list.js
+++ b/erpnext/accounts/doctype/subscription/subscription_list.js
@@ -14,4 +14,4 @@ frappe.listview_settings['Subscription'] = {
return [__("Cancelled"), "gray"];
}
}
-};
\ No newline at end of file
+};
diff --git a/erpnext/accounts/doctype/subscription/test_subscription.py b/erpnext/accounts/doctype/subscription/test_subscription.py
index 7c58e9865f..4f2cf487a4 100644
--- a/erpnext/accounts/doctype/subscription/test_subscription.py
+++ b/erpnext/accounts/doctype/subscription/test_subscription.py
@@ -630,5 +630,3 @@ class TestSubscription(unittest.TestCase):
subscription.process()
self.assertEqual(len(subscription.invoices), 1)
-
-
diff --git a/erpnext/accounts/doctype/subscription_plan/subscription_plan.js b/erpnext/accounts/doctype/subscription_plan/subscription_plan.js
index aaa32cfe7e..7d6f2aed10 100644
--- a/erpnext/accounts/doctype/subscription_plan/subscription_plan.js
+++ b/erpnext/accounts/doctype/subscription_plan/subscription_plan.js
@@ -6,4 +6,4 @@ frappe.ui.form.on('Subscription Plan', {
frm.toggle_reqd("cost", frm.doc.price_determination === 'Fixed rate');
frm.toggle_reqd("price_list", frm.doc.price_determination === 'Based on price list');
}
-});
\ No newline at end of file
+});
diff --git a/erpnext/accounts/doctype/subscription_plan/subscription_plan.py b/erpnext/accounts/doctype/subscription_plan/subscription_plan.py
index 1ca442a453..a341c2af6a 100644
--- a/erpnext/accounts/doctype/subscription_plan/subscription_plan.py
+++ b/erpnext/accounts/doctype/subscription_plan/subscription_plan.py
@@ -54,4 +54,4 @@ def get_plan_rate(plan, quantity=1, customer=None, start_date=None, end_date=Non
cost -= (plan.cost * prorate_factor)
- return cost
\ No newline at end of file
+ return cost
diff --git a/erpnext/accounts/doctype/tax_rule/tax_rule.py b/erpnext/accounts/doctype/tax_rule/tax_rule.py
index e4ebc6d12f..5814231817 100644
--- a/erpnext/accounts/doctype/tax_rule/tax_rule.py
+++ b/erpnext/accounts/doctype/tax_rule/tax_rule.py
@@ -188,4 +188,4 @@ def get_customer_group_condition(customer_group):
customer_groups = ["%s"%(frappe.db.escape(d.name)) for d in get_parent_customer_groups(customer_group)]
if customer_groups:
condition = ",".join(['%s'] * len(customer_groups))%(tuple(customer_groups))
- return condition
\ No newline at end of file
+ return condition
diff --git a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
index 481ef285e7..1536a237de 100644
--- a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
+++ b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
@@ -240,7 +240,7 @@ def get_deducted_tax(taxable_vouchers, fiscal_year, tax_details):
def get_tds_amount(ldc, parties, inv, tax_details, fiscal_year_details, tax_deducted, vouchers):
tds_amount = 0
invoice_filters = {
- 'name': ('in', vouchers),
+ 'name': ('in', vouchers),
'docstatus': 1
}
@@ -282,7 +282,7 @@ def get_tds_amount(ldc, parties, inv, tax_details, fiscal_year_details, tax_dedu
tds_amount = get_ltds_amount(supp_credit_amt, 0, ldc.certificate_limit, ldc.rate, tax_details)
else:
tds_amount = supp_credit_amt * tax_details.rate / 100 if supp_credit_amt > 0 else 0
-
+
if cint(tax_details.round_off_tax_amount):
tds_amount = round(tds_amount)
diff --git a/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py b/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py
index 2ba22ca435..1c687e5cb1 100644
--- a/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py
+++ b/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py
@@ -97,7 +97,7 @@ class TestTaxWithholdingCategory(unittest.TestCase):
pi.save()
pi.submit()
invoices.append(pi)
-
+
# Second Invoice will apply TDS checked
pi1 = create_purchase_invoice(supplier = "Test TDS Supplier3", rate = 20000)
pi1.submit()
diff --git a/erpnext/accounts/print_format/bank_and_cash_payment_voucher/bank_and_cash_payment_voucher.html b/erpnext/accounts/print_format/bank_and_cash_payment_voucher/bank_and_cash_payment_voucher.html
index e588ed6609..4ac657d1ae 100644
--- a/erpnext/accounts/print_format/bank_and_cash_payment_voucher/bank_and_cash_payment_voucher.html
+++ b/erpnext/accounts/print_format/bank_and_cash_payment_voucher/bank_and_cash_payment_voucher.html
@@ -73,4 +73,4 @@
-
\ No newline at end of file
+
diff --git a/erpnext/accounts/print_format/gst_e_invoice/gst_e_invoice.html b/erpnext/accounts/print_format/gst_e_invoice/gst_e_invoice.html
index 71c26e8c55..7643eca763 100644
--- a/erpnext/accounts/print_format/gst_e_invoice/gst_e_invoice.html
+++ b/erpnext/accounts/print_format/gst_e_invoice/gst_e_invoice.html
@@ -159,4 +159,4 @@
-
\ No newline at end of file
+
diff --git a/erpnext/accounts/print_format/journal_auditing_voucher/journal_auditing_voucher.html b/erpnext/accounts/print_format/journal_auditing_voucher/journal_auditing_voucher.html
index 0ca940f8bd..c1c611ee3a 100644
--- a/erpnext/accounts/print_format/journal_auditing_voucher/journal_auditing_voucher.html
+++ b/erpnext/accounts/print_format/journal_auditing_voucher/journal_auditing_voucher.html
@@ -68,4 +68,4 @@
-
\ No newline at end of file
+
diff --git a/erpnext/accounts/print_format/payment_receipt_voucher/payment_receipt_voucher.html b/erpnext/accounts/print_format/payment_receipt_voucher/payment_receipt_voucher.html
index 283d505e3b..ae07582704 100644
--- a/erpnext/accounts/print_format/payment_receipt_voucher/payment_receipt_voucher.html
+++ b/erpnext/accounts/print_format/payment_receipt_voucher/payment_receipt_voucher.html
@@ -27,4 +27,3 @@
{{ _("Authorized Signatory") }}
-
diff --git a/erpnext/accounts/print_format/purchase_auditing_voucher/purchase_auditing_voucher.html b/erpnext/accounts/print_format/purchase_auditing_voucher/purchase_auditing_voucher.html
index 043ac254ed..8696bffbfc 100644
--- a/erpnext/accounts/print_format/purchase_auditing_voucher/purchase_auditing_voucher.html
+++ b/erpnext/accounts/print_format/purchase_auditing_voucher/purchase_auditing_voucher.html
@@ -103,4 +103,4 @@
-
\ No newline at end of file
+
diff --git a/erpnext/accounts/print_format/sales_auditing_voucher/sales_auditing_voucher.html b/erpnext/accounts/print_format/sales_auditing_voucher/sales_auditing_voucher.html
index a53b593a72..efb2d00f0b 100644
--- a/erpnext/accounts/print_format/sales_auditing_voucher/sales_auditing_voucher.html
+++ b/erpnext/accounts/print_format/sales_auditing_voucher/sales_auditing_voucher.html
@@ -93,4 +93,4 @@
-
\ No newline at end of file
+
diff --git a/erpnext/accounts/report/account_balance/test_account_balance.py b/erpnext/accounts/report/account_balance/test_account_balance.py
index 14ddf4a30f..f5c9449e85 100644
--- a/erpnext/accounts/report/account_balance/test_account_balance.py
+++ b/erpnext/accounts/report/account_balance/test_account_balance.py
@@ -62,8 +62,3 @@ def make_sales_invoice():
income_account = 'Sales - _TC2',
expense_account = 'Cost of Goods Sold - _TC2',
cost_center = 'Main - _TC2')
-
-
-
-
-
diff --git a/erpnext/accounts/report/accounts_payable/accounts_payable.js b/erpnext/accounts/report/accounts_payable/accounts_payable.js
index 6abd6e5cf7..b6c6689be0 100644
--- a/erpnext/accounts/report/accounts_payable/accounts_payable.js
+++ b/erpnext/accounts/report/accounts_payable/accounts_payable.js
@@ -136,4 +136,3 @@ frappe.query_reports["Accounts Payable"] = {
}
erpnext.utils.add_dimensions('Accounts Payable', 9);
-
diff --git a/erpnext/accounts/report/accounts_payable_summary/accounts_payable_summary.js b/erpnext/accounts/report/accounts_payable_summary/accounts_payable_summary.js
index 9c6b0639c0..ea200720df 100644
--- a/erpnext/accounts/report/accounts_payable_summary/accounts_payable_summary.js
+++ b/erpnext/accounts/report/accounts_payable_summary/accounts_payable_summary.js
@@ -105,4 +105,3 @@ frappe.query_reports["Accounts Payable Summary"] = {
}
erpnext.utils.add_dimensions('Accounts Payable Summary', 9);
-
diff --git a/erpnext/accounts/report/accounts_payable_summary/accounts_payable_summary.py b/erpnext/accounts/report/accounts_payable_summary/accounts_payable_summary.py
index 729eda9492..c08582b564 100644
--- a/erpnext/accounts/report/accounts_payable_summary/accounts_payable_summary.py
+++ b/erpnext/accounts/report/accounts_payable_summary/accounts_payable_summary.py
@@ -12,4 +12,3 @@ def execute(filters=None):
"naming_by": ["Buying Settings", "supp_master_name"],
}
return AccountsReceivableSummary(filters).run(args)
-
diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.js b/erpnext/accounts/report/accounts_receivable/accounts_receivable.js
index 29c4f7d394..1a32e2a8e0 100644
--- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.js
+++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.js
@@ -200,4 +200,3 @@ frappe.query_reports["Accounts Receivable"] = {
}
erpnext.utils.add_dimensions('Accounts Receivable', 9);
-
diff --git a/erpnext/accounts/report/accounts_receivable/test_accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/test_accounts_receivable.py
index 2ff5b531c5..cca6760823 100644
--- a/erpnext/accounts/report/accounts_receivable/test_accounts_receivable.py
+++ b/erpnext/accounts/report/accounts_receivable/test_accounts_receivable.py
@@ -93,4 +93,3 @@ def make_credit_note(docname):
cost_center = 'Main - _TC2',
is_return = 1,
return_against = docname)
-
diff --git a/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py b/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py
index 657b3e8f20..e94b30921f 100644
--- a/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py
+++ b/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py
@@ -134,4 +134,4 @@ class AccountsReceivableSummary(ReceivablePayableReport):
"{range2}-{range3}".format(range2=cint(self.filters["range2"])+ 1, range3=self.filters["range3"]),
"{range3}-{range4}".format(range3=cint(self.filters["range3"])+ 1, range4=self.filters["range4"]),
"{range4}-{above}".format(range4=cint(self.filters["range4"])+ 1, above=_("Above"))]):
- self.add_column(label=label, fieldname='range' + str(i+1))
\ No newline at end of file
+ self.add_column(label=label, fieldname='range' + str(i+1))
diff --git a/erpnext/accounts/report/balance_sheet/balance_sheet.py b/erpnext/accounts/report/balance_sheet/balance_sheet.py
index 26bb44f4f7..7838385dc5 100644
--- a/erpnext/accounts/report/balance_sheet/balance_sheet.py
+++ b/erpnext/accounts/report/balance_sheet/balance_sheet.py
@@ -209,4 +209,4 @@ def get_chart_data(filters, columns, asset, liability, equity):
else:
chart["type"] = "line"
- return chart
\ No newline at end of file
+ return chart
diff --git a/erpnext/accounts/report/bank_clearance_summary/bank_clearance_summary.js b/erpnext/accounts/report/bank_clearance_summary/bank_clearance_summary.js
index dbee022973..f0b6c6b20a 100644
--- a/erpnext/accounts/report/bank_clearance_summary/bank_clearance_summary.js
+++ b/erpnext/accounts/report/bank_clearance_summary/bank_clearance_summary.js
@@ -22,7 +22,7 @@ frappe.query_reports["Bank Clearance Summary"] = {
"fieldtype": "Link",
"options": "Account",
"reqd": 1,
- "default": frappe.defaults.get_user_default("Company")?
+ "default": frappe.defaults.get_user_default("Company")?
locals[":Company"][frappe.defaults.get_user_default("Company")]["default_bank_account"]: "",
"get_query": function() {
return {
diff --git a/erpnext/accounts/report/bank_clearance_summary/bank_clearance_summary.py b/erpnext/accounts/report/bank_clearance_summary/bank_clearance_summary.py
index 79b0a6f30e..95f724cc58 100644
--- a/erpnext/accounts/report/bank_clearance_summary/bank_clearance_summary.py
+++ b/erpnext/accounts/report/bank_clearance_summary/bank_clearance_summary.py
@@ -74,19 +74,19 @@ def get_entries(filters):
journal_entries = frappe.db.sql("""SELECT
"Journal Entry", jv.name, jv.posting_date, jv.cheque_no,
jv.clearance_date, jvd.against_account, jvd.debit - jvd.credit
- FROM
+ FROM
`tabJournal Entry Account` jvd, `tabJournal Entry` jv
- WHERE
+ WHERE
jvd.parent = jv.name and jv.docstatus=1 and jvd.account = %(account)s {0}
order by posting_date DESC, jv.name DESC""".format(conditions), filters, as_list=1)
payment_entries = frappe.db.sql("""SELECT
- "Payment Entry", name, posting_date, reference_no, clearance_date, party,
+ "Payment Entry", name, posting_date, reference_no, clearance_date, party,
if(paid_from=%(account)s, paid_amount * -1, received_amount)
- FROM
+ FROM
`tabPayment Entry`
- WHERE
+ WHERE
docstatus=1 and (paid_from = %(account)s or paid_to = %(account)s) {0}
order by posting_date DESC, name DESC""".format(conditions), filters, as_list=1)
- return sorted(journal_entries + payment_entries, key=lambda k: k[2] or getdate(nowdate()))
\ No newline at end of file
+ return sorted(journal_entries + payment_entries, key=lambda k: k[2] or getdate(nowdate()))
diff --git a/erpnext/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.js b/erpnext/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.js
index 8f028496cd..9bb6a14c67 100644
--- a/erpnext/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.js
+++ b/erpnext/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.js
@@ -16,7 +16,7 @@ frappe.query_reports["Bank Reconciliation Statement"] = {
"label": __("Bank Account"),
"fieldtype": "Link",
"options": "Account",
- "default": frappe.defaults.get_user_default("Company")?
+ "default": frappe.defaults.get_user_default("Company")?
locals[":Company"][frappe.defaults.get_user_default("Company")]["default_bank_account"]: "",
"reqd": 1,
"get_query": function() {
diff --git a/erpnext/accounts/report/billed_items_to_be_received/billed_items_to_be_received.py b/erpnext/accounts/report/billed_items_to_be_received/billed_items_to_be_received.py
index 2ce5d50edf..2dcea22f7e 100644
--- a/erpnext/accounts/report/billed_items_to_be_received/billed_items_to_be_received.py
+++ b/erpnext/accounts/report/billed_items_to_be_received/billed_items_to_be_received.py
@@ -104,4 +104,4 @@ def get_columns():
'fieldtype': 'Currency',
'width': 100
}
- ]
\ No newline at end of file
+ ]
diff --git a/erpnext/accounts/report/budget_variance_report/budget_variance_report.js b/erpnext/accounts/report/budget_variance_report/budget_variance_report.js
index f547ca619b..718b6e2fcb 100644
--- a/erpnext/accounts/report/budget_variance_report/budget_variance_report.js
+++ b/erpnext/accounts/report/budget_variance_report/budget_variance_report.js
@@ -92,4 +92,3 @@ frappe.query_reports["Budget Variance Report"] = {
erpnext.dimension_filters.forEach((dimension) => {
frappe.query_reports["Budget Variance Report"].filters[4].options.push(dimension["document_type"]);
});
-
diff --git a/erpnext/accounts/report/budget_variance_report/budget_variance_report.py b/erpnext/accounts/report/budget_variance_report/budget_variance_report.py
index 9f0eee8aa5..443126e465 100644
--- a/erpnext/accounts/report/budget_variance_report/budget_variance_report.py
+++ b/erpnext/accounts/report/budget_variance_report/budget_variance_report.py
@@ -78,7 +78,7 @@ def get_final_data(dimension, dimension_items, filters, period_month_ranges, dat
if filters["period"] != "Yearly" :
row += totals
data.append(row)
-
+
return data
@@ -388,7 +388,7 @@ def get_chart_data(filters, columns, data):
budget_values[i] += values[index]
actual_values[i] += values[index+1]
index += 3
-
+
return {
'data': {
'labels': labels,
@@ -399,4 +399,3 @@ def get_chart_data(filters, columns, data):
},
'type' : 'bar'
}
-
diff --git a/erpnext/accounts/report/cash_flow/cash_flow.html b/erpnext/accounts/report/cash_flow/cash_flow.html
index 40ba20c4ac..d4ae54d4f3 100644
--- a/erpnext/accounts/report/cash_flow/cash_flow.html
+++ b/erpnext/accounts/report/cash_flow/cash_flow.html
@@ -1 +1 @@
-{% include "accounts/report/financial_statements.html" %}
\ No newline at end of file
+{% include "accounts/report/financial_statements.html" %}
diff --git a/erpnext/accounts/report/cash_flow/cash_flow.js b/erpnext/accounts/report/cash_flow/cash_flow.js
index a984bf46b5..a2c34c6ee2 100644
--- a/erpnext/accounts/report/cash_flow/cash_flow.js
+++ b/erpnext/accounts/report/cash_flow/cash_flow.js
@@ -21,4 +21,4 @@ frappe.require("assets/erpnext/js/financial_statements.js", function() {
"default": 1
}
);
-});
\ No newline at end of file
+});
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 1363b53746..6a8301a6f9 100644
--- a/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.js
+++ b/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.js
@@ -94,10 +94,10 @@ frappe.require("assets/erpnext/js/financial_statements.js", function() {
"default": 1
}
],
- "formatter": function(value, row, column, data, default_formatter) {
+ "formatter": function(value, row, column, data, default_formatter) {
if (data && column.fieldname=="account") {
value = data.account_name || value;
-
+
column.link_onclick =
"erpnext.financial_statements.open_general_ledger(" + JSON.stringify(data) + ")";
column.is_tree = true;
@@ -126,4 +126,4 @@ frappe.require("assets/erpnext/js/financial_statements.js", function() {
});
}
}
-});
\ No newline at end of file
+});
diff --git a/erpnext/accounts/report/delivered_items_to_be_billed/delivered_items_to_be_billed.py b/erpnext/accounts/report/delivered_items_to_be_billed/delivered_items_to_be_billed.py
index 515fd995e6..9953d8fcaf 100644
--- a/erpnext/accounts/report/delivered_items_to_be_billed/delivered_items_to_be_billed.py
+++ b/erpnext/accounts/report/delivered_items_to_be_billed/delivered_items_to_be_billed.py
@@ -105,4 +105,4 @@ def get_column():
def get_args():
return {'doctype': 'Delivery Note', 'party': 'customer',
- 'date': 'posting_date', 'order': 'name', 'order_by': 'desc'}
\ No newline at end of file
+ 'date': 'posting_date', 'order': 'name', 'order_by': 'desc'}
diff --git a/erpnext/accounts/report/general_ledger/general_ledger.js b/erpnext/accounts/report/general_ledger/general_ledger.js
index 4a551b8012..095f5eda66 100644
--- a/erpnext/accounts/report/general_ledger/general_ledger.js
+++ b/erpnext/accounts/report/general_ledger/general_ledger.js
@@ -176,4 +176,3 @@ frappe.query_reports["General Ledger"] = {
}
erpnext.utils.add_dimensions('General Ledger', 15)
-
diff --git a/erpnext/accounts/report/general_ledger/general_ledger.py b/erpnext/accounts/report/general_ledger/general_ledger.py
index 1759fa3a48..5d8d49d6a6 100644
--- a/erpnext/accounts/report/general_ledger/general_ledger.py
+++ b/erpnext/accounts/report/general_ledger/general_ledger.py
@@ -48,7 +48,7 @@ def validate_filters(filters, account_details):
if not filters.get("from_date") and not filters.get("to_date"):
frappe.throw(_("{0} and {1} are mandatory").format(frappe.bold(_("From Date")), frappe.bold(_("To Date"))))
-
+
if filters.get('account'):
filters.account = frappe.parse_json(filters.get('account'))
for account in filters.account:
@@ -92,7 +92,7 @@ def set_account_currency(filters):
account_currency = None
if filters.get("account"):
- if len(filters.get("account")) == 1:
+ if len(filters.get("account")) == 1:
account_currency = get_account_currency(filters.account[0])
else:
currency = get_account_currency(filters.account[0])
diff --git a/erpnext/accounts/report/gross_and_net_profit_report/gross_and_net_profit_report.html b/erpnext/accounts/report/gross_and_net_profit_report/gross_and_net_profit_report.html
index 40ba20c4ac..d4ae54d4f3 100644
--- a/erpnext/accounts/report/gross_and_net_profit_report/gross_and_net_profit_report.html
+++ b/erpnext/accounts/report/gross_and_net_profit_report/gross_and_net_profit_report.html
@@ -1 +1 @@
-{% include "accounts/report/financial_statements.html" %}
\ No newline at end of file
+{% include "accounts/report/financial_statements.html" %}
diff --git a/erpnext/accounts/report/gross_and_net_profit_report/gross_and_net_profit_report.py b/erpnext/accounts/report/gross_and_net_profit_report/gross_and_net_profit_report.py
index 714e48d279..8e33af7ee8 100644
--- a/erpnext/accounts/report/gross_and_net_profit_report/gross_and_net_profit_report.py
+++ b/erpnext/accounts/report/gross_and_net_profit_report/gross_and_net_profit_report.py
@@ -165,4 +165,4 @@ def get_net_profit(non_gross_income, gross_income, gross_expense, non_gross_expe
has_value=True
if has_value:
- return profit_loss
\ No newline at end of file
+ return profit_loss
diff --git a/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py b/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py
index 08065a204e..c9c22c246e 100644
--- a/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py
+++ b/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py
@@ -626,7 +626,3 @@ def add_sub_total_row(item, total_row_map, group_by_value, tax_columns):
for tax in tax_columns:
total_row.setdefault(frappe.scrub(tax + ' Amount'), 0.0)
total_row[frappe.scrub(tax + ' Amount')] += flt(item[frappe.scrub(tax + ' Amount')])
-
-
-
-
diff --git a/erpnext/accounts/report/non_billed_report.py b/erpnext/accounts/report/non_billed_report.py
index 2e18ce11dd..5173505689 100644
--- a/erpnext/accounts/report/non_billed_report.py
+++ b/erpnext/accounts/report/non_billed_report.py
@@ -44,4 +44,4 @@ def get_ordered_to_be_billed_data(args):
def get_project_field(doctype, party):
if party == "supplier": doctype = doctype + ' Item'
- return "`tab%s`.project"%(doctype)
\ No newline at end of file
+ return "`tab%s`.project"%(doctype)
diff --git a/erpnext/accounts/report/payment_period_based_on_invoice_date/payment_period_based_on_invoice_date.py b/erpnext/accounts/report/payment_period_based_on_invoice_date/payment_period_based_on_invoice_date.py
index 7195c7e0b8..556f5ad4f7 100644
--- a/erpnext/accounts/report/payment_period_based_on_invoice_date/payment_period_based_on_invoice_date.py
+++ b/erpnext/accounts/report/payment_period_based_on_invoice_date/payment_period_based_on_invoice_date.py
@@ -40,7 +40,7 @@ def execute(filters=None):
row = [
d.voucher_type, d.voucher_no, d.party_type, d.party, d.posting_date, d.against_voucher,
- invoice.posting_date, invoice.due_date, d.debit, d.credit, d.remarks,
+ invoice.posting_date, invoice.due_date, d.debit, d.credit, d.remarks,
d.age, d.range1, d.range2, d.range3, d.range4
]
diff --git a/erpnext/accounts/report/pos_register/pos_register.py b/erpnext/accounts/report/pos_register/pos_register.py
index 6a42bb4fb6..b7e112c0c9 100644
--- a/erpnext/accounts/report/pos_register/pos_register.py
+++ b/erpnext/accounts/report/pos_register/pos_register.py
@@ -10,7 +10,7 @@ from erpnext.accounts.report.sales_register.sales_register import get_mode_of_pa
def execute(filters=None):
if not filters:
return [], []
-
+
validate_filters(filters)
columns = get_columns(filters)
@@ -29,7 +29,7 @@ def execute(filters=None):
invoice_map, grouped_data = {}, []
for d in pos_entries:
invoice_map.setdefault(d[group_by_field], []).append(d)
-
+
for key in invoice_map:
invoices = invoice_map[key]
grouped_data += invoices
@@ -56,7 +56,7 @@ def get_pos_entries(filters, group_by_field):
return frappe.db.sql(
"""
- SELECT
+ SELECT
p.posting_date, p.name as pos_invoice, p.pos_profile,
p.owner, p.base_grand_total as grand_total, p.base_paid_amount as paid_amount,
p.customer, p.is_return {select_mop_field}
@@ -96,22 +96,22 @@ def add_subtotal_row(data, group_invoices, group_by_field, group_by_value):
def validate_filters(filters):
if not filters.get("company"):
frappe.throw(_("{0} is mandatory").format(_("Company")))
-
+
if not filters.get("from_date") and not filters.get("to_date"):
frappe.throw(_("{0} and {1} are mandatory").format(frappe.bold(_("From Date")), frappe.bold(_("To Date"))))
-
+
if filters.from_date > filters.to_date:
frappe.throw(_("From Date must be before To Date"))
if (filters.get("pos_profile") and filters.get("group_by") == _('POS Profile')):
frappe.throw(_("Can not filter based on POS Profile, if grouped by POS Profile"))
-
+
if (filters.get("customer") and filters.get("group_by") == _('Customer')):
frappe.throw(_("Can not filter based on Customer, if grouped by Customer"))
-
+
if (filters.get("owner") and filters.get("group_by") == _('Cashier')):
frappe.throw(_("Can not filter based on Cashier, if grouped by Cashier"))
-
+
if (filters.get("mode_of_payment") and filters.get("group_by") == _('Payment Method')):
frappe.throw(_("Can not filter based on Payment Method, if grouped by Payment Method"))
@@ -120,23 +120,23 @@ def get_conditions(filters):
if filters.get("pos_profile"):
conditions += " AND pos_profile = %(pos_profile)s"
-
+
if filters.get("owner"):
conditions += " AND owner = %(owner)s"
-
+
if filters.get("customer"):
conditions += " AND customer = %(customer)s"
-
+
if filters.get("is_return"):
conditions += " AND is_return = %(is_return)s"
-
+
if filters.get("mode_of_payment"):
conditions += """
AND EXISTS(
SELECT name FROM `tabSales Invoice Payment` sip
WHERE parent=p.name AND ifnull(sip.mode_of_payment, '') = %(mode_of_payment)s
)"""
-
+
return conditions
def get_group_by_field(group_by):
@@ -150,7 +150,7 @@ def get_group_by_field(group_by):
group_by_field = "customer"
elif group_by == "Payment Method":
group_by_field = "mode_of_payment"
-
+
return group_by_field
def get_columns(filters):
@@ -217,4 +217,4 @@ def get_columns(filters):
},
]
- return columns
\ No newline at end of file
+ return columns
diff --git a/erpnext/accounts/report/profitability_analysis/profitability_analysis.html b/erpnext/accounts/report/profitability_analysis/profitability_analysis.html
index 40ba20c4ac..d4ae54d4f3 100644
--- a/erpnext/accounts/report/profitability_analysis/profitability_analysis.html
+++ b/erpnext/accounts/report/profitability_analysis/profitability_analysis.html
@@ -1 +1 @@
-{% include "accounts/report/financial_statements.html" %}
\ No newline at end of file
+{% include "accounts/report/financial_statements.html" %}
diff --git a/erpnext/accounts/report/purchase_invoice_trends/purchase_invoice_trends.js b/erpnext/accounts/report/purchase_invoice_trends/purchase_invoice_trends.js
index a95cfacaee..feab96f265 100644
--- a/erpnext/accounts/report/purchase_invoice_trends/purchase_invoice_trends.js
+++ b/erpnext/accounts/report/purchase_invoice_trends/purchase_invoice_trends.js
@@ -5,4 +5,4 @@ frappe.require("assets/erpnext/js/purchase_trends_filters.js", function() {
frappe.query_reports["Purchase Invoice Trends"] = {
filters: erpnext.get_purchase_trends_filters()
}
-});
\ No newline at end of file
+});
diff --git a/erpnext/accounts/report/purchase_invoice_trends/purchase_invoice_trends.py b/erpnext/accounts/report/purchase_invoice_trends/purchase_invoice_trends.py
index ad3783f0de..ba236b9969 100644
--- a/erpnext/accounts/report/purchase_invoice_trends/purchase_invoice_trends.py
+++ b/erpnext/accounts/report/purchase_invoice_trends/purchase_invoice_trends.py
@@ -11,4 +11,4 @@ def execute(filters=None):
conditions = get_columns(filters, "Purchase Invoice")
data = get_data(filters, conditions)
- return conditions["columns"], data
\ No newline at end of file
+ return conditions["columns"], data
diff --git a/erpnext/accounts/report/purchase_register/purchase_register.js b/erpnext/accounts/report/purchase_register/purchase_register.js
index f34ea57163..aaf76c4299 100644
--- a/erpnext/accounts/report/purchase_register/purchase_register.js
+++ b/erpnext/accounts/report/purchase_register/purchase_register.js
@@ -56,4 +56,4 @@ frappe.query_reports["Purchase Register"] = {
]
}
-erpnext.utils.add_dimensions('Purchase Register', 7);
\ No newline at end of file
+erpnext.utils.add_dimensions('Purchase Register', 7);
diff --git a/erpnext/accounts/report/received_items_to_be_billed/received_items_to_be_billed.py b/erpnext/accounts/report/received_items_to_be_billed/received_items_to_be_billed.py
index e9e9c9c4e6..a5eced5f80 100644
--- a/erpnext/accounts/report/received_items_to_be_billed/received_items_to_be_billed.py
+++ b/erpnext/accounts/report/received_items_to_be_billed/received_items_to_be_billed.py
@@ -105,4 +105,4 @@ def get_column():
def get_args():
return {'doctype': 'Purchase Receipt', 'party': 'supplier',
- 'date': 'posting_date', 'order': 'name', 'order_by': 'desc'}
\ No newline at end of file
+ 'date': 'posting_date', 'order': 'name', 'order_by': 'desc'}
diff --git a/erpnext/accounts/report/sales_invoice_trends/sales_invoice_trends.js b/erpnext/accounts/report/sales_invoice_trends/sales_invoice_trends.js
index 2d320f52cf..e3d43a7de1 100644
--- a/erpnext/accounts/report/sales_invoice_trends/sales_invoice_trends.js
+++ b/erpnext/accounts/report/sales_invoice_trends/sales_invoice_trends.js
@@ -5,4 +5,4 @@ frappe.require("assets/erpnext/js/sales_trends_filters.js", function() {
frappe.query_reports["Sales Invoice Trends"] = {
filters: erpnext.get_sales_trends_filters()
}
-});
\ No newline at end of file
+});
diff --git a/erpnext/accounts/report/sales_payment_summary/sales_payment_summary.js b/erpnext/accounts/report/sales_payment_summary/sales_payment_summary.js
index 068926b063..44e20e83c5 100644
--- a/erpnext/accounts/report/sales_payment_summary/sales_payment_summary.js
+++ b/erpnext/accounts/report/sales_payment_summary/sales_payment_summary.js
@@ -42,4 +42,4 @@ frappe.query_reports["Sales Payment Summary"] = {
"fieldtype": "Check"
},
]
-};
\ No newline at end of file
+};
diff --git a/erpnext/accounts/report/sales_payment_summary/test_sales_payment_summary.py b/erpnext/accounts/report/sales_payment_summary/test_sales_payment_summary.py
index a51c427630..e4a3d3527f 100644
--- a/erpnext/accounts/report/sales_payment_summary/test_sales_payment_summary.py
+++ b/erpnext/accounts/report/sales_payment_summary/test_sales_payment_summary.py
@@ -162,4 +162,4 @@ def create_records():
"price_list": "Standard Selling",
"item_code": item.item_code,
"price_list_rate": 10000
- }).insert()
\ No newline at end of file
+ }).insert()
diff --git a/erpnext/accounts/report/sales_register/sales_register.js b/erpnext/accounts/report/sales_register/sales_register.js
index 85bbceab82..2c9b01bbaa 100644
--- a/erpnext/accounts/report/sales_register/sales_register.js
+++ b/erpnext/accounts/report/sales_register/sales_register.js
@@ -69,4 +69,3 @@ frappe.query_reports["Sales Register"] = {
}
erpnext.utils.add_dimensions('Sales Register', 7);
-
diff --git a/erpnext/accounts/report/supplier_ledger_summary/supplier_ledger_summary.py b/erpnext/accounts/report/supplier_ledger_summary/supplier_ledger_summary.py
index d2c23ee4e7..fbd25b13bb 100644
--- a/erpnext/accounts/report/supplier_ledger_summary/supplier_ledger_summary.py
+++ b/erpnext/accounts/report/supplier_ledger_summary/supplier_ledger_summary.py
@@ -10,4 +10,4 @@ def execute(filters=None):
"party_type": "Supplier",
"naming_by": ["Buying Settings", "supp_master_name"],
}
- return PartyLedgerSummaryReport(filters).run(args)
\ No newline at end of file
+ return PartyLedgerSummaryReport(filters).run(args)
diff --git a/erpnext/accounts/report/trial_balance/trial_balance.js b/erpnext/accounts/report/trial_balance/trial_balance.js
index 8645d55d0f..078b06519f 100644
--- a/erpnext/accounts/report/trial_balance/trial_balance.js
+++ b/erpnext/accounts/report/trial_balance/trial_balance.js
@@ -110,6 +110,3 @@ frappe.require("assets/erpnext/js/financial_statements.js", function() {
erpnext.utils.add_dimensions('Trial Balance', 6);
});
-
-
-
diff --git a/erpnext/accounts/report/trial_balance/trial_balance.py b/erpnext/accounts/report/trial_balance/trial_balance.py
index 33360e2b01..1fc0faab3a 100644
--- a/erpnext/accounts/report/trial_balance/trial_balance.py
+++ b/erpnext/accounts/report/trial_balance/trial_balance.py
@@ -321,4 +321,4 @@ def prepare_opening_closing(row):
row[reverse_col] = abs(row[valid_col])
row[valid_col] = 0.0
else:
- row[reverse_col] = 0.0
\ No newline at end of file
+ row[reverse_col] = 0.0
diff --git a/erpnext/accounts/report/trial_balance_for_party/trial_balance_for_party.py b/erpnext/accounts/report/trial_balance_for_party/trial_balance_for_party.py
index 78c7e439d3..f034e7450e 100644
--- a/erpnext/accounts/report/trial_balance_for_party/trial_balance_for_party.py
+++ b/erpnext/accounts/report/trial_balance_for_party/trial_balance_for_party.py
@@ -242,4 +242,4 @@ def is_party_name_visible(filters):
else:
show_party_name = True
- return show_party_name
\ No newline at end of file
+ return show_party_name
diff --git a/erpnext/accounts/report/unpaid_expense_claim/unpaid_expense_claim.py b/erpnext/accounts/report/unpaid_expense_claim/unpaid_expense_claim.py
index eee620b7cc..1250d676a0 100644
--- a/erpnext/accounts/report/unpaid_expense_claim/unpaid_expense_claim.py
+++ b/erpnext/accounts/report/unpaid_expense_claim/unpaid_expense_claim.py
@@ -20,11 +20,11 @@ def get_unclaimed_expese_claims(filters):
if filters.get("employee"):
cond = "ec.employee = %(employee)s"
- return frappe.db.sql("""
+ return frappe.db.sql("""
select
ec.employee, ec.employee_name, ec.name, ec.total_sanctioned_amount, ec.total_amount_reimbursed,
sum(gle.credit_in_account_currency - gle.debit_in_account_currency) as outstanding_amt
- from
+ from
`tabExpense Claim` ec, `tabGL Entry` gle
where
gle.against_voucher_type = "Expense Claim" and gle.against_voucher = ec.name
diff --git a/erpnext/agriculture/doctype/crop/crop.js b/erpnext/agriculture/doctype/crop/crop.js
index afd84fd9f6..550824636b 100644
--- a/erpnext/agriculture/doctype/crop/crop.js
+++ b/erpnext/agriculture/doctype/crop/crop.js
@@ -52,4 +52,4 @@ erpnext.crop.update_item_qty_amount = function(frm, cdt, cdn) {
}
});
});
-};
\ No newline at end of file
+};
diff --git a/erpnext/agriculture/doctype/crop/crop_dashboard.py b/erpnext/agriculture/doctype/crop/crop_dashboard.py
index 9a8f26fe90..8f37735c81 100644
--- a/erpnext/agriculture/doctype/crop/crop_dashboard.py
+++ b/erpnext/agriculture/doctype/crop/crop_dashboard.py
@@ -9,4 +9,4 @@ def get_data():
'items': ['Crop Cycle']
}
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/agriculture/doctype/crop/test_crop.js b/erpnext/agriculture/doctype/crop/test_crop.js
index 138acbf85a..40555634a2 100644
--- a/erpnext/agriculture/doctype/crop/test_crop.js
+++ b/erpnext/agriculture/doctype/crop/test_crop.js
@@ -105,7 +105,7 @@ QUnit.test("test: Crop", function (assert) {
]
]}
]),
- // agriculture task list
+ // agriculture task list
() => {
assert.equal(cur_frm.doc.name, 'Basil from seed');
assert.equal(cur_frm.doc.period, 15);
diff --git a/erpnext/agriculture/doctype/crop/test_crop.py b/erpnext/agriculture/doctype/crop/test_crop.py
index c2e4917404..b3079837c3 100644
--- a/erpnext/agriculture/doctype/crop/test_crop.py
+++ b/erpnext/agriculture/doctype/crop/test_crop.py
@@ -11,4 +11,4 @@ test_dependencies = ["Fertilizer"]
class TestCrop(unittest.TestCase):
def test_crop_period(self):
basil = frappe.get_doc('Crop', 'Basil from seed')
- self.assertEqual(basil.period, 15)
\ No newline at end of file
+ self.assertEqual(basil.period, 15)
diff --git a/erpnext/agriculture/doctype/crop_cycle/test_crop_cycle.js b/erpnext/agriculture/doctype/crop_cycle/test_crop_cycle.js
index 464a3680ba..87184daedc 100644
--- a/erpnext/agriculture/doctype/crop_cycle/test_crop_cycle.js
+++ b/erpnext/agriculture/doctype/crop_cycle/test_crop_cycle.js
@@ -19,7 +19,7 @@ QUnit.test("test: Crop Cycle", function (assert) {
{disease: 'Aphids'}
]
]},
- {linked_land_unit: [
+ {linked_land_unit: [
[
{land_unit: 'Basil Farm'}
]
diff --git a/erpnext/agriculture/doctype/disease/disease.py b/erpnext/agriculture/doctype/disease/disease.py
index c7707a5465..affa57046e 100644
--- a/erpnext/agriculture/doctype/disease/disease.py
+++ b/erpnext/agriculture/doctype/disease/disease.py
@@ -17,4 +17,4 @@ class Disease(Document):
frappe.throw(_("Start day is greater than end day in task '{0}'").format(task.task_name))
# to calculate the period of the Crop Cycle
if task.end_day > max_period: max_period = task.end_day
- self.treatment_period = max_period
\ No newline at end of file
+ self.treatment_period = max_period
diff --git a/erpnext/agriculture/doctype/disease/test_disease.js b/erpnext/agriculture/doctype/disease/test_disease.js
index 57d62c16c2..33f60c4e15 100644
--- a/erpnext/agriculture/doctype/disease/test_disease.js
+++ b/erpnext/agriculture/doctype/disease/test_disease.js
@@ -36,4 +36,3 @@ QUnit.test("test: Disease", function (assert) {
]);
});
-
diff --git a/erpnext/agriculture/doctype/disease/test_disease.py b/erpnext/agriculture/doctype/disease/test_disease.py
index 54788a2c81..80861770b0 100644
--- a/erpnext/agriculture/doctype/disease/test_disease.py
+++ b/erpnext/agriculture/doctype/disease/test_disease.py
@@ -9,4 +9,4 @@ import unittest
class TestDisease(unittest.TestCase):
def test_treatment_period(self):
disease = frappe.get_doc('Disease', 'Aphids')
- self.assertEqual(disease.treatment_period, 3)
\ No newline at end of file
+ self.assertEqual(disease.treatment_period, 3)
diff --git a/erpnext/agriculture/doctype/fertilizer/fertilizer.py b/erpnext/agriculture/doctype/fertilizer/fertilizer.py
index 9cb492aff1..c475f00298 100644
--- a/erpnext/agriculture/doctype/fertilizer/fertilizer.py
+++ b/erpnext/agriculture/doctype/fertilizer/fertilizer.py
@@ -11,4 +11,4 @@ class Fertilizer(Document):
def load_contents(self):
docs = frappe.get_all("Agriculture Analysis Criteria", filters={'linked_doctype':'Fertilizer'})
for doc in docs:
- self.append('fertilizer_contents', {'title': str(doc.name)})
\ No newline at end of file
+ self.append('fertilizer_contents', {'title': str(doc.name)})
diff --git a/erpnext/agriculture/doctype/fertilizer/test_fertilizer.py b/erpnext/agriculture/doctype/fertilizer/test_fertilizer.py
index 3a25b3f0a7..4c71d33fe8 100644
--- a/erpnext/agriculture/doctype/fertilizer/test_fertilizer.py
+++ b/erpnext/agriculture/doctype/fertilizer/test_fertilizer.py
@@ -8,4 +8,4 @@ import unittest
class TestFertilizer(unittest.TestCase):
def test_fertilizer_creation(self):
- self.assertEqual(frappe.db.exists('Fertilizer', 'Urea'), 'Urea')
\ No newline at end of file
+ self.assertEqual(frappe.db.exists('Fertilizer', 'Urea'), 'Urea')
diff --git a/erpnext/agriculture/doctype/plant_analysis/plant_analysis.py b/erpnext/agriculture/doctype/plant_analysis/plant_analysis.py
index 2806cc6523..b65f93de0a 100644
--- a/erpnext/agriculture/doctype/plant_analysis/plant_analysis.py
+++ b/erpnext/agriculture/doctype/plant_analysis/plant_analysis.py
@@ -12,4 +12,4 @@ class PlantAnalysis(Document):
def load_contents(self):
docs = frappe.get_all("Agriculture Analysis Criteria", filters={'linked_doctype':'Plant Analysis'})
for doc in docs:
- self.append('plant_analysis_criteria', {'title': str(doc.name)})
\ No newline at end of file
+ self.append('plant_analysis_criteria', {'title': str(doc.name)})
diff --git a/erpnext/agriculture/doctype/soil_analysis/soil_analysis.py b/erpnext/agriculture/doctype/soil_analysis/soil_analysis.py
index 37835f8c7b..234d0d4b01 100644
--- a/erpnext/agriculture/doctype/soil_analysis/soil_analysis.py
+++ b/erpnext/agriculture/doctype/soil_analysis/soil_analysis.py
@@ -11,4 +11,4 @@ class SoilAnalysis(Document):
def load_contents(self):
docs = frappe.get_all("Agriculture Analysis Criteria", filters={'linked_doctype':'Soil Analysis'})
for doc in docs:
- self.append('soil_analysis_criteria', {'title': str(doc.name)})
\ No newline at end of file
+ self.append('soil_analysis_criteria', {'title': str(doc.name)})
diff --git a/erpnext/agriculture/doctype/soil_texture/test_soil_texture.py b/erpnext/agriculture/doctype/soil_texture/test_soil_texture.py
index 937c06ccad..16d105c9c5 100644
--- a/erpnext/agriculture/doctype/soil_texture/test_soil_texture.py
+++ b/erpnext/agriculture/doctype/soil_texture/test_soil_texture.py
@@ -11,4 +11,4 @@ class TestSoilTexture(unittest.TestCase):
soil_tex = frappe.get_all('Soil Texture', fields=['name'], filters={'collection_datetime': '2017-11-08'})
doc = frappe.get_doc('Soil Texture', soil_tex[0].name)
self.assertEqual(doc.silt_composition, 50)
- self.assertEqual(doc.soil_type, 'Silt Loam')
\ No newline at end of file
+ self.assertEqual(doc.soil_type, 'Silt Loam')
diff --git a/erpnext/agriculture/doctype/water_analysis/water_analysis.py b/erpnext/agriculture/doctype/water_analysis/water_analysis.py
index d9f007cea1..cb2691d455 100644
--- a/erpnext/agriculture/doctype/water_analysis/water_analysis.py
+++ b/erpnext/agriculture/doctype/water_analysis/water_analysis.py
@@ -24,4 +24,4 @@ class WaterAnalysis(Document):
if self.collection_datetime > self.laboratory_testing_datetime:
frappe.throw(_('Lab testing datetime cannot be before collection datetime'))
if self.laboratory_testing_datetime > self.result_datetime:
- frappe.throw(_('Lab result datetime cannot be before testing datetime'))
\ No newline at end of file
+ frappe.throw(_('Lab result datetime cannot be before testing datetime'))
diff --git a/erpnext/agriculture/setup.py b/erpnext/agriculture/setup.py
index ab91343d5d..75f07be5de 100644
--- a/erpnext/agriculture/setup.py
+++ b/erpnext/agriculture/setup.py
@@ -426,5 +426,5 @@ def create_agriculture_data():
title='Degree Days',
standard=1,
linked_doctype='Weather')
- ]
+ ]
insert_record(records)
diff --git a/erpnext/assets/dashboard_fixtures.py b/erpnext/assets/dashboard_fixtures.py
index 7f3c1de406..2c70179607 100644
--- a/erpnext/assets/dashboard_fixtures.py
+++ b/erpnext/assets/dashboard_fixtures.py
@@ -176,4 +176,4 @@ def get_number_cards(fiscal_year, year_start_date, year_end_date):
"filters_json": "[]",
"doctype": "Number Card"
}
- ]
\ No newline at end of file
+ ]
diff --git a/erpnext/assets/doctype/asset/asset.js b/erpnext/assets/doctype/asset/asset.js
index 922cc4a7b2..da5778ea3d 100644
--- a/erpnext/assets/doctype/asset/asset.js
+++ b/erpnext/assets/doctype/asset/asset.js
@@ -103,11 +103,11 @@ frappe.ui.form.on('Asset', {
frm.trigger("create_asset_maintenance");
}, __("Manage"));
}
-
+
frm.add_custom_button(__("Repair Asset"), function() {
frm.trigger("create_asset_repair");
}, __("Manage"));
-
+
if (frm.doc.status != 'Fully Depreciated') {
frm.add_custom_button(__("Adjust Asset Value"), function() {
frm.trigger("create_asset_adjustment");
diff --git a/erpnext/assets/doctype/asset/asset_dashboard.py b/erpnext/assets/doctype/asset/asset_dashboard.py
index a5cf23803d..62bb4be53a 100644
--- a/erpnext/assets/doctype/asset/asset_dashboard.py
+++ b/erpnext/assets/doctype/asset/asset_dashboard.py
@@ -11,4 +11,4 @@ def get_data():
'items': ['Asset Movement']
}
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/assets/doctype/asset/asset_list.js b/erpnext/assets/doctype/asset/asset_list.js
index 02f39e0e7f..4302cb2c51 100644
--- a/erpnext/assets/doctype/asset/asset_list.js
+++ b/erpnext/assets/doctype/asset/asset_list.js
@@ -50,4 +50,4 @@ frappe.listview_settings['Asset'] = {
});
});
},
-}
\ No newline at end of file
+}
diff --git a/erpnext/assets/doctype/asset/test_asset.py b/erpnext/assets/doctype/asset/test_asset.py
index e23a715452..605ce2e250 100644
--- a/erpnext/assets/doctype/asset/test_asset.py
+++ b/erpnext/assets/doctype/asset/test_asset.py
@@ -763,4 +763,4 @@ def set_depreciation_settings_in_company():
company.save()
# Enable booking asset depreciation entry automatically
- frappe.db.set_value("Accounts Settings", None, "book_asset_depreciation_entry_automatically", 1)
\ No newline at end of file
+ frappe.db.set_value("Accounts Settings", None, "book_asset_depreciation_entry_automatically", 1)
diff --git a/erpnext/assets/doctype/asset_category/asset_category.py b/erpnext/assets/doctype/asset_category/asset_category.py
index 46620d56e9..39032d637b 100644
--- a/erpnext/assets/doctype/asset_category/asset_category.py
+++ b/erpnext/assets/doctype/asset_category/asset_category.py
@@ -20,7 +20,7 @@ class AssetCategory(Document):
for field in ("Total Number of Depreciations", "Frequency of Depreciation"):
if cint(d.get(frappe.scrub(field)))<1:
frappe.throw(_("Row {0}: {1} must be greater than 0").format(d.idx, field), frappe.MandatoryError)
-
+
def validate_account_currency(self):
account_types = [
'fixed_asset_account', 'accumulated_depreciation_account', 'depreciation_expense_account', 'capital_work_in_progress_account'
@@ -33,13 +33,13 @@ class AssetCategory(Document):
account_currency = frappe.get_value("Account", d.get(type_of_account), "account_currency")
if account_currency != company_currency:
invalid_accounts.append(frappe._dict({ 'type': type_of_account, 'idx': d.idx, 'account': d.get(type_of_account) }))
-
+
for d in invalid_accounts:
frappe.throw(_("Row #{}: Currency of {} - {} doesn't matches company currency.")
.format(d.idx, frappe.bold(frappe.unscrub(d.type)), frappe.bold(d.account)),
title=_("Invalid Account"))
-
+
def validate_account_types(self):
account_type_map = {
'fixed_asset_account': { 'account_type': 'Fixed Asset' },
@@ -59,12 +59,12 @@ class AssetCategory(Document):
frappe.throw(_("Row #{}: {} of {} should be {}. Please modify the account or select a different account.")
.format(d.idx, frappe.unscrub(key_to_match), frappe.bold(selected_account), frappe.bold(expected_key_type)),
title=_("Invalid Account"))
-
+
def valide_cwip_account(self):
if self.enable_cwip_accounting:
missing_cwip_accounts_for_company = []
for d in self.accounts:
- if (not d.capital_work_in_progress_account and
+ if (not d.capital_work_in_progress_account and
not frappe.db.get_value("Company", d.company_name, "capital_work_in_progress_account")):
missing_cwip_accounts_for_company.append(get_link_to_form("Company", d.company_name))
@@ -93,4 +93,4 @@ def get_asset_category_account(fieldname, item=None, asset=None, account=None, a
account = frappe.db.get_value("Asset Category Account",
filters={"parent": asset_category, "company_name": company}, fieldname=fieldname)
- return account
\ No newline at end of file
+ return account
diff --git a/erpnext/assets/doctype/asset_category/test_asset_category.py b/erpnext/assets/doctype/asset_category/test_asset_category.py
index 39b79d6c50..9f7ada65d8 100644
--- a/erpnext/assets/doctype/asset_category/test_asset_category.py
+++ b/erpnext/assets/doctype/asset_category/test_asset_category.py
@@ -10,9 +10,9 @@ class TestAssetCategory(unittest.TestCase):
def test_mandatory_fields(self):
asset_category = frappe.new_doc("Asset Category")
asset_category.asset_category_name = "Computers"
-
+
self.assertRaises(frappe.MandatoryError, asset_category.insert)
-
+
asset_category.total_number_of_depreciations = 3
asset_category.frequency_of_depreciation = 3
asset_category.append("accounts", {
@@ -21,7 +21,7 @@ class TestAssetCategory(unittest.TestCase):
"accumulated_depreciation_account": "_Test Accumulated Depreciations - _TC",
"depreciation_expense_account": "_Test Depreciations - _TC"
})
-
+
try:
asset_category.insert()
except frappe.DuplicateEntryError:
@@ -44,4 +44,4 @@ class TestAssetCategory(unittest.TestCase):
"depreciation_expense_account": "_Test Depreciations - _TC"
})
- self.assertRaises(frappe.ValidationError, asset_category.insert)
\ No newline at end of file
+ self.assertRaises(frappe.ValidationError, asset_category.insert)
diff --git a/erpnext/assets/doctype/asset_maintenance/asset_maintenance.js b/erpnext/assets/doctype/asset_maintenance/asset_maintenance.js
index 70b8654509..52996e9347 100644
--- a/erpnext/assets/doctype/asset_maintenance/asset_maintenance.js
+++ b/erpnext/assets/doctype/asset_maintenance/asset_maintenance.js
@@ -97,4 +97,4 @@ var get_next_due_date = function (frm, cdt, cdn) {
}
});
}
-};
\ No newline at end of file
+};
diff --git a/erpnext/assets/doctype/asset_maintenance/asset_maintenance.py b/erpnext/assets/doctype/asset_maintenance/asset_maintenance.py
index a506deec93..e14f1d88dc 100644
--- a/erpnext/assets/doctype/asset_maintenance/asset_maintenance.py
+++ b/erpnext/assets/doctype/asset_maintenance/asset_maintenance.py
@@ -116,4 +116,4 @@ def get_maintenance_log(asset_name):
select maintenance_status, count(asset_name) as count, asset_name
from `tabAsset Maintenance Log`
where asset_name=%s group by maintenance_status""",
- (asset_name), as_dict=1)
\ No newline at end of file
+ (asset_name), as_dict=1)
diff --git a/erpnext/assets/doctype/asset_maintenance/test_asset_maintenance.py b/erpnext/assets/doctype/asset_maintenance/test_asset_maintenance.py
index 392fbdd2af..7610152039 100644
--- a/erpnext/assets/doctype/asset_maintenance/test_asset_maintenance.py
+++ b/erpnext/assets/doctype/asset_maintenance/test_asset_maintenance.py
@@ -73,7 +73,7 @@ def create_asset_data():
'doctype': 'Location',
'location_name': 'Test Location'
}).insert()
-
+
if not frappe.db.exists("Item", "Photocopier"):
meta = frappe.get_meta('Asset')
naming_series = meta.get_field("naming_series").options
@@ -157,6 +157,6 @@ def set_depreciation_settings_in_company():
company.disposal_account = "_Test Gain/Loss on Asset Disposal - _TC"
company.depreciation_cost_center = "_Test Cost Center - _TC"
company.save()
-
+
# Enable booking asset depreciation entry automatically
- frappe.db.set_value("Accounts Settings", None, "book_asset_depreciation_entry_automatically", 1)
\ No newline at end of file
+ frappe.db.set_value("Accounts Settings", None, "book_asset_depreciation_entry_automatically", 1)
diff --git a/erpnext/assets/doctype/asset_maintenance_log/asset_maintenance_log.js b/erpnext/assets/doctype/asset_maintenance_log/asset_maintenance_log.js
index c5db90ad37..bcdc3acf0a 100644
--- a/erpnext/assets/doctype/asset_maintenance_log/asset_maintenance_log.js
+++ b/erpnext/assets/doctype/asset_maintenance_log/asset_maintenance_log.js
@@ -12,4 +12,4 @@ frappe.ui.form.on('Asset Maintenance Log', {
};
});
}
-});
\ No newline at end of file
+});
diff --git a/erpnext/assets/doctype/asset_movement/asset_movement.js b/erpnext/assets/doctype/asset_movement/asset_movement.js
index 06d8879091..2df7db9744 100644
--- a/erpnext/assets/doctype/asset_movement/asset_movement.js
+++ b/erpnext/assets/doctype/asset_movement/asset_movement.js
@@ -99,4 +99,4 @@ frappe.ui.form.on('Asset Movement Item', {
});
}
}
-});
\ No newline at end of file
+});
diff --git a/erpnext/assets/doctype/asset_movement/asset_movement.py b/erpnext/assets/doctype/asset_movement/asset_movement.py
index b2de250b16..1771e27ddf 100644
--- a/erpnext/assets/doctype/asset_movement/asset_movement.py
+++ b/erpnext/assets/doctype/asset_movement/asset_movement.py
@@ -40,14 +40,14 @@ class AssetMovement(Document):
if current_location != d.source_location:
frappe.throw(_("Asset {0} does not belongs to the location {1}").
format(d.asset, d.source_location))
-
+
if self.purpose == 'Issue':
if d.target_location:
frappe.throw(_("Issuing cannot be done to a location. \
Please enter employee who has issued Asset {0}").format(d.asset), title="Incorrect Movement Purpose")
if not d.to_employee:
frappe.throw(_("Employee is required while issuing Asset {0}").format(d.asset))
-
+
if self.purpose == 'Transfer':
if d.to_employee:
frappe.throw(_("Transferring cannot be done to an Employee. \
@@ -57,7 +57,7 @@ class AssetMovement(Document):
frappe.throw(_("Target Location is required while transferring Asset {0}").format(d.asset))
if d.source_location == d.target_location:
frappe.throw(_("Source and Target Location cannot be same"))
-
+
if self.purpose == 'Receipt':
# only when asset is bought and first entry is made
if not d.source_location and not (d.target_location or d.to_employee):
@@ -80,14 +80,14 @@ class AssetMovement(Document):
if current_custodian != d.from_employee:
frappe.throw(_("Asset {0} does not belongs to the custodian {1}").
format(d.asset, d.from_employee))
-
+
if d.to_employee and frappe.db.get_value("Employee", d.to_employee, "company") != self.company:
frappe.throw(_("Employee {0} does not belongs to the company {1}").
format(d.to_employee, self.company))
def on_submit(self):
self.set_latest_location_in_asset()
-
+
def on_cancel(self):
self.set_latest_location_in_asset()
@@ -105,12 +105,12 @@ class AssetMovement(Document):
# In case of cancellation it corresponds to previous latest document's location, employee
latest_movement_entry = frappe.db.sql(
"""
- SELECT asm_item.target_location, asm_item.to_employee
+ SELECT asm_item.target_location, asm_item.to_employee
FROM `tabAsset Movement Item` asm_item, `tabAsset Movement` asm
- WHERE
+ WHERE
asm_item.parent=asm.name and
asm_item.asset=%(asset)s and
- asm.company=%(company)s and
+ asm.company=%(company)s and
asm.docstatus=1 and {0}
ORDER BY
asm.transaction_date desc limit 1
diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.js b/erpnext/assets/doctype/asset_repair/asset_repair.js
index 1cebfff66e..18a56d33e6 100644
--- a/erpnext/assets/doctype/asset_repair/asset_repair.js
+++ b/erpnext/assets/doctype/asset_repair/asset_repair.js
@@ -59,7 +59,7 @@ frappe.ui.form.on('Asset Repair', {
if (frm.doc.repair_status == "Completed") {
frm.set_value('completion_date', frappe.datetime.now_datetime());
- }
+ }
}
});
@@ -68,4 +68,4 @@ frappe.ui.form.on('Asset Repair Consumed Item', {
var row = locals[cdt][cdn];
frappe.model.set_value(cdt, cdn, 'total_value', row.consumed_quantity * row.valuation_rate);
},
-});
\ No newline at end of file
+});
diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.py b/erpnext/assets/doctype/asset_repair/asset_repair.py
index d32fdf7054..746f582fdc 100644
--- a/erpnext/assets/doctype/asset_repair/asset_repair.py
+++ b/erpnext/assets/doctype/asset_repair/asset_repair.py
@@ -18,7 +18,7 @@ class AssetRepair(AccountsController):
if self.get('stock_items'):
self.set_total_value()
self.calculate_total_repair_cost()
-
+
def update_status(self):
if self.repair_status == 'Pending':
frappe.db.set_value('Asset', self.asset, 'status', 'Out of Order')
@@ -98,7 +98,7 @@ class AssetRepair(AccountsController):
if self.capitalize_repair_cost:
row.value_after_depreciation -= self.repair_cost
-
+
def get_total_value_of_stock_consumed(self):
total_value_of_stock_consumed = 0
if self.get('stock_consumption'):
@@ -141,7 +141,7 @@ class AssetRepair(AccountsController):
gl_entries = []
repair_and_maintenance_account = frappe.db.get_value('Company', self.company, 'repair_and_maintenance_account')
fixed_asset_account = get_asset_account("fixed_asset_account", asset=self.asset, company=self.company)
- expense_account = frappe.get_doc('Purchase Invoice', self.purchase_invoice).items[0].expense_account
+ expense_account = frappe.get_doc('Purchase Invoice', self.purchase_invoice).items[0].expense_account
gl_entries.append(
self.get_gl_dict({
@@ -149,7 +149,7 @@ class AssetRepair(AccountsController):
"credit": self.repair_cost,
"credit_in_account_currency": self.repair_cost,
"against": repair_and_maintenance_account,
- "voucher_type": self.doctype,
+ "voucher_type": self.doctype,
"voucher_no": self.name,
"cost_center": self.cost_center,
"posting_date": getdate(),
@@ -167,7 +167,7 @@ class AssetRepair(AccountsController):
"credit": item.amount,
"credit_in_account_currency": item.amount,
"against": repair_and_maintenance_account,
- "voucher_type": self.doctype,
+ "voucher_type": self.doctype,
"voucher_no": self.name,
"cost_center": self.cost_center,
"posting_date": getdate(),
diff --git a/erpnext/assets/doctype/asset_repair/asset_repair_list.js b/erpnext/assets/doctype/asset_repair/asset_repair_list.js
index f36fd2f8dc..86376f4004 100644
--- a/erpnext/assets/doctype/asset_repair/asset_repair_list.js
+++ b/erpnext/assets/doctype/asset_repair/asset_repair_list.js
@@ -10,4 +10,3 @@ frappe.listview_settings['Asset Repair'] = {
}
}
};
-
diff --git a/erpnext/assets/doctype/asset_repair/test_asset_repair.py b/erpnext/assets/doctype/asset_repair/test_asset_repair.py
index 30bbb37851..5e727d007a 100644
--- a/erpnext/assets/doctype/asset_repair/test_asset_repair.py
+++ b/erpnext/assets/doctype/asset_repair/test_asset_repair.py
@@ -41,7 +41,7 @@ class TestAssetRepair(unittest.TestCase):
self.assertEqual(total_repair_cost, asset_repair.repair_cost)
for item in asset_repair.stock_items:
total_repair_cost += item.total_value
-
+
self.assertEqual(total_repair_cost, asset_repair.total_repair_cost)
def test_repair_status_after_submit(self):
@@ -99,7 +99,7 @@ class TestAssetRepair(unittest.TestCase):
initial_num_of_depreciations = num_of_depreciations(asset)
create_asset_repair(asset= asset, capitalize_repair_cost = 1, submit = 1)
asset.reload()
-
+
self.assertEqual((initial_num_of_depreciations + 1), num_of_depreciations(asset))
self.assertEqual(asset.schedules[-1].accumulated_depreciation_amount, asset.finance_books[0].value_after_depreciation)
@@ -139,7 +139,7 @@ def create_asset_repair(**args):
})
asset_repair.insert(ignore_if_duplicate=True)
-
+
if args.submit:
asset_repair.repair_status = "Completed"
asset_repair.cost_center = "_Test Cost Center - _TC"
@@ -165,4 +165,4 @@ def create_asset_repair(**args):
asset_repair.purchase_invoice = make_purchase_invoice().name
asset_repair.submit()
- return asset_repair
\ No newline at end of file
+ return asset_repair
diff --git a/erpnext/assets/doctype/asset_value_adjustment/test_asset_value_adjustment.py b/erpnext/assets/doctype/asset_value_adjustment/test_asset_value_adjustment.py
index 03dc47b0bb..a9dc9795ee 100644
--- a/erpnext/assets/doctype/asset_value_adjustment/test_asset_value_adjustment.py
+++ b/erpnext/assets/doctype/asset_value_adjustment/test_asset_value_adjustment.py
@@ -91,4 +91,4 @@ def make_asset_value_adjustment(**args):
"cost_center": args.cost_center or "Main - _TC"
}).insert()
- return doc
\ No newline at end of file
+ return doc
diff --git a/erpnext/assets/doctype/location/location_tree.js b/erpnext/assets/doctype/location/location_tree.js
index b405afd1dd..3e105f6ca4 100644
--- a/erpnext/assets/doctype/location/location_tree.js
+++ b/erpnext/assets/doctype/location/location_tree.js
@@ -30,4 +30,4 @@ frappe.treeview_settings["Location"] = {
onload: function (treeview) {
treeview.make_tree();
}
-};
\ No newline at end of file
+};
diff --git a/erpnext/assets/report/fixed_asset_register/fixed_asset_register.js b/erpnext/assets/report/fixed_asset_register/fixed_asset_register.js
index 1a6ef54a83..75f42a9f78 100644
--- a/erpnext/assets/report/fixed_asset_register/fixed_asset_register.js
+++ b/erpnext/assets/report/fixed_asset_register/fixed_asset_register.js
@@ -76,7 +76,7 @@ frappe.query_reports["Fixed Asset Register"] = {
fieldtype: "Link",
options: "Asset Category"
},
- {
+ {
fieldname:"finance_book",
label: __("Finance Book"),
fieldtype: "Link",
diff --git a/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py b/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py
index d1457b9b85..7d07397944 100644
--- a/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py
+++ b/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py
@@ -99,7 +99,7 @@ def prepare_chart_data(data, filters):
labels_values_map = {}
date_field = frappe.scrub(filters.date_based_on)
- period_list = get_period_list(filters.from_fiscal_year, filters.to_fiscal_year,
+ period_list = get_period_list(filters.from_fiscal_year, filters.to_fiscal_year,
filters.from_date, filters.to_date, filters.filter_based_on, "Monthly", company=filters.company)
for d in period_list:
@@ -293,4 +293,4 @@ def get_columns(filters):
"options": "Location",
"width": 100
},
- ]
\ No newline at end of file
+ ]
diff --git a/erpnext/buying/doctype/buying_settings/buying_settings.js b/erpnext/buying/doctype/buying_settings/buying_settings.js
index e496e9628d..944bb61cfe 100644
--- a/erpnext/buying/doctype/buying_settings/buying_settings.js
+++ b/erpnext/buying/doctype/buying_settings/buying_settings.js
@@ -28,4 +28,4 @@ frappe.tour['Buying Settings'] = [
title: "Purchase Receipt Required for Purchase Invoice Creation",
description: __("If this option is configured 'Yes', ERPNext will prevent you from creating a Purchase Invoice without creating a Purchase Receipt first. This configuration can be overridden for a particular supplier by enabling the 'Allow Purchase Invoice Creation Without Purchase Receipt' checkbox in the Supplier master.")
}
-];
\ No newline at end of file
+];
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py
index a0b1e073cc..ca3bd90960 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.py
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.py
@@ -635,4 +635,4 @@ def add_items_in_ste(ste_doc, row, qty, po_details, batch_no=None):
'item_code': row.item_details['rm_item_code'],
'subcontracted_item': row.item_details['main_item_code'],
'serial_no': '\n'.join(row.serial_no) if row.serial_no else ''
- })
\ No newline at end of file
+ })
diff --git a/erpnext/buying/doctype/purchase_order/regional/india.js b/erpnext/buying/doctype/purchase_order/regional/india.js
index 42d3995907..ef83f203e7 100644
--- a/erpnext/buying/doctype/purchase_order/regional/india.js
+++ b/erpnext/buying/doctype/purchase_order/regional/india.js
@@ -1,3 +1,3 @@
{% include "erpnext/regional/india/taxes.js" %}
-erpnext.setup_auto_gst_taxation('Purchase Order');
\ No newline at end of file
+erpnext.setup_auto_gst_taxation('Purchase Order');
diff --git a/erpnext/buying/doctype/purchase_order/test_purchase_order.py b/erpnext/buying/doctype/purchase_order/test_purchase_order.py
index d668c76b6b..fa174ba8fa 100644
--- a/erpnext/buying/doctype/purchase_order/test_purchase_order.py
+++ b/erpnext/buying/doctype/purchase_order/test_purchase_order.py
@@ -485,7 +485,7 @@ class TestPurchaseOrder(unittest.TestCase):
def test_make_purchase_invoice_with_terms(self):
from erpnext.selling.doctype.sales_order.test_sales_order import automatically_fetch_payment_terms, compare_payment_schedules
-
+
automatically_fetch_payment_terms()
po = create_purchase_order(do_not_save=True)
diff --git a/erpnext/buying/doctype/purchase_order/tests/test_purchase_order.js b/erpnext/buying/doctype/purchase_order/tests/test_purchase_order.js
index 5d196874c9..012b0619cc 100644
--- a/erpnext/buying/doctype/purchase_order/tests/test_purchase_order.js
+++ b/erpnext/buying/doctype/purchase_order/tests/test_purchase_order.js
@@ -77,4 +77,4 @@ QUnit.test("test: purchase order", function(assert) {
() => done()
]);
-});
\ No newline at end of file
+});
diff --git a/erpnext/buying/doctype/purchase_order/tests/test_purchase_order_get_items.js b/erpnext/buying/doctype/purchase_order/tests/test_purchase_order_get_items.js
index 8c0c144314..bc3d767f95 100644
--- a/erpnext/buying/doctype/purchase_order/tests/test_purchase_order_get_items.js
+++ b/erpnext/buying/doctype/purchase_order/tests/test_purchase_order_get_items.js
@@ -58,4 +58,4 @@ QUnit.test("test: purchase order with get items", function(assert) {
() => done()
]);
-});
\ No newline at end of file
+});
diff --git a/erpnext/buying/doctype/purchase_order/tests/test_purchase_order_with_discount_on_grand_total.js b/erpnext/buying/doctype/purchase_order/tests/test_purchase_order_with_discount_on_grand_total.js
index 4e73ab8ef4..83eb295010 100644
--- a/erpnext/buying/doctype/purchase_order/tests/test_purchase_order_with_discount_on_grand_total.js
+++ b/erpnext/buying/doctype/purchase_order/tests/test_purchase_order_with_discount_on_grand_total.js
@@ -44,4 +44,4 @@ QUnit.test("test: purchase order with discount on grand total", function(assert)
() => done()
]);
-});
\ No newline at end of file
+});
diff --git a/erpnext/buying/doctype/purchase_order/tests/test_purchase_order_with_item_wise_discount.js b/erpnext/buying/doctype/purchase_order/tests/test_purchase_order_with_item_wise_discount.js
index 1e54e50dda..a729dd9839 100644
--- a/erpnext/buying/doctype/purchase_order/tests/test_purchase_order_with_item_wise_discount.js
+++ b/erpnext/buying/doctype/purchase_order/tests/test_purchase_order_with_item_wise_discount.js
@@ -41,4 +41,4 @@ QUnit.test("test: purchase order with item wise discount", function(assert) {
() => done()
]);
-});
\ No newline at end of file
+});
diff --git a/erpnext/buying/doctype/purchase_order/tests/test_purchase_order_with_multi_uom.js b/erpnext/buying/doctype/purchase_order/tests/test_purchase_order_with_multi_uom.js
index bf2dfeb37b..b605e76ddf 100644
--- a/erpnext/buying/doctype/purchase_order/tests/test_purchase_order_with_multi_uom.js
+++ b/erpnext/buying/doctype/purchase_order/tests/test_purchase_order_with_multi_uom.js
@@ -36,4 +36,4 @@ QUnit.test("test: purchase order with multi UOM", function(assert) {
() => done()
]);
-});
\ No newline at end of file
+});
diff --git a/erpnext/buying/doctype/purchase_order/tests/test_purchase_order_with_shipping_rule.js b/erpnext/buying/doctype/purchase_order/tests/test_purchase_order_with_shipping_rule.js
index 96775eb007..c258756b2a 100644
--- a/erpnext/buying/doctype/purchase_order/tests/test_purchase_order_with_shipping_rule.js
+++ b/erpnext/buying/doctype/purchase_order/tests/test_purchase_order_with_shipping_rule.js
@@ -40,4 +40,4 @@ QUnit.test("test: purchase order with shipping rule", function(assert) {
() => frappe.timeout(0.3),
() => done()
]);
-});
\ No newline at end of file
+});
diff --git a/erpnext/buying/doctype/purchase_order/tests/test_purchase_order_with_taxes_and_charges.js b/erpnext/buying/doctype/purchase_order/tests/test_purchase_order_with_taxes_and_charges.js
index 39716ed560..ccc383fd74 100644
--- a/erpnext/buying/doctype/purchase_order/tests/test_purchase_order_with_taxes_and_charges.js
+++ b/erpnext/buying/doctype/purchase_order/tests/test_purchase_order_with_taxes_and_charges.js
@@ -41,4 +41,4 @@ QUnit.test("test: purchase order with taxes and charges", function(assert) {
() => frappe.timeout(0.3),
() => done()
]);
-});
\ No newline at end of file
+});
diff --git a/erpnext/buying/doctype/purchase_order_item/purchase_order_item.py b/erpnext/buying/doctype/purchase_order_item/purchase_order_item.py
index 8bdcd47e02..b6e28b6c67 100644
--- a/erpnext/buying/doctype/purchase_order_item/purchase_order_item.py
+++ b/erpnext/buying/doctype/purchase_order_item/purchase_order_item.py
@@ -10,4 +10,4 @@ class PurchaseOrderItem(Document):
pass
def on_doctype_update():
- frappe.db.add_index("Purchase Order Item", ["item_code", "warehouse"])
\ No newline at end of file
+ frappe.db.add_index("Purchase Order Item", ["item_code", "warehouse"])
diff --git a/erpnext/buying/doctype/purchase_order_item_supplied/purchase_order_item_supplied.py b/erpnext/buying/doctype/purchase_order_item_supplied/purchase_order_item_supplied.py
index 6caffbda1f..c85ca2fbaf 100644
--- a/erpnext/buying/doctype/purchase_order_item_supplied/purchase_order_item_supplied.py
+++ b/erpnext/buying/doctype/purchase_order_item_supplied/purchase_order_item_supplied.py
@@ -7,4 +7,4 @@ import frappe
from frappe.model.document import Document
class PurchaseOrderItemSupplied(Document):
- pass
\ No newline at end of file
+ pass
diff --git a/erpnext/buying/doctype/purchase_receipt_item_supplied/purchase_receipt_item_supplied.py b/erpnext/buying/doctype/purchase_receipt_item_supplied/purchase_receipt_item_supplied.py
index 1a76f0ee7d..00c93ed1ea 100644
--- a/erpnext/buying/doctype/purchase_receipt_item_supplied/purchase_receipt_item_supplied.py
+++ b/erpnext/buying/doctype/purchase_receipt_item_supplied/purchase_receipt_item_supplied.py
@@ -7,4 +7,4 @@ import frappe
from frappe.model.document import Document
class PurchaseReceiptItemSupplied(Document):
- pass
\ No newline at end of file
+ pass
diff --git a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py
index a4ce84e1cf..8ed6c9e2a6 100644
--- a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py
+++ b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py
@@ -425,4 +425,4 @@ def get_rfq_containing_supplier(doctype, txt, searchfield, start, page_len, filt
.format(filters.get("supplier"), filters.get("company"), conditions),
{"page_len": page_len, "start": start}, as_dict=1)
- return rfq_data
\ No newline at end of file
+ return rfq_data
diff --git a/erpnext/buying/doctype/request_for_quotation/request_for_quotation_dashboard.py b/erpnext/buying/doctype/request_for_quotation/request_for_quotation_dashboard.py
index 6efbc78225..751336dc4c 100644
--- a/erpnext/buying/doctype/request_for_quotation/request_for_quotation_dashboard.py
+++ b/erpnext/buying/doctype/request_for_quotation/request_for_quotation_dashboard.py
@@ -10,4 +10,4 @@ def get_data():
'items': ['Supplier Quotation']
},
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/buying/doctype/request_for_quotation/tests/test_request_for_quotation.js b/erpnext/buying/doctype/request_for_quotation/tests/test_request_for_quotation.js
index 1fcfe75bb0..75f85f86d1 100644
--- a/erpnext/buying/doctype/request_for_quotation/tests/test_request_for_quotation.js
+++ b/erpnext/buying/doctype/request_for_quotation/tests/test_request_for_quotation.js
@@ -73,4 +73,4 @@ QUnit.test("test: request_for_quotation", function(assert) {
() => frappe.click_button('Close'),
() => done()
]);
-});
\ No newline at end of file
+});
diff --git a/erpnext/buying/doctype/request_for_quotation/tests/test_request_for_quotation_for_status.js b/erpnext/buying/doctype/request_for_quotation/tests/test_request_for_quotation_for_status.js
index 2e1652de73..f06c3f34c4 100644
--- a/erpnext/buying/doctype/request_for_quotation/tests/test_request_for_quotation_for_status.js
+++ b/erpnext/buying/doctype/request_for_quotation/tests/test_request_for_quotation_for_status.js
@@ -125,4 +125,4 @@ QUnit.test("Test: Request for Quotation", function (assert) {
},
() => done()
]);
-});
\ No newline at end of file
+});
diff --git a/erpnext/buying/doctype/supplier/regional/india.js b/erpnext/buying/doctype/supplier/regional/india.js
index bd710e0df7..5f49a47e75 100644
--- a/erpnext/buying/doctype/supplier/regional/india.js
+++ b/erpnext/buying/doctype/supplier/regional/india.js
@@ -1,3 +1,3 @@
{% include "erpnext/regional/india/party.js" %}
-erpnext.setup_gst_reminder_button('Supplier');
\ No newline at end of file
+erpnext.setup_gst_reminder_button('Supplier');
diff --git a/erpnext/buying/doctype/supplier/test_supplier.js b/erpnext/buying/doctype/supplier/test_supplier.js
index bf7c192c91..eaa4d0989d 100644
--- a/erpnext/buying/doctype/supplier/test_supplier.js
+++ b/erpnext/buying/doctype/supplier/test_supplier.js
@@ -74,4 +74,4 @@ QUnit.test("test: supplier", function(assert) {
},
() => done()
]);
-});
\ No newline at end of file
+});
diff --git a/erpnext/buying/doctype/supplier_item_group/supplier_item_group.py b/erpnext/buying/doctype/supplier_item_group/supplier_item_group.py
index 3a2e5d6dce..4473ddea28 100644
--- a/erpnext/buying/doctype/supplier_item_group/supplier_item_group.py
+++ b/erpnext/buying/doctype/supplier_item_group/supplier_item_group.py
@@ -15,4 +15,4 @@ class SupplierItemGroup(Document):
'item_group': self.item_group
})
if exists:
- frappe.throw(_("Item Group has already been linked to this supplier."))
\ No newline at end of file
+ frappe.throw(_("Item Group has already been linked to this supplier."))
diff --git a/erpnext/buying/doctype/supplier_quotation/supplier_quotation.py b/erpnext/buying/doctype/supplier_quotation/supplier_quotation.py
index 6a4c02c075..25e4e2a4dc 100644
--- a/erpnext/buying/doctype/supplier_quotation/supplier_quotation.py
+++ b/erpnext/buying/doctype/supplier_quotation/supplier_quotation.py
@@ -166,4 +166,4 @@ def set_expired_status():
`tabSupplier Quotation` SET `status` = 'Expired'
WHERE
`status` not in ('Cancelled', 'Stopped') AND `valid_till` < %s
- """, (nowdate()))
\ No newline at end of file
+ """, (nowdate()))
diff --git a/erpnext/buying/doctype/supplier_quotation/tests/test_supplier_quotation.js b/erpnext/buying/doctype/supplier_quotation/tests/test_supplier_quotation.js
index 2d2b29cb91..20fb43026a 100644
--- a/erpnext/buying/doctype/supplier_quotation/tests/test_supplier_quotation.js
+++ b/erpnext/buying/doctype/supplier_quotation/tests/test_supplier_quotation.js
@@ -71,4 +71,4 @@ QUnit.test("test: supplier quotation", function(assert) {
() => done()
]);
-});
\ No newline at end of file
+});
diff --git a/erpnext/buying/doctype/supplier_quotation/tests/test_supplier_quotation_for_item_wise_discount.js b/erpnext/buying/doctype/supplier_quotation/tests/test_supplier_quotation_for_item_wise_discount.js
index b151824ba6..0a51565b08 100644
--- a/erpnext/buying/doctype/supplier_quotation/tests/test_supplier_quotation_for_item_wise_discount.js
+++ b/erpnext/buying/doctype/supplier_quotation/tests/test_supplier_quotation_for_item_wise_discount.js
@@ -31,4 +31,4 @@ QUnit.test("test: supplier quotation with item wise discount", function(assert){
() => frappe.timeout(0.3),
() => done()
]);
-});
\ No newline at end of file
+});
diff --git a/erpnext/buying/doctype/supplier_quotation/tests/test_supplier_quotation_for_taxes_and_charges.js b/erpnext/buying/doctype/supplier_quotation/tests/test_supplier_quotation_for_taxes_and_charges.js
index e37731eb57..7ea3e6079c 100644
--- a/erpnext/buying/doctype/supplier_quotation/tests/test_supplier_quotation_for_taxes_and_charges.js
+++ b/erpnext/buying/doctype/supplier_quotation/tests/test_supplier_quotation_for_taxes_and_charges.js
@@ -34,4 +34,4 @@ QUnit.test("test: supplier quotation with taxes and charges", function(assert) {
() => frappe.timeout(0.3),
() => done()
]);
-});
\ No newline at end of file
+});
diff --git a/erpnext/buying/doctype/supplier_scorecard/supplier_scorecard.js b/erpnext/buying/doctype/supplier_scorecard/supplier_scorecard.js
index 5f5f54b79f..b4cd852c32 100644
--- a/erpnext/buying/doctype/supplier_scorecard/supplier_scorecard.js
+++ b/erpnext/buying/doctype/supplier_scorecard/supplier_scorecard.js
@@ -93,5 +93,3 @@ var loadAllStandings = function(frm) {
}
});
};
-
-
diff --git a/erpnext/buying/doctype/supplier_scorecard/supplier_scorecard_dashboard.py b/erpnext/buying/doctype/supplier_scorecard/supplier_scorecard_dashboard.py
index 3d2305e285..8e5cce5696 100644
--- a/erpnext/buying/doctype/supplier_scorecard/supplier_scorecard_dashboard.py
+++ b/erpnext/buying/doctype/supplier_scorecard/supplier_scorecard_dashboard.py
@@ -13,4 +13,4 @@ def get_data():
'items': ['Supplier Scorecard Period']
}
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/buying/doctype/supplier_scorecard/test_supplier_scorecard.py b/erpnext/buying/doctype/supplier_scorecard/test_supplier_scorecard.py
index 2528240549..a5f05ea525 100644
--- a/erpnext/buying/doctype/supplier_scorecard/test_supplier_scorecard.py
+++ b/erpnext/buying/doctype/supplier_scorecard/test_supplier_scorecard.py
@@ -128,4 +128,3 @@ valid_scorecard = [
"weighting_function":"{total_score} * max( 0, min ( 1 , (12 - {period_number}) / 12) )"
}
]
-
diff --git a/erpnext/buying/doctype/supplier_scorecard_criteria/test_supplier_scorecard_criteria.py b/erpnext/buying/doctype/supplier_scorecard_criteria/test_supplier_scorecard_criteria.py
index 4eef4b4e03..3babfc8cab 100644
--- a/erpnext/buying/doctype/supplier_scorecard_criteria/test_supplier_scorecard_criteria.py
+++ b/erpnext/buying/doctype/supplier_scorecard_criteria/test_supplier_scorecard_criteria.py
@@ -72,4 +72,4 @@ test_bad_criteria = [
"criteria_name":"Fake Criteria 3",
"max_score":100.0
},
-]
\ No newline at end of file
+]
diff --git a/erpnext/buying/doctype/supplier_scorecard_period/supplier_scorecard_period.py b/erpnext/buying/doctype/supplier_scorecard_period/supplier_scorecard_period.py
index 9938710e6e..cc345e96bb 100644
--- a/erpnext/buying/doctype/supplier_scorecard_period/supplier_scorecard_period.py
+++ b/erpnext/buying/doctype/supplier_scorecard_period/supplier_scorecard_period.py
@@ -109,4 +109,3 @@ def make_supplier_scorecard(source_name, target_doc=None):
}, target_doc, post_process, ignore_permissions=True)
return doc
-
diff --git a/erpnext/buying/doctype/supplier_scorecard_standing/supplier_scorecard_standing.py b/erpnext/buying/doctype/supplier_scorecard_standing/supplier_scorecard_standing.py
index 1ba5d06c53..678855a457 100644
--- a/erpnext/buying/doctype/supplier_scorecard_standing/supplier_scorecard_standing.py
+++ b/erpnext/buying/doctype/supplier_scorecard_standing/supplier_scorecard_standing.py
@@ -26,4 +26,4 @@ def get_standings_list():
`tabSupplier Scorecard Standing` scs""",
{}, as_dict=1)
- return standings
\ No newline at end of file
+ return standings
diff --git a/erpnext/buying/doctype/supplier_scorecard_variable/supplier_scorecard_variable.py b/erpnext/buying/doctype/supplier_scorecard_variable/supplier_scorecard_variable.py
index 37fdc5724f..89a6459bba 100644
--- a/erpnext/buying/doctype/supplier_scorecard_variable/supplier_scorecard_variable.py
+++ b/erpnext/buying/doctype/supplier_scorecard_variable/supplier_scorecard_variable.py
@@ -493,4 +493,4 @@ def get_rfq_response_days(scorecard):
total_sq_days = 0
- return total_sq_days
\ No newline at end of file
+ return total_sq_days
diff --git a/erpnext/buying/doctype/supplier_scorecard_variable/test_supplier_scorecard_variable.py b/erpnext/buying/doctype/supplier_scorecard_variable/test_supplier_scorecard_variable.py
index fe6dde5048..14b87105e6 100644
--- a/erpnext/buying/doctype/supplier_scorecard_variable/test_supplier_scorecard_variable.py
+++ b/erpnext/buying/doctype/supplier_scorecard_variable/test_supplier_scorecard_variable.py
@@ -54,4 +54,4 @@ test_bad_variables = [
"variable_label":"Fake Variable 1",
"path":"get_fake_variable1"
},
-]
\ No newline at end of file
+]
diff --git a/erpnext/buying/report/procurement_tracker/procurement_tracker.py b/erpnext/buying/report/procurement_tracker/procurement_tracker.py
index beeca091c8..99bcbe633c 100644
--- a/erpnext/buying/report/procurement_tracker/procurement_tracker.py
+++ b/erpnext/buying/report/procurement_tracker/procurement_tracker.py
@@ -296,4 +296,4 @@ def get_po_entries(conditions):
{conditions}
GROUP BY
parent.name, child.item_code
- """.format(conditions=conditions), as_dict=1) #nosec
\ No newline at end of file
+ """.format(conditions=conditions), as_dict=1) #nosec
diff --git a/erpnext/buying/report/procurement_tracker/test_procurement_tracker.py b/erpnext/buying/report/procurement_tracker/test_procurement_tracker.py
index 44ab767c0a..c36083f2af 100644
--- a/erpnext/buying/report/procurement_tracker/test_procurement_tracker.py
+++ b/erpnext/buying/report/procurement_tracker/test_procurement_tracker.py
@@ -68,4 +68,4 @@ class TestProcurementTracker(unittest.TestCase):
"actual_delivery_date": date_obj
}
- return expected_data
\ No newline at end of file
+ return expected_data
diff --git a/erpnext/buying/report/purchase_order_analysis/purchase_order_analysis.py b/erpnext/buying/report/purchase_order_analysis/purchase_order_analysis.py
index 89be62231b..bda172769a 100644
--- a/erpnext/buying/report/purchase_order_analysis/purchase_order_analysis.py
+++ b/erpnext/buying/report/purchase_order_analysis/purchase_order_analysis.py
@@ -268,4 +268,3 @@ def get_columns(filters):
])
return columns
-
diff --git a/erpnext/buying/report/purchase_order_trends/purchase_order_trends.js b/erpnext/buying/report/purchase_order_trends/purchase_order_trends.js
index 83d25d80ba..90919dcc6a 100644
--- a/erpnext/buying/report/purchase_order_trends/purchase_order_trends.js
+++ b/erpnext/buying/report/purchase_order_trends/purchase_order_trends.js
@@ -5,4 +5,4 @@ frappe.require("assets/erpnext/js/purchase_trends_filters.js", function() {
frappe.query_reports["Purchase Order Trends"] = {
filters: erpnext.get_purchase_trends_filters()
}
-});
\ No newline at end of file
+});
diff --git a/erpnext/buying/report/purchase_order_trends/purchase_order_trends.py b/erpnext/buying/report/purchase_order_trends/purchase_order_trends.py
index 1ed6cad6b4..095a44319d 100644
--- a/erpnext/buying/report/purchase_order_trends/purchase_order_trends.py
+++ b/erpnext/buying/report/purchase_order_trends/purchase_order_trends.py
@@ -55,4 +55,4 @@ def get_chart_data(data, conditions, filters):
"lineOptions": {
"regionFill": 1
}
- }
\ No newline at end of file
+ }
diff --git a/erpnext/buying/report/subcontract_order_summary/subcontract_order_summary.py b/erpnext/buying/report/subcontract_order_summary/subcontract_order_summary.py
index 0c0d4f0531..9a45972837 100644
--- a/erpnext/buying/report/subcontract_order_summary/subcontract_order_summary.py
+++ b/erpnext/buying/report/subcontract_order_summary/subcontract_order_summary.py
@@ -149,4 +149,4 @@ def get_columns():
"fieldtype": "Float",
"width": 110
}
- ]
\ No newline at end of file
+ ]
diff --git a/erpnext/buying/report/subcontracted_item_to_be_received/test_subcontracted_item_to_be_received.py b/erpnext/buying/report/subcontracted_item_to_be_received/test_subcontracted_item_to_be_received.py
index d8de701bf6..cb304a1fda 100644
--- a/erpnext/buying/report/subcontracted_item_to_be_received/test_subcontracted_item_to_be_received.py
+++ b/erpnext/buying/report/subcontracted_item_to_be_received/test_subcontracted_item_to_be_received.py
@@ -33,4 +33,4 @@ def make_purchase_receipt_against_po(po, quantity=5):
pr.items[0].qty = quantity
pr.supplier_warehouse = '_Test Warehouse 1 - _TC'
pr.insert()
- pr.submit()
\ No newline at end of file
+ pr.submit()
diff --git a/erpnext/buying/report/subcontracted_raw_materials_to_be_transferred/subcontracted_raw_materials_to_be_transferred.py b/erpnext/buying/report/subcontracted_raw_materials_to_be_transferred/subcontracted_raw_materials_to_be_transferred.py
index 68426abbb0..96cacb6f1b 100644
--- a/erpnext/buying/report/subcontracted_raw_materials_to_be_transferred/subcontracted_raw_materials_to_be_transferred.py
+++ b/erpnext/buying/report/subcontracted_raw_materials_to_be_transferred/subcontracted_raw_materials_to_be_transferred.py
@@ -94,4 +94,4 @@ def get_po_items_to_supply(filters):
["Purchase Order", "transaction_date", ">=", filters.from_date],
["Purchase Order", "docstatus", "=", 1]
]
- )
\ No newline at end of file
+ )
diff --git a/erpnext/buying/report/supplier_quotation_comparison/supplier_quotation_comparison.html b/erpnext/buying/report/supplier_quotation_comparison/supplier_quotation_comparison.html
index 098214d741..015b31c206 100644
--- a/erpnext/buying/report/supplier_quotation_comparison/supplier_quotation_comparison.html
+++ b/erpnext/buying/report/supplier_quotation_comparison/supplier_quotation_comparison.html
@@ -129,4 +129,4 @@
-Printed On {%= frappe.datetime.str_to_user(frappe.datetime.get_datetime_as_string()) %}
\ No newline at end of file
+Printed On {%= frappe.datetime.str_to_user(frappe.datetime.get_datetime_as_string()) %}
diff --git a/erpnext/buying/report/supplier_quotation_comparison/supplier_quotation_comparison.js b/erpnext/buying/report/supplier_quotation_comparison/supplier_quotation_comparison.js
index 80e521a8bf..7a8d08dd22 100644
--- a/erpnext/buying/report/supplier_quotation_comparison/supplier_quotation_comparison.js
+++ b/erpnext/buying/report/supplier_quotation_comparison/supplier_quotation_comparison.js
@@ -174,4 +174,4 @@ frappe.query_reports["Supplier Quotation Comparison"] = {
});
dialog.show();
}
-}
\ No newline at end of file
+}
diff --git a/erpnext/buying/report/supplier_quotation_comparison/supplier_quotation_comparison.py b/erpnext/buying/report/supplier_quotation_comparison/supplier_quotation_comparison.py
index 2b371915f3..a5a3105a84 100644
--- a/erpnext/buying/report/supplier_quotation_comparison/supplier_quotation_comparison.py
+++ b/erpnext/buying/report/supplier_quotation_comparison/supplier_quotation_comparison.py
@@ -263,4 +263,4 @@ def get_message():
Expires today / Already Expired
- """
\ No newline at end of file
+ """
diff --git a/erpnext/buying/utils.py b/erpnext/buying/utils.py
index a73cb0d62e..17928634e7 100644
--- a/erpnext/buying/utils.py
+++ b/erpnext/buying/utils.py
@@ -102,4 +102,3 @@ def get_linked_material_requests(items):
mr_list.append(material_request)
return mr_list
-
diff --git a/erpnext/commands/__init__.py b/erpnext/commands/__init__.py
index a991cf9881..2276c738fb 100644
--- a/erpnext/commands/__init__.py
+++ b/erpnext/commands/__init__.py
@@ -46,4 +46,4 @@ def make_demo(context, site, domain='Manufacturing', days=100,
commands = [
make_demo
-]
\ No newline at end of file
+]
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index 26eb5bb337..4c243d0cc4 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -842,7 +842,7 @@ class AccountsController(TransactionBase):
dr_or_cr = "credit"
rev_dr_cr = "debit"
supplier_or_customer = self.supplier
-
+
else:
dr_or_cr = "debit"
rev_dr_cr = "credit"
@@ -853,11 +853,11 @@ class AccountsController(TransactionBase):
discount_amount = item.discount_amount * item.qty
if self.doctype == "Purchase Invoice":
income_or_expense_account = (item.expense_account
- if (not item.enable_deferred_expense or self.is_return)
+ if (not item.enable_deferred_expense or self.is_return)
else item.deferred_expense_account)
else:
income_or_expense_account = (item.income_account
- if (not item.enable_deferred_revenue or self.is_return)
+ if (not item.enable_deferred_revenue or self.is_return)
else item.deferred_revenue_account)
account_currency = get_account_currency(item.discount_account)
@@ -866,7 +866,7 @@ class AccountsController(TransactionBase):
"account": item.discount_account,
"against": supplier_or_customer,
dr_or_cr: flt(discount_amount, item.precision('discount_amount')),
- dr_or_cr + "_in_account_currency": flt(discount_amount * self.get('conversion_rate'),
+ dr_or_cr + "_in_account_currency": flt(discount_amount * self.get('conversion_rate'),
item.precision('discount_amount')),
"cost_center": item.cost_center,
"project": item.project
@@ -879,7 +879,7 @@ class AccountsController(TransactionBase):
"account": income_or_expense_account,
"against": supplier_or_customer,
rev_dr_cr: flt(discount_amount, item.precision('discount_amount')),
- rev_dr_cr + "_in_account_currency": flt(discount_amount * self.get('conversion_rate'),
+ rev_dr_cr + "_in_account_currency": flt(discount_amount * self.get('conversion_rate'),
item.precision('discount_amount')),
"cost_center": item.cost_center,
"project": item.project or self.project
@@ -894,8 +894,8 @@ class AccountsController(TransactionBase):
dr_or_cr: self.discount_amount,
"cost_center": self.cost_center
}, item=self)
- )
-
+ )
+
def allocate_advance_taxes(self, gl_entries):
tax_map = self.get_tax_map()
for pe in self.get("advances"):
@@ -1223,7 +1223,7 @@ class AccountsController(TransactionBase):
po_or_so = self.get('items')[0].get('purchase_order')
po_or_so_doctype = "Purchase Order"
po_or_so_doctype_name = "purchase_order"
-
+
return po_or_so, po_or_so_doctype, po_or_so_doctype_name
def linked_order_has_payment_terms(self, po_or_so, fieldname, doctype):
@@ -1232,14 +1232,14 @@ class AccountsController(TransactionBase):
return True
elif self.linked_order_has_payment_schedule(po_or_so):
return True
-
+
return False
def all_items_have_same_po_or_so(self, po_or_so, fieldname):
for item in self.get('items'):
if item.get(fieldname) != po_or_so:
return False
-
+
return True
def linked_order_has_payment_terms_template(self, po_or_so, doctype):
@@ -1978,4 +1978,4 @@ def validate_regional(doc):
@erpnext.allow_regional
def validate_einvoice_fields(doc):
- pass
\ No newline at end of file
+ pass
diff --git a/erpnext/controllers/item_variant.py b/erpnext/controllers/item_variant.py
index 051481ff60..8c361a2e56 100644
--- a/erpnext/controllers/item_variant.py
+++ b/erpnext/controllers/item_variant.py
@@ -344,4 +344,3 @@ def create_variant_doc_for_quick_entry(template, args):
variant.name = variant.item_code
validate_item_variant_attributes(variant, args)
return variant.as_dict()
-
diff --git a/erpnext/controllers/subcontracting.py b/erpnext/controllers/subcontracting.py
index 36ae110216..969829f965 100644
--- a/erpnext/controllers/subcontracting.py
+++ b/erpnext/controllers/subcontracting.py
@@ -390,4 +390,4 @@ class Subcontracting():
incorrect_sn = "\n".join(incorrect_sn)
link = get_link_to_form('Purchase Order', row.purchase_order)
msg = f'The Serial Nos {incorrect_sn} has not supplied against the Purchase Order {link}'
- frappe.throw(_(msg), title=_("Incorrect Serial Number Consumed"))
\ No newline at end of file
+ frappe.throw(_(msg), title=_("Incorrect Serial Number Consumed"))
diff --git a/erpnext/crm/doctype/appointment/appointment.py b/erpnext/crm/doctype/appointment/appointment.py
index df73f09c49..f7c6b6c799 100644
--- a/erpnext/crm/doctype/appointment/appointment.py
+++ b/erpnext/crm/doctype/appointment/appointment.py
@@ -235,4 +235,3 @@ def _get_employee_from_user(user):
# frappe.db.exists returns a tuple of a tuple
return frappe.get_doc('Employee', employee_docname[0][0])
return None
-
diff --git a/erpnext/crm/doctype/appointment_booking_settings/appointment_booking_settings.js b/erpnext/crm/doctype/appointment_booking_settings/appointment_booking_settings.js
index dc3ae8bf41..0c64eb8e82 100644
--- a/erpnext/crm/doctype/appointment_booking_settings/appointment_booking_settings.js
+++ b/erpnext/crm/doctype/appointment_booking_settings/appointment_booking_settings.js
@@ -7,4 +7,4 @@ function check_times(frm) {
frappe.throw(__('In row {0} of Appointment Booking Slots: "To Time" must be later than "From Time".', [i + 1]));
}
});
-}
\ No newline at end of file
+}
diff --git a/erpnext/crm/doctype/contract/contract.js b/erpnext/crm/doctype/contract/contract.js
index 9968855163..7848de7a72 100644
--- a/erpnext/crm/doctype/contract/contract.js
+++ b/erpnext/crm/doctype/contract/contract.js
@@ -15,7 +15,7 @@ frappe.ui.form.on("Contract", {
let contract_template = r.message.contract_template;
frm.set_value("contract_terms", r.message.contract_terms);
frm.set_value("requires_fulfilment", contract_template.requires_fulfilment);
-
+
if (frm.doc.requires_fulfilment) {
// Populate the fulfilment terms table from a contract template, if any
r.message.contract_template.fulfilment_terms.forEach(element => {
@@ -23,7 +23,7 @@ frappe.ui.form.on("Contract", {
d.requirement = element.requirement;
});
frm.refresh_field("fulfilment_terms");
- }
+ }
}
}
});
diff --git a/erpnext/crm/doctype/contract/contract_list.js b/erpnext/crm/doctype/contract/contract_list.js
index 26a2907c7c..7d5609651a 100644
--- a/erpnext/crm/doctype/contract/contract_list.js
+++ b/erpnext/crm/doctype/contract/contract_list.js
@@ -9,4 +9,4 @@ frappe.listview_settings['Contract'] = {
return [__(doc.status), "gray", "status,=," + doc.status];
}
},
-};
\ No newline at end of file
+};
diff --git a/erpnext/crm/doctype/contract_template/contract_template.py b/erpnext/crm/doctype/contract_template/contract_template.py
index 69fd86f7fb..9281220eef 100644
--- a/erpnext/crm/doctype/contract_template/contract_template.py
+++ b/erpnext/crm/doctype/contract_template/contract_template.py
@@ -24,8 +24,8 @@ def get_contract_template(template_name, doc):
if contract_template.contract_terms:
contract_terms = frappe.render_template(contract_template.contract_terms, doc)
-
+
return {
- 'contract_template': contract_template,
+ 'contract_template': contract_template,
'contract_terms': contract_terms
- }
\ No newline at end of file
+ }
diff --git a/erpnext/crm/doctype/lead/lead.py b/erpnext/crm/doctype/lead/lead.py
index 7f028cb316..c0ce6badbf 100644
--- a/erpnext/crm/doctype/lead/lead.py
+++ b/erpnext/crm/doctype/lead/lead.py
@@ -34,7 +34,7 @@ class Lead(SellingController):
"ends_on": frappe.db.get_value("Lead", self.name, "ends_on") if (not cint(self.is_new())) else None,
"contact_by": frappe.db.get_value("Lead", self.name, "contact_by") if (not cint(self.is_new())) else None,
})
-
+
def set_full_name(self):
self.lead_name = " ".join(filter(None, [self.first_name, self.middle_name, self.last_name]))
diff --git a/erpnext/crm/doctype/lead/lead_dashboard.py b/erpnext/crm/doctype/lead/lead_dashboard.py
index 69d8ca7092..3950d063f2 100644
--- a/erpnext/crm/doctype/lead/lead_dashboard.py
+++ b/erpnext/crm/doctype/lead/lead_dashboard.py
@@ -16,4 +16,4 @@ def get_data():
'items': ['Opportunity', 'Quotation']
},
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/crm/doctype/lead/test_lead.py b/erpnext/crm/doctype/lead/test_lead.py
index d4886d3506..d7bc46165f 100644
--- a/erpnext/crm/doctype/lead/test_lead.py
+++ b/erpnext/crm/doctype/lead/test_lead.py
@@ -82,4 +82,4 @@ def make_lead(**args):
"email_id": args.email_id or "new_lead_{}@example.com".format(random_string(5)),
}).insert()
- return lead_doc
\ No newline at end of file
+ return lead_doc
diff --git a/erpnext/crm/doctype/opportunity/opportunity.js b/erpnext/crm/doctype/opportunity/opportunity.js
index e9a7a95fc7..632012b31d 100644
--- a/erpnext/crm/doctype/opportunity/opportunity.js
+++ b/erpnext/crm/doctype/opportunity/opportunity.js
@@ -57,7 +57,7 @@ frappe.ui.form.on("Opportunity", {
if (frm.doc.status == "Lost"){
frm.trigger('set_as_lost_dialog');
}
-
+
},
customer_address: function(frm, cdt, cdn) {
diff --git a/erpnext/crm/doctype/opportunity/opportunity.py b/erpnext/crm/doctype/opportunity/opportunity.py
index 23ad98a282..8ce482a3f9 100644
--- a/erpnext/crm/doctype/opportunity/opportunity.py
+++ b/erpnext/crm/doctype/opportunity/opportunity.py
@@ -372,4 +372,4 @@ def get_events(start, end, filters=None):
"start": start,
"end": end
}, as_dict=True, update={"allDay": 0})
- return data
\ No newline at end of file
+ return data
diff --git a/erpnext/crm/doctype/opportunity/opportunity_dashboard.py b/erpnext/crm/doctype/opportunity/opportunity_dashboard.py
index 68f0104fd6..b8c53f077a 100644
--- a/erpnext/crm/doctype/opportunity/opportunity_dashboard.py
+++ b/erpnext/crm/doctype/opportunity/opportunity_dashboard.py
@@ -9,4 +9,4 @@ def get_data():
'items': ['Quotation', 'Supplier Quotation']
},
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/crm/doctype/opportunity/test_opportunity.py b/erpnext/crm/doctype/opportunity/test_opportunity.py
index 04cd8a26ca..52aa0b036a 100644
--- a/erpnext/crm/doctype/opportunity/test_opportunity.py
+++ b/erpnext/crm/doctype/opportunity/test_opportunity.py
@@ -87,4 +87,4 @@ def make_opportunity(**args):
})
opp_doc.insert()
- return opp_doc
\ No newline at end of file
+ return opp_doc
diff --git a/erpnext/crm/doctype/social_media_post/social_media_post.js b/erpnext/crm/doctype/social_media_post/social_media_post.js
index 0ce8b44e19..6fb0f975f4 100644
--- a/erpnext/crm/doctype/social_media_post/social_media_post.js
+++ b/erpnext/crm/doctype/social_media_post/social_media_post.js
@@ -19,7 +19,7 @@ frappe.ui.form.on('Social Media Post', {
refresh: function(frm){
if (frm.doc.docstatus === 1){
if (frm.doc.post_status != "Posted"){
- add_post_btn(frm);
+ add_post_btn(frm);
}
else if (frm.doc.post_status == "Posted"){
frm.set_df_property('sheduled_time', 'read_only', 1);
@@ -63,5 +63,5 @@ var post = function(frm){
frappe.dom.unfreeze();
}
})
-
-}
\ No newline at end of file
+
+}
diff --git a/erpnext/crm/report/campaign_efficiency/campaign_efficiency.js b/erpnext/crm/report/campaign_efficiency/campaign_efficiency.js
index 0bc77a3f2a..f29c2c64e1 100644
--- a/erpnext/crm/report/campaign_efficiency/campaign_efficiency.js
+++ b/erpnext/crm/report/campaign_efficiency/campaign_efficiency.js
@@ -16,4 +16,3 @@ frappe.query_reports["Campaign Efficiency"] = {
}
]
};
-
diff --git a/erpnext/crm/report/campaign_efficiency/campaign_efficiency.py b/erpnext/crm/report/campaign_efficiency/campaign_efficiency.py
index ec498837f5..238884b519 100644
--- a/erpnext/crm/report/campaign_efficiency/campaign_efficiency.py
+++ b/erpnext/crm/report/campaign_efficiency/campaign_efficiency.py
@@ -132,4 +132,4 @@ def get_order_amount(leads):
where prevdoc_docname in (
select name from `tabQuotation` where status = 'Ordered'
and quotation_to = 'Lead' and party_name in (%s)
- )""" % ', '.join(["%s"]*len(leads)), tuple(leads))[0][0]
\ No newline at end of file
+ )""" % ', '.join(["%s"]*len(leads)), tuple(leads))[0][0]
diff --git a/erpnext/crm/report/lead_conversion_time/lead_conversion_time.js b/erpnext/crm/report/lead_conversion_time/lead_conversion_time.js
index 0325de9b8d..eeb8984513 100644
--- a/erpnext/crm/report/lead_conversion_time/lead_conversion_time.js
+++ b/erpnext/crm/report/lead_conversion_time/lead_conversion_time.js
@@ -20,5 +20,3 @@ frappe.query_reports["Lead Conversion Time"] = {
},
]
};
-
-
diff --git a/erpnext/crm/report/lead_details/lead_details.js b/erpnext/crm/report/lead_details/lead_details.js
index f92070daf3..2f6d24224f 100644
--- a/erpnext/crm/report/lead_details/lead_details.js
+++ b/erpnext/crm/report/lead_details/lead_details.js
@@ -49,4 +49,4 @@ frappe.query_reports["Lead Details"] = {
"options": "Territory",
}
]
-};
\ No newline at end of file
+};
diff --git a/erpnext/crm/report/lead_details/lead_details.py b/erpnext/crm/report/lead_details/lead_details.py
index eeaaec2bce..072a47611b 100644
--- a/erpnext/crm/report/lead_details/lead_details.py
+++ b/erpnext/crm/report/lead_details/lead_details.py
@@ -107,7 +107,7 @@ def get_columns():
"options": "Country",
"width": 100
},
-
+
]
return columns
@@ -142,7 +142,7 @@ def get_data(filters):
company = %(company)s
AND `tabLead`.creation BETWEEN %(from_date)s AND %(to_date)s
{conditions}
- ORDER BY
+ ORDER BY
`tabLead`.creation asc """.format(conditions=get_conditions(filters)), filters, as_dict=1)
def get_conditions(filters) :
@@ -153,6 +153,5 @@ def get_conditions(filters) :
if filters.get("status"):
conditions.append(" and `tabLead`.status=%(status)s")
-
- return " ".join(conditions) if conditions else ""
+ return " ".join(conditions) if conditions else ""
diff --git a/erpnext/crm/report/lost_opportunity/lost_opportunity.js b/erpnext/crm/report/lost_opportunity/lost_opportunity.js
index d79f8c8480..97c56f8c43 100644
--- a/erpnext/crm/report/lost_opportunity/lost_opportunity.js
+++ b/erpnext/crm/report/lost_opportunity/lost_opportunity.js
@@ -64,4 +64,4 @@ frappe.query_reports["Lost Opportunity"] = {
"options": "User"
},
]
-};
\ No newline at end of file
+};
diff --git a/erpnext/crm/report/lost_opportunity/lost_opportunity.py b/erpnext/crm/report/lost_opportunity/lost_opportunity.py
index 1aa4afe186..858dcc4da8 100644
--- a/erpnext/crm/report/lost_opportunity/lost_opportunity.py
+++ b/erpnext/crm/report/lost_opportunity/lost_opportunity.py
@@ -87,17 +87,17 @@ def get_data(filters):
`tabOpportunity`.sales_stage,
`tabOpportunity`.territory
FROM
- `tabOpportunity`
+ `tabOpportunity`
{join}
WHERE
`tabOpportunity`.status = 'Lost' and `tabOpportunity`.company = %(company)s
- AND `tabOpportunity`.modified BETWEEN %(from_date)s AND %(to_date)s
- {conditions}
- GROUP BY
- `tabOpportunity`.name
- ORDER BY
+ AND `tabOpportunity`.modified BETWEEN %(from_date)s AND %(to_date)s
+ {conditions}
+ GROUP BY
+ `tabOpportunity`.name
+ ORDER BY
`tabOpportunity`.creation asc """.format(conditions=get_conditions(filters), join=get_join(filters)), filters, as_dict=1)
-
+
def get_conditions(filters):
conditions = []
@@ -117,15 +117,15 @@ def get_conditions(filters):
return " ".join(conditions) if conditions else ""
def get_join(filters):
- join = """LEFT JOIN `tabOpportunity Lost Reason Detail`
- ON `tabOpportunity Lost Reason Detail`.parenttype = 'Opportunity' and
+ join = """LEFT JOIN `tabOpportunity Lost Reason Detail`
+ ON `tabOpportunity Lost Reason Detail`.parenttype = 'Opportunity' and
`tabOpportunity Lost Reason Detail`.parent = `tabOpportunity`.name"""
if filters.get("lost_reason"):
- join = """JOIN `tabOpportunity Lost Reason Detail`
- ON `tabOpportunity Lost Reason Detail`.parenttype = 'Opportunity' and
+ join = """JOIN `tabOpportunity Lost Reason Detail`
+ ON `tabOpportunity Lost Reason Detail`.parenttype = 'Opportunity' and
`tabOpportunity Lost Reason Detail`.parent = `tabOpportunity`.name and
`tabOpportunity Lost Reason Detail`.lost_reason = '{0}'
""".format(filters.get("lost_reason"))
-
- return join
\ No newline at end of file
+
+ return join
diff --git a/erpnext/crm/report/prospects_engaged_but_not_converted/prospects_engaged_but_not_converted.py b/erpnext/crm/report/prospects_engaged_but_not_converted/prospects_engaged_but_not_converted.py
index 3a9d57d607..425b7a8fdd 100644
--- a/erpnext/crm/report/prospects_engaged_but_not_converted/prospects_engaged_but_not_converted.py
+++ b/erpnext/crm/report/prospects_engaged_but_not_converted/prospects_engaged_but_not_converted.py
@@ -106,4 +106,4 @@ def get_lead_filters(filters):
return lead_filters
def get_creation_date_based_on_lead_age(filters):
- return add_days(now(), (filters.get('lead_age') * -1))
\ No newline at end of file
+ return add_days(now(), (filters.get('lead_age') * -1))
diff --git a/erpnext/demo/domains.py b/erpnext/demo/domains.py
index d5c2bfd2f0..b1db7b57b1 100644
--- a/erpnext/demo/domains.py
+++ b/erpnext/demo/domains.py
@@ -25,4 +25,4 @@ data = {
'Non Profit': {
'company_name': 'Erpnext Foundation'
}
-}
\ No newline at end of file
+}
diff --git a/erpnext/demo/user/education.py b/erpnext/demo/user/education.py
index fc31176e1e..883a6d88cf 100644
--- a/erpnext/demo/user/education.py
+++ b/erpnext/demo/user/education.py
@@ -19,7 +19,7 @@ def work():
approve_random_student_applicant()
enroll_random_student(frappe.flags.current_date)
# if frappe.flags.current_date.weekday()== 0:
- # make_course_schedule(frappe.flags.current_date, frappe.utils.add_days(frappe.flags.current_date, 5))
+ # make_course_schedule(frappe.flags.current_date, frappe.utils.add_days(frappe.flags.current_date, 5))
mark_student_attendance(frappe.flags.current_date)
# make_assessment_plan()
make_fees()
@@ -48,7 +48,7 @@ def enroll_random_student(current_date):
frappe.db.commit()
assign_student_group(enrollment.student, enrollment.student_name, enrollment.program,
enrolled_courses, enrollment.student_batch_name)
-
+
def assign_student_group(student, student_name, program, courses, batch):
course_list = [d["course"] for d in courses]
for d in frappe.get_list("Student Group", fields=("name"), filters={"program": program, "course":("in", course_list), "disabled": 0}):
@@ -69,11 +69,11 @@ def mark_student_attendance(current_date):
students = get_student_group_students(d.name)
for stud in students:
make_attendance_records(stud.student, stud.student_name, status[weighted_choice([9,4])], None, d.name, current_date)
-
+
def make_fees():
for d in range(1,10):
random_fee = get_random("Fees", {"paid_amount": 0})
- collect_fees(random_fee, frappe.db.get_value("Fees", random_fee, "outstanding_amount"))
+ collect_fees(random_fee, frappe.db.get_value("Fees", random_fee, "outstanding_amount"))
def make_assessment_plan(date):
for d in range(1,4):
@@ -84,7 +84,7 @@ def make_assessment_plan(date):
doc.assessment_group = get_random("Assessment Group", {"is_group": 0, "parent": "2017-18 (Semester 2)"})
doc.grading_scale = get_random("Grading Scale")
doc.maximum_assessment_score = 100
-
+
def make_course_schedule(start_date, end_date):
for d in frappe.db.get_list("Student Group"):
cs = frappe.new_doc("Scheduling Tool")
@@ -114,4 +114,4 @@ def weighted_choice(weights):
rnd = random.random() * running_total
for i, total in enumerate(totals):
if rnd < total:
- return i
\ No newline at end of file
+ return i
diff --git a/erpnext/domains/agriculture.py b/erpnext/domains/agriculture.py
index 8c7427ab2d..9212d2ea71 100644
--- a/erpnext/domains/agriculture.py
+++ b/erpnext/domains/agriculture.py
@@ -25,4 +25,4 @@ data = {
],
'default_portal_role': 'System Manager',
'on_setup': 'erpnext.agriculture.setup.setup_agriculture'
-}
\ No newline at end of file
+}
diff --git a/erpnext/domains/education.py b/erpnext/domains/education.py
index bbaa6e55d9..870624ab3b 100644
--- a/erpnext/domains/education.py
+++ b/erpnext/domains/education.py
@@ -26,4 +26,4 @@ data = {
],
'on_setup': 'erpnext.education.setup.setup_education'
-}
\ No newline at end of file
+}
diff --git a/erpnext/domains/manufacturing.py b/erpnext/domains/manufacturing.py
index 259ee9238e..b9ad49e772 100644
--- a/erpnext/domains/manufacturing.py
+++ b/erpnext/domains/manufacturing.py
@@ -21,4 +21,4 @@ data = {
['Stock Settings', None, 'show_barcode_field', 1]
],
'default_portal_role': 'Customer'
-}
\ No newline at end of file
+}
diff --git a/erpnext/domains/non_profit.py b/erpnext/domains/non_profit.py
index b6772c5315..7c4f6b1f9d 100644
--- a/erpnext/domains/non_profit.py
+++ b/erpnext/domains/non_profit.py
@@ -21,4 +21,4 @@ data = {
'Non Profit'
],
'default_portal_role': 'Non Profit Manager'
-}
\ No newline at end of file
+}
diff --git a/erpnext/domains/services.py b/erpnext/domains/services.py
index 7a4ffc4993..8921372076 100644
--- a/erpnext/domains/services.py
+++ b/erpnext/domains/services.py
@@ -18,4 +18,4 @@ data = {
['Stock Settings', None, 'show_barcode_field', 0]
],
'default_portal_role': 'Customer'
-}
\ No newline at end of file
+}
diff --git a/erpnext/education/doctype/academic_term/academic_term.py b/erpnext/education/doctype/academic_term/academic_term.py
index 3aa0be157b..fa7f2899dc 100644
--- a/erpnext/education/doctype/academic_term/academic_term.py
+++ b/erpnext/education/doctype/academic_term/academic_term.py
@@ -22,9 +22,9 @@ class AcademicTerm(Document):
and getdate(self.term_start_date) > getdate(self.term_end_date):
frappe.throw(_("The Term End Date cannot be earlier than the Term Start Date. Please correct the dates and try again."))
- # Check that the start of the term is not before the start of the academic year
+ # Check that the start of the term is not before the start of the academic year
# and end of term is not after the end of the academic year"""
-
+
year = frappe.get_doc("Academic Year",self.academic_year)
if self.term_start_date and getdate(year.year_start_date) and (getdate(self.term_start_date) < getdate(year.year_start_date)):
frappe.throw(_("The Term Start Date cannot be earlier than the Year Start Date of the Academic Year to which the term is linked (Academic Year {}). Please correct the dates and try again.").format(self.academic_year))
diff --git a/erpnext/education/doctype/academic_term/academic_term_dashboard.py b/erpnext/education/doctype/academic_term/academic_term_dashboard.py
index 871e0f3284..eb2f90742c 100644
--- a/erpnext/education/doctype/academic_term/academic_term_dashboard.py
+++ b/erpnext/education/doctype/academic_term/academic_term_dashboard.py
@@ -22,4 +22,4 @@ def get_data():
'items': ['Assessment Plan', 'Assessment Result']
}
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/education/doctype/academic_term/test_academic_term.js b/erpnext/education/doctype/academic_term/test_academic_term.js
index 6d91e977c6..383b65a703 100644
--- a/erpnext/education/doctype/academic_term/test_academic_term.js
+++ b/erpnext/education/doctype/academic_term/test_academic_term.js
@@ -21,4 +21,4 @@ QUnit.test('Test: Academic Term', function(assert){
},
() => done()
]);
-});
\ No newline at end of file
+});
diff --git a/erpnext/education/doctype/academic_year/academic_year.js b/erpnext/education/doctype/academic_year/academic_year.js
index 0e8619849c..20e25281ff 100644
--- a/erpnext/education/doctype/academic_year/academic_year.js
+++ b/erpnext/education/doctype/academic_year/academic_year.js
@@ -1,2 +1,2 @@
frappe.ui.form.on("Academic Year", {
-});
\ No newline at end of file
+});
diff --git a/erpnext/education/doctype/academic_year/academic_year_dashboard.py b/erpnext/education/doctype/academic_year/academic_year_dashboard.py
index f27f7d14cf..d3734df803 100644
--- a/erpnext/education/doctype/academic_year/academic_year_dashboard.py
+++ b/erpnext/education/doctype/academic_year/academic_year_dashboard.py
@@ -22,4 +22,4 @@ def get_data():
'items': ['Assessment Plan', 'Assessment Result']
}
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/education/doctype/academic_year/test_academic_year.js b/erpnext/education/doctype/academic_year/test_academic_year.js
index ec2f49c5a1..51e9cf307d 100644
--- a/erpnext/education/doctype/academic_year/test_academic_year.js
+++ b/erpnext/education/doctype/academic_year/test_academic_year.js
@@ -20,4 +20,4 @@ QUnit.test('Test: Academic Year', function(assert){
},
() => done()
]);
-});
\ No newline at end of file
+});
diff --git a/erpnext/education/doctype/article/article.js b/erpnext/education/doctype/article/article.js
index edfec26273..85b387f621 100644
--- a/erpnext/education/doctype/article/article.js
+++ b/erpnext/education/doctype/article/article.js
@@ -53,4 +53,4 @@ let get_topics_without_article = function(article) {
method: 'erpnext.education.doctype.article.article.get_topics_without_article',
args: {'article': article}
});
-};
\ No newline at end of file
+};
diff --git a/erpnext/education/doctype/article/article.py b/erpnext/education/doctype/article/article.py
index 8ba367da76..b5cc5cbc7a 100644
--- a/erpnext/education/doctype/article/article.py
+++ b/erpnext/education/doctype/article/article.py
@@ -18,4 +18,4 @@ def get_topics_without_article(article):
topic_contents = [tc.content for tc in topic.topic_content]
if not topic_contents or article not in topic_contents:
data.append(topic.name)
- return data
\ No newline at end of file
+ return data
diff --git a/erpnext/education/doctype/assessment_criteria/assessment_criteria.py b/erpnext/education/doctype/assessment_criteria/assessment_criteria.py
index 1ea37023b2..bfbf26cf6c 100644
--- a/erpnext/education/doctype/assessment_criteria/assessment_criteria.py
+++ b/erpnext/education/doctype/assessment_criteria/assessment_criteria.py
@@ -12,4 +12,4 @@ STD_CRITERIA = ["total", "total score", "total grade", "maximum score", "score",
class AssessmentCriteria(Document):
def validate(self):
if self.assessment_criteria.lower() in STD_CRITERIA:
- frappe.throw(_("Can't create standard criteria. Please rename the criteria"))
\ No newline at end of file
+ frappe.throw(_("Can't create standard criteria. Please rename the criteria"))
diff --git a/erpnext/education/doctype/assessment_criteria/test_assessment_criteria.js b/erpnext/education/doctype/assessment_criteria/test_assessment_criteria.js
index db4a4cf5a8..724c4dac49 100644
--- a/erpnext/education/doctype/assessment_criteria/test_assessment_criteria.js
+++ b/erpnext/education/doctype/assessment_criteria/test_assessment_criteria.js
@@ -13,4 +13,4 @@ QUnit.test('Test: Assessment Criteria', function(assert){
},
() => done()
]);
-});
\ No newline at end of file
+});
diff --git a/erpnext/education/doctype/assessment_criteria_group/test_assessment_criteria_group.js b/erpnext/education/doctype/assessment_criteria_group/test_assessment_criteria_group.js
index bcfcaf82e6..ab27e63723 100644
--- a/erpnext/education/doctype/assessment_criteria_group/test_assessment_criteria_group.js
+++ b/erpnext/education/doctype/assessment_criteria_group/test_assessment_criteria_group.js
@@ -12,4 +12,4 @@ QUnit.test('Test: Assessment Criteria Group', function(assert){
},
() => done()
]);
-});
\ No newline at end of file
+});
diff --git a/erpnext/education/doctype/assessment_group/assessment_group_dashboard.py b/erpnext/education/doctype/assessment_group/assessment_group_dashboard.py
index 2649d4b90c..1a23606a61 100644
--- a/erpnext/education/doctype/assessment_group/assessment_group_dashboard.py
+++ b/erpnext/education/doctype/assessment_group/assessment_group_dashboard.py
@@ -12,4 +12,4 @@ def get_data():
'items': ['Assessment Plan', 'Assessment Result']
}
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/education/doctype/assessment_group/assessment_group_tree.js b/erpnext/education/doctype/assessment_group/assessment_group_tree.js
index e4676831a3..e0dfaa31fd 100644
--- a/erpnext/education/doctype/assessment_group/assessment_group_tree.js
+++ b/erpnext/education/doctype/assessment_group/assessment_group_tree.js
@@ -1,3 +1,3 @@
frappe.treeview_settings["Assessment Group"] = {
-
-}
\ No newline at end of file
+
+}
diff --git a/erpnext/education/doctype/assessment_group/test_assessment_group.js b/erpnext/education/doctype/assessment_group/test_assessment_group.js
index a127fd4adf..00e6309837 100644
--- a/erpnext/education/doctype/assessment_group/test_assessment_group.js
+++ b/erpnext/education/doctype/assessment_group/test_assessment_group.js
@@ -62,4 +62,4 @@ frappe.map_group = {
() => frappe.click_button('Create New'),
]);
}
-};
\ No newline at end of file
+};
diff --git a/erpnext/education/doctype/assessment_plan/assessment_plan.js b/erpnext/education/doctype/assessment_plan/assessment_plan.js
index 726c0fcecd..cf545c41af 100644
--- a/erpnext/education/doctype/assessment_plan/assessment_plan.js
+++ b/erpnext/education/doctype/assessment_plan/assessment_plan.js
@@ -75,4 +75,4 @@ frappe.ui.form.on('Assessment Plan', {
maximum_assessment_score: function(frm) {
frm.trigger('course');
}
-});
\ No newline at end of file
+});
diff --git a/erpnext/education/doctype/assessment_plan/assessment_plan_dashboard.py b/erpnext/education/doctype/assessment_plan/assessment_plan_dashboard.py
index 5e6c29dcdf..8ac3faf6dd 100644
--- a/erpnext/education/doctype/assessment_plan/assessment_plan_dashboard.py
+++ b/erpnext/education/doctype/assessment_plan/assessment_plan_dashboard.py
@@ -18,4 +18,4 @@ def get_data():
'items': ['Assessment Plan Status']
}
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/education/doctype/assessment_result/assessment_result.js b/erpnext/education/doctype/assessment_result/assessment_result.js
index c35f607a99..b6d28817b5 100644
--- a/erpnext/education/doctype/assessment_result/assessment_result.js
+++ b/erpnext/education/doctype/assessment_result/assessment_result.js
@@ -122,4 +122,4 @@ frappe.ui.form.on('Assessment Result Detail', {
});
}
}
-});
\ No newline at end of file
+});
diff --git a/erpnext/education/doctype/assessment_result/assessment_result.py b/erpnext/education/doctype/assessment_result/assessment_result.py
index 6b873ecf97..7dfe0cf6c2 100644
--- a/erpnext/education/doctype/assessment_result/assessment_result.py
+++ b/erpnext/education/doctype/assessment_result/assessment_result.py
@@ -42,7 +42,3 @@ class AssessmentResult(Document):
"student":self.student, "assessment_plan":self.assessment_plan, "docstatus":("!=", 2)})
if assessment_result:
frappe.throw(_("Assessment Result record {0} already exists.").format(getlink("Assessment Result",assessment_result[0].name)))
-
-
-
-
diff --git a/erpnext/education/doctype/assessment_result/assessment_result_dashboard.py b/erpnext/education/doctype/assessment_result/assessment_result_dashboard.py
index 438379d08e..2526076d30 100644
--- a/erpnext/education/doctype/assessment_result/assessment_result_dashboard.py
+++ b/erpnext/education/doctype/assessment_result/assessment_result_dashboard.py
@@ -11,4 +11,4 @@ def get_data():
'items': ['Final Assessment Grades', 'Course wise Assessment Report']
}
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/education/doctype/assessment_result/test_assessment_result.js b/erpnext/education/doctype/assessment_result/test_assessment_result.js
index b7adfacb1a..d4eb4b8ba6 100644
--- a/erpnext/education/doctype/assessment_result/test_assessment_result.js
+++ b/erpnext/education/doctype/assessment_result/test_assessment_result.js
@@ -70,4 +70,4 @@ QUnit.test('Test: Assessment Result', function(assert){
() => done()
]);
-});
\ No newline at end of file
+});
diff --git a/erpnext/education/doctype/assessment_result/test_assessment_result.py b/erpnext/education/doctype/assessment_result/test_assessment_result.py
index e5535d6085..adce57769d 100644
--- a/erpnext/education/doctype/assessment_result/test_assessment_result.py
+++ b/erpnext/education/doctype/assessment_result/test_assessment_result.py
@@ -16,4 +16,3 @@ class TestAssessmentResult(unittest.TestCase):
grade = get_grade("_Test Grading Scale", 70)
self.assertEqual("B", grade)
-
\ No newline at end of file
diff --git a/erpnext/education/doctype/assessment_result_tool/assessment_result_tool.py b/erpnext/education/doctype/assessment_result_tool/assessment_result_tool.py
index 649f420d41..a0d286ccbe 100644
--- a/erpnext/education/doctype/assessment_result_tool/assessment_result_tool.py
+++ b/erpnext/education/doctype/assessment_result_tool/assessment_result_tool.py
@@ -7,4 +7,4 @@ import frappe
from frappe.model.document import Document
class AssessmentResultTool(Document):
- pass
\ No newline at end of file
+ pass
diff --git a/erpnext/education/doctype/assessment_result_tool/test_assessment_result_tool.js b/erpnext/education/doctype/assessment_result_tool/test_assessment_result_tool.js
index 0bbe33194a..7ef5c688fb 100644
--- a/erpnext/education/doctype/assessment_result_tool/test_assessment_result_tool.js
+++ b/erpnext/education/doctype/assessment_result_tool/test_assessment_result_tool.js
@@ -26,4 +26,4 @@ QUnit.test('Test: Assessment Result Tool', function(assert){
},
() => done()
]);
-});
\ No newline at end of file
+});
diff --git a/erpnext/education/doctype/course/course.js b/erpnext/education/doctype/course/course.js
index 81e4a8c08d..bd8d62c8d2 100644
--- a/erpnext/education/doctype/course/course.js
+++ b/erpnext/education/doctype/course/course.js
@@ -76,4 +76,4 @@ let get_programs_without_course = function(course) {
method: 'erpnext.education.doctype.course.course.get_programs_without_course',
args: {'course': course}
});
-}
\ No newline at end of file
+}
diff --git a/erpnext/education/doctype/course/course.py b/erpnext/education/doctype/course/course.py
index 06efa54e77..92f92ed9f3 100644
--- a/erpnext/education/doctype/course/course.py
+++ b/erpnext/education/doctype/course/course.py
@@ -53,4 +53,4 @@ def get_programs_without_course(course):
courses = [c.course for c in program.courses]
if not courses or course not in courses:
data.append(program.name)
- return data
\ No newline at end of file
+ return data
diff --git a/erpnext/education/doctype/course/course_dashboard.py b/erpnext/education/doctype/course/course_dashboard.py
index 8a570bdc57..8de91b1c09 100644
--- a/erpnext/education/doctype/course/course_dashboard.py
+++ b/erpnext/education/doctype/course/course_dashboard.py
@@ -20,4 +20,4 @@ def get_data():
'items': ['Assessment Plan', 'Assessment Result']
},
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/education/doctype/course/test_course.js b/erpnext/education/doctype/course/test_course.js
index 88fddc2bb6..2b6860cb7f 100644
--- a/erpnext/education/doctype/course/test_course.js
+++ b/erpnext/education/doctype/course/test_course.js
@@ -33,4 +33,4 @@ QUnit.test('test course', function(assert) {
},
() => done()
]);
-});
\ No newline at end of file
+});
diff --git a/erpnext/education/doctype/course_activity/course_activity.py b/erpnext/education/doctype/course_activity/course_activity.py
index e7fc08a1d7..3aa1ea0c5b 100644
--- a/erpnext/education/doctype/course_activity/course_activity.py
+++ b/erpnext/education/doctype/course_activity/course_activity.py
@@ -16,4 +16,4 @@ class CourseActivity(Document):
if frappe.db.exists("Course Enrollment", self.enrollment):
return True
else:
- frappe.throw(_("Course Enrollment {0} does not exists").format(self.enrollment))
\ No newline at end of file
+ frappe.throw(_("Course Enrollment {0} does not exists").format(self.enrollment))
diff --git a/erpnext/education/doctype/course_enrollment/course_enrollment_dashboard.py b/erpnext/education/doctype/course_enrollment/course_enrollment_dashboard.py
index b9dd457b61..37972fe354 100644
--- a/erpnext/education/doctype/course_enrollment/course_enrollment_dashboard.py
+++ b/erpnext/education/doctype/course_enrollment/course_enrollment_dashboard.py
@@ -12,4 +12,4 @@ def get_data():
'items': ['Course Activity', 'Quiz Activity']
}
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/education/doctype/course_enrollment/test_course_enrollment.py b/erpnext/education/doctype/course_enrollment/test_course_enrollment.py
index e22c7ce0ba..874bf121f4 100644
--- a/erpnext/education/doctype/course_enrollment/test_course_enrollment.py
+++ b/erpnext/education/doctype/course_enrollment/test_course_enrollment.py
@@ -39,6 +39,3 @@ class TestCourseEnrollment(unittest.TestCase):
doc = frappe.get_doc("Program Enrollment", entry.name)
doc.cancel()
doc.delete()
-
-
-
diff --git a/erpnext/education/doctype/course_schedule/course_schedule.js b/erpnext/education/doctype/course_schedule/course_schedule.js
index 4275f6ef2a..366bbd8b0d 100644
--- a/erpnext/education/doctype/course_schedule/course_schedule.js
+++ b/erpnext/education/doctype/course_schedule/course_schedule.js
@@ -13,4 +13,4 @@ frappe.ui.form.on("Course Schedule", {
}).addClass("btn-primary");
}
}
-});
\ No newline at end of file
+});
diff --git a/erpnext/education/doctype/course_schedule/course_schedule.py b/erpnext/education/doctype/course_schedule/course_schedule.py
index 5083ff6589..748728d104 100644
--- a/erpnext/education/doctype/course_schedule/course_schedule.py
+++ b/erpnext/education/doctype/course_schedule/course_schedule.py
@@ -14,11 +14,11 @@ class CourseSchedule(Document):
self.validate_course()
self.validate_date()
self.validate_overlap()
-
+
def set_title(self):
"""Set document Title"""
self.title = self.course + " by " + (self.instructor_name if self.instructor_name else self.instructor)
-
+
def validate_course(self):
group_based_on, course = frappe.db.get_value("Student Group", self.student_group, ["group_based_on", "course"])
if group_based_on == "Course":
@@ -28,23 +28,22 @@ class CourseSchedule(Document):
"""Validates if from_time is greater than to_time"""
if self.from_time > self.to_time:
frappe.throw(_("From Time cannot be greater than To Time."))
-
+
def validate_overlap(self):
"""Validates overlap for Student Group, Instructor, Room"""
-
+
from erpnext.education.utils import validate_overlap_for
#Validate overlapping course schedules.
if self.student_group:
validate_overlap_for(self, "Course Schedule", "student_group")
-
+
validate_overlap_for(self, "Course Schedule", "instructor")
validate_overlap_for(self, "Course Schedule", "room")
#validate overlapping assessment schedules.
if self.student_group:
validate_overlap_for(self, "Assessment Plan", "student_group")
-
+
validate_overlap_for(self, "Assessment Plan", "room")
validate_overlap_for(self, "Assessment Plan", "supervisor", self.instructor)
-
diff --git a/erpnext/education/doctype/course_schedule/course_schedule_dashboard.py b/erpnext/education/doctype/course_schedule/course_schedule_dashboard.py
index 0866cd6535..22ce7e1ec2 100644
--- a/erpnext/education/doctype/course_schedule/course_schedule_dashboard.py
+++ b/erpnext/education/doctype/course_schedule/course_schedule_dashboard.py
@@ -12,4 +12,4 @@ def get_data():
'items': ['Student Attendance']
}
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/education/doctype/course_schedule/test_course_schedule.py b/erpnext/education/doctype/course_schedule/test_course_schedule.py
index a901f1e467..5bb4de8584 100644
--- a/erpnext/education/doctype/course_schedule/test_course_schedule.py
+++ b/erpnext/education/doctype/course_schedule/test_course_schedule.py
@@ -17,28 +17,28 @@ class TestCourseSchedule(unittest.TestCase):
def test_student_group_conflict(self):
cs1 = make_course_schedule_test_record(simulate= True)
- cs2 = make_course_schedule_test_record(schedule_date=cs1.schedule_date, from_time= cs1.from_time,
+ cs2 = make_course_schedule_test_record(schedule_date=cs1.schedule_date, from_time= cs1.from_time,
to_time= cs1.to_time, instructor="_Test Instructor 2", room=frappe.get_all("Room")[1].name, do_not_save= 1)
self.assertRaises(OverlapError, cs2.save)
def test_instructor_conflict(self):
cs1 = make_course_schedule_test_record(simulate= True)
-
- cs2 = make_course_schedule_test_record(from_time= cs1.from_time, to_time= cs1.to_time,
+
+ cs2 = make_course_schedule_test_record(from_time= cs1.from_time, to_time= cs1.to_time,
student_group="Course-TC101-2014-2015 (_Test Academic Term)", room=frappe.get_all("Room")[1].name, do_not_save= 1)
self.assertRaises(OverlapError, cs2.save)
def test_room_conflict(self):
cs1 = make_course_schedule_test_record(simulate= True)
-
- cs2 = make_course_schedule_test_record(from_time= cs1.from_time, to_time= cs1.to_time,
+
+ cs2 = make_course_schedule_test_record(from_time= cs1.from_time, to_time= cs1.to_time,
student_group="Course-TC101-2014-2015 (_Test Academic Term)", instructor="_Test Instructor 2", do_not_save= 1)
self.assertRaises(OverlapError, cs2.save)
-
+
def test_no_conflict(self):
cs1 = make_course_schedule_test_record(simulate= True)
-
- make_course_schedule_test_record(from_time= cs1.from_time, to_time= cs1.to_time,
+
+ make_course_schedule_test_record(from_time= cs1.from_time, to_time= cs1.to_time,
student_group="Course-TC102-2014-2015 (_Test Academic Term)", instructor="_Test Instructor 2", room=frappe.get_all("Room")[1].name)
def make_course_schedule_test_record(**args):
@@ -49,12 +49,12 @@ def make_course_schedule_test_record(**args):
course_schedule.course = args.course or "TC101"
course_schedule.instructor = args.instructor or "_Test Instructor"
course_schedule.room = args.room or frappe.get_all("Room")[0].name
-
+
course_schedule.schedule_date = args.schedule_date or today()
course_schedule.from_time = args.from_time or to_timedelta("01:00:00")
course_schedule.to_time = args.to_time or course_schedule.from_time + datetime.timedelta(hours= 1)
-
+
if not args.do_not_save:
if args.simulate:
while True:
diff --git a/erpnext/education/doctype/course_scheduling_tool/course_scheduling_tool.js b/erpnext/education/doctype/course_scheduling_tool/course_scheduling_tool.js
index d57f46ab98..7b0e4ab47c 100644
--- a/erpnext/education/doctype/course_scheduling_tool/course_scheduling_tool.js
+++ b/erpnext/education/doctype/course_scheduling_tool/course_scheduling_tool.js
@@ -41,4 +41,4 @@ frappe.ui.form.on('Course Scheduling Tool', {
});
});
}
-});
\ No newline at end of file
+});
diff --git a/erpnext/education/doctype/education_settings/education_settings.py b/erpnext/education/doctype/education_settings/education_settings.py
index 658380ea42..6c7e95c80d 100644
--- a/erpnext/education/doctype/education_settings/education_settings.py
+++ b/erpnext/education/doctype/education_settings/education_settings.py
@@ -36,4 +36,4 @@ class EducationSettings(Document):
make_property_setter('Instructor', "naming_series", "hidden", 1, "Check", validate_fields_for_doctype=False)
def update_website_context(context):
- context["lms_enabled"] = frappe.get_doc("Education Settings").enable_lms
\ No newline at end of file
+ context["lms_enabled"] = frappe.get_doc("Education Settings").enable_lms
diff --git a/erpnext/education/doctype/fee_schedule/fee_schedule.js b/erpnext/education/doctype/fee_schedule/fee_schedule.js
index 0089957df4..97691a5b62 100644
--- a/erpnext/education/doctype/fee_schedule/fee_schedule.js
+++ b/erpnext/education/doctype/fee_schedule/fee_schedule.js
@@ -130,4 +130,4 @@ frappe.ui.form.on('Fee Schedule Student Group', {
});
}
}
-})
\ No newline at end of file
+})
diff --git a/erpnext/education/doctype/fee_schedule/fee_schedule_dashboard.py b/erpnext/education/doctype/fee_schedule/fee_schedule_dashboard.py
index acfe400219..4d7da21ea1 100644
--- a/erpnext/education/doctype/fee_schedule/fee_schedule_dashboard.py
+++ b/erpnext/education/doctype/fee_schedule/fee_schedule_dashboard.py
@@ -10,4 +10,4 @@ def get_data():
'items': ['Fees']
}
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/education/doctype/fee_structure/fee_structure.js b/erpnext/education/doctype/fee_structure/fee_structure.js
index 310c4105f4..d9ab99f818 100644
--- a/erpnext/education/doctype/fee_structure/fee_structure.js
+++ b/erpnext/education/doctype/fee_structure/fee_structure.js
@@ -69,4 +69,4 @@ frappe.ui.form.on('Fee Component', {
}
frm.set_value('total_amount', total_amount);
}
-});
\ No newline at end of file
+});
diff --git a/erpnext/education/doctype/fee_structure/fee_structure.py b/erpnext/education/doctype/fee_structure/fee_structure.py
index 781382b51b..9755717ee9 100644
--- a/erpnext/education/doctype/fee_structure/fee_structure.py
+++ b/erpnext/education/doctype/fee_structure/fee_structure.py
@@ -11,13 +11,13 @@ from frappe.model.mapper import get_mapped_doc
class FeeStructure(Document):
def validate(self):
self.calculate_total()
-
+
def calculate_total(self):
"""Calculates total amount."""
self.total_amount = 0
for d in self.components:
self.total_amount += d.amount
-
+
@frappe.whitelist()
def make_fee_schedule(source_name, target_doc=None):
@@ -31,4 +31,4 @@ def make_fee_schedule(source_name, target_doc=None):
"Fee Component": {
"doctype": "Fee Component"
}
- }, target_doc)
\ No newline at end of file
+ }, target_doc)
diff --git a/erpnext/education/doctype/fee_structure/fee_structure_dashboard.py b/erpnext/education/doctype/fee_structure/fee_structure_dashboard.py
index 73e314f351..fdf7df7aa2 100644
--- a/erpnext/education/doctype/fee_structure/fee_structure_dashboard.py
+++ b/erpnext/education/doctype/fee_structure/fee_structure_dashboard.py
@@ -12,4 +12,4 @@ def get_data():
'items': ['Fees', 'Fee Schedule']
}
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/education/doctype/fees/fees.py b/erpnext/education/doctype/fees/fees.py
index 25d67d2d5f..7e86704904 100644
--- a/erpnext/education/doctype/fees/fees.py
+++ b/erpnext/education/doctype/fees/fees.py
@@ -132,4 +132,4 @@ def get_list_context(context=None):
"title": _("Fees"),
"get_list": get_fee_list,
"row_template": "templates/includes/fee/fee_row.html"
- }
\ No newline at end of file
+ }
diff --git a/erpnext/education/doctype/fees/fees_list.js b/erpnext/education/doctype/fees/fees_list.js
index 52e1c4beb5..ee8e1e382e 100644
--- a/erpnext/education/doctype/fees/fees_list.js
+++ b/erpnext/education/doctype/fees/fees_list.js
@@ -9,4 +9,4 @@ frappe.listview_settings['Fees'] = {
return [__("Overdue"), "red", "outstanding_amount,>,0|due_date,<=,Today"];
}
}
-};
\ No newline at end of file
+};
diff --git a/erpnext/education/doctype/grading_scale/grading_scale.py b/erpnext/education/doctype/grading_scale/grading_scale.py
index 6309d02c15..0e73297161 100644
--- a/erpnext/education/doctype/grading_scale/grading_scale.py
+++ b/erpnext/education/doctype/grading_scale/grading_scale.py
@@ -17,4 +17,4 @@ class GradingScale(Document):
else:
thresholds.append(cint(d.threshold))
if 0 not in thresholds:
- frappe.throw(_("Please define grade for Threshold 0%"))
\ No newline at end of file
+ frappe.throw(_("Please define grade for Threshold 0%"))
diff --git a/erpnext/education/doctype/grading_scale/test_grading_scale.js b/erpnext/education/doctype/grading_scale/test_grading_scale.js
index e363545ff8..fb56918fdb 100644
--- a/erpnext/education/doctype/grading_scale/test_grading_scale.js
+++ b/erpnext/education/doctype/grading_scale/test_grading_scale.js
@@ -99,4 +99,4 @@ QUnit.test('Test: Grading Scale', function(assert){
() => done()
]);
-});
\ No newline at end of file
+});
diff --git a/erpnext/education/doctype/guardian/test_guardian.js b/erpnext/education/doctype/guardian/test_guardian.js
index 9bbfacd580..1ea6dc290b 100644
--- a/erpnext/education/doctype/guardian/test_guardian.js
+++ b/erpnext/education/doctype/guardian/test_guardian.js
@@ -31,4 +31,4 @@ QUnit.test('Test: Guardian', function(assert){
},
() => done()
]);
-});
\ No newline at end of file
+});
diff --git a/erpnext/education/doctype/instructor/instructor.js b/erpnext/education/doctype/instructor/instructor.js
index 24e80fa937..034b0aaf5d 100644
--- a/erpnext/education/doctype/instructor/instructor.js
+++ b/erpnext/education/doctype/instructor/instructor.js
@@ -61,4 +61,4 @@ frappe.ui.form.on("Instructor", {
};
});
}
-});
\ No newline at end of file
+});
diff --git a/erpnext/education/doctype/instructor/instructor_dashboard.py b/erpnext/education/doctype/instructor/instructor_dashboard.py
index a404fc56c5..c19c85947d 100644
--- a/erpnext/education/doctype/instructor/instructor_dashboard.py
+++ b/erpnext/education/doctype/instructor/instructor_dashboard.py
@@ -21,4 +21,4 @@ def get_data():
'items': ['Student Group']
}
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/education/doctype/program/program.js b/erpnext/education/doctype/program/program.js
index 98263b55a1..2d89351504 100644
--- a/erpnext/education/doctype/program/program.js
+++ b/erpnext/education/doctype/program/program.js
@@ -4,5 +4,5 @@
cur_frm.add_fetch('fee_structure', 'total_amount', 'amount');
frappe.ui.form.on("Program", "refresh", function(frm) {
-
-});
\ No newline at end of file
+
+});
diff --git a/erpnext/education/doctype/program/program.py b/erpnext/education/doctype/program/program.py
index d24df5d614..9d886b7b9e 100644
--- a/erpnext/education/doctype/program/program.py
+++ b/erpnext/education/doctype/program/program.py
@@ -11,4 +11,4 @@ class Program(Document):
def get_course_list(self):
program_course_list = self.courses
course_list = [frappe.get_doc("Course", program_course.course) for program_course in program_course_list]
- return course_list
\ No newline at end of file
+ return course_list
diff --git a/erpnext/education/doctype/program/program_dashboard.py b/erpnext/education/doctype/program/program_dashboard.py
index c5d249451f..6c503e1bf1 100644
--- a/erpnext/education/doctype/program/program_dashboard.py
+++ b/erpnext/education/doctype/program/program_dashboard.py
@@ -21,4 +21,4 @@ def get_data():
'items': ['Assessment Plan', 'Assessment Result']
}
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/education/doctype/program/test_program.js b/erpnext/education/doctype/program/test_program.js
index dc347cf1b0..b9ca41ae3f 100644
--- a/erpnext/education/doctype/program/test_program.js
+++ b/erpnext/education/doctype/program/test_program.js
@@ -31,4 +31,4 @@ QUnit.test('Test: Program', function(assert){
},
() => done()
]);
-});
\ No newline at end of file
+});
diff --git a/erpnext/education/doctype/program/test_program.py b/erpnext/education/doctype/program/test_program.py
index d753036511..204f2961e7 100644
--- a/erpnext/education/doctype/program/test_program.py
+++ b/erpnext/education/doctype/program/test_program.py
@@ -88,4 +88,4 @@ def setup_program():
course_list = [course['course_name'] for course in test_data['course']]
program = make_program_and_linked_courses(test_data['program_name'], course_list)
- return program
\ No newline at end of file
+ return program
diff --git a/erpnext/education/doctype/program_enrollment/program_enrollment.js b/erpnext/education/doctype/program_enrollment/program_enrollment.js
index f9c65fbbfb..e92d063602 100644
--- a/erpnext/education/doctype/program_enrollment/program_enrollment.js
+++ b/erpnext/education/doctype/program_enrollment/program_enrollment.js
@@ -101,4 +101,4 @@ frappe.ui.form.on('Program Enrollment Course', {
return { filters: [['Course', 'name', 'not in', course_list]] };
};
}
-});
\ No newline at end of file
+});
diff --git a/erpnext/education/doctype/program_enrollment/program_enrollment.py b/erpnext/education/doctype/program_enrollment/program_enrollment.py
index b282babd0f..dd4aa576ac 100644
--- a/erpnext/education/doctype/program_enrollment/program_enrollment.py
+++ b/erpnext/education/doctype/program_enrollment/program_enrollment.py
@@ -174,4 +174,3 @@ def get_students(doctype, txt, searchfield, start, page_len, filters):
tuple(students + ["%%%s%%" % txt, start, page_len]
)
)
-
diff --git a/erpnext/education/doctype/program_enrollment/program_enrollment_dashboard.py b/erpnext/education/doctype/program_enrollment/program_enrollment_dashboard.py
index 18d307cdf0..c47f866689 100644
--- a/erpnext/education/doctype/program_enrollment/program_enrollment_dashboard.py
+++ b/erpnext/education/doctype/program_enrollment/program_enrollment_dashboard.py
@@ -16,4 +16,4 @@ def get_data():
'items': ['Student and Guardian Contact Details']
}
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/education/doctype/program_enrollment/test_program_enrollment.py b/erpnext/education/doctype/program_enrollment/test_program_enrollment.py
index fec6422e75..497ee288aa 100644
--- a/erpnext/education/doctype/program_enrollment/test_program_enrollment.py
+++ b/erpnext/education/doctype/program_enrollment/test_program_enrollment.py
@@ -32,4 +32,4 @@ class TestProgramEnrollment(unittest.TestCase):
for entry in frappe.db.get_all("Program Enrollment"):
doc = frappe.get_doc("Program Enrollment", entry.name)
doc.cancel()
- doc.delete()
\ No newline at end of file
+ doc.delete()
diff --git a/erpnext/education/doctype/question/question.py b/erpnext/education/doctype/question/question.py
index a7deeab6f6..fb3b50478c 100644
--- a/erpnext/education/doctype/question/question.py
+++ b/erpnext/education/doctype/question/question.py
@@ -43,4 +43,4 @@ class Question(Document):
elif len(answers) == 1:
return answers[0]
else:
- return answers
\ No newline at end of file
+ return answers
diff --git a/erpnext/education/doctype/quiz/quiz.js b/erpnext/education/doctype/quiz/quiz.js
index 01bcf73236..320869be31 100644
--- a/erpnext/education/doctype/quiz/quiz.js
+++ b/erpnext/education/doctype/quiz/quiz.js
@@ -68,4 +68,4 @@ let get_topics_without_quiz = function(quiz) {
method: 'erpnext.education.doctype.quiz.quiz.get_topics_without_quiz',
args: {'quiz': quiz}
});
-};
\ No newline at end of file
+};
diff --git a/erpnext/education/doctype/quiz/quiz.py b/erpnext/education/doctype/quiz/quiz.py
index a774b88579..a128e1f342 100644
--- a/erpnext/education/doctype/quiz/quiz.py
+++ b/erpnext/education/doctype/quiz/quiz.py
@@ -68,4 +68,4 @@ def get_topics_without_quiz(quiz):
topic_contents = [tc.content for tc in topic.topic_content]
if not topic_contents or quiz not in topic_contents:
data.append(topic.name)
- return data
\ No newline at end of file
+ return data
diff --git a/erpnext/education/doctype/room/room.js b/erpnext/education/doctype/room/room.js
index 20cee6b2a6..1263b60ced 100644
--- a/erpnext/education/doctype/room/room.js
+++ b/erpnext/education/doctype/room/room.js
@@ -1,2 +1,2 @@
frappe.ui.form.on("Room", {
-});
\ No newline at end of file
+});
diff --git a/erpnext/education/doctype/room/room_dashboard.py b/erpnext/education/doctype/room/room_dashboard.py
index 99aac3393e..7bcb97f709 100644
--- a/erpnext/education/doctype/room/room_dashboard.py
+++ b/erpnext/education/doctype/room/room_dashboard.py
@@ -16,4 +16,4 @@ def get_data():
'items': ['Assessment Plan']
}
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/education/doctype/student/student.js b/erpnext/education/doctype/student/student.js
index fd23ae41ef..aead556dc9 100644
--- a/erpnext/education/doctype/student/student.js
+++ b/erpnext/education/doctype/student/student.js
@@ -60,4 +60,4 @@ frappe.ui.form.on('Student Sibling', {
return { filters: [['Student', 'name', 'not in', sibling_list]] };
};
}
-});
\ No newline at end of file
+});
diff --git a/erpnext/education/doctype/student/student_list.js b/erpnext/education/doctype/student/student_list.js
index 763f120f41..c1bce24d15 100644
--- a/erpnext/education/doctype/student/student_list.js
+++ b/erpnext/education/doctype/student/student_list.js
@@ -1,3 +1,3 @@
frappe.listview_settings['Student'] = {
add_fields: [ "image"]
-}
\ No newline at end of file
+}
diff --git a/erpnext/education/doctype/student/test_student.py b/erpnext/education/doctype/student/test_student.py
index 2e5263788f..fcb2b5fb93 100644
--- a/erpnext/education/doctype/student/test_student.py
+++ b/erpnext/education/doctype/student/test_student.py
@@ -68,4 +68,4 @@ def get_student(email):
student_id = frappe.get_all("Student", {"student_email_id": email}, ["name"])[0].name
return frappe.get_doc("Student", student_id)
except IndexError:
- return None
\ No newline at end of file
+ return None
diff --git a/erpnext/education/doctype/student_admission/templates/student_admission_row.html b/erpnext/education/doctype/student_admission/templates/student_admission_row.html
index 99868d5f02..529d65184a 100644
--- a/erpnext/education/doctype/student_admission/templates/student_admission_row.html
+++ b/erpnext/education/doctype/student_admission/templates/student_admission_row.html
@@ -41,4 +41,4 @@
-
\ No newline at end of file
+
diff --git a/erpnext/education/doctype/student_admission/test_student_admission.js b/erpnext/education/doctype/student_admission/test_student_admission.js
index 3a0bb0b2f2..e01791a78a 100644
--- a/erpnext/education/doctype/student_admission/test_student_admission.js
+++ b/erpnext/education/doctype/student_admission/test_student_admission.js
@@ -37,4 +37,4 @@ QUnit.test('Test: Student Admission', function(assert) {
},
() => done()
]);
-});
\ No newline at end of file
+});
diff --git a/erpnext/education/doctype/student_applicant/student_applicant.js b/erpnext/education/doctype/student_applicant/student_applicant.js
index b4cfdf16e0..7b41a72174 100644
--- a/erpnext/education/doctype/student_applicant/student_applicant.js
+++ b/erpnext/education/doctype/student_applicant/student_applicant.js
@@ -59,4 +59,4 @@ frappe.ui.form.on('Student Sibling', {
frm.add_fetch("student", "gender", "gender");
frm.add_fetch("student", "date_of_birth", "date_of_birth");
}
-});
\ No newline at end of file
+});
diff --git a/erpnext/education/doctype/student_applicant/student_applicant.py b/erpnext/education/doctype/student_applicant/student_applicant.py
index 211348201e..193b6d3297 100644
--- a/erpnext/education/doctype/student_applicant/student_applicant.py
+++ b/erpnext/education/doctype/student_applicant/student_applicant.py
@@ -49,7 +49,7 @@ class StudentApplicant(Document):
frappe.throw(_("Please select Student Admission which is mandatory for the paid student applicant"))
def validation_from_student_admission(self):
-
+
student_admission = get_student_admission_data(self.student_admission, self.program)
if student_admission and student_admission.min_age and \
diff --git a/erpnext/education/doctype/student_applicant/student_applicant_list.js b/erpnext/education/doctype/student_applicant/student_applicant_list.js
index 817a728f69..c39d46ec63 100644
--- a/erpnext/education/doctype/student_applicant/student_applicant_list.js
+++ b/erpnext/education/doctype/student_applicant/student_applicant_list.js
@@ -18,4 +18,4 @@ frappe.listview_settings['Student Applicant'] = {
return [__("Admitted"), "blue", "application_status,=,Admitted"];
}
}
-};
\ No newline at end of file
+};
diff --git a/erpnext/education/doctype/student_applicant/tests/test_student_applicant.js b/erpnext/education/doctype/student_applicant/tests/test_student_applicant.js
index a69ad8a564..fa67977985 100644
--- a/erpnext/education/doctype/student_applicant/tests/test_student_applicant.js
+++ b/erpnext/education/doctype/student_applicant/tests/test_student_applicant.js
@@ -92,4 +92,4 @@ QUnit.test('Test: Student Applicant', function(assert){
},
() => done()
]);
-});
\ No newline at end of file
+});
diff --git a/erpnext/education/doctype/student_applicant/tests/test_student_applicant_dummy_data.js b/erpnext/education/doctype/student_applicant/tests/test_student_applicant_dummy_data.js
index 26244ab184..03101e41e0 100644
--- a/erpnext/education/doctype/student_applicant/tests/test_student_applicant_dummy_data.js
+++ b/erpnext/education/doctype/student_applicant/tests/test_student_applicant_dummy_data.js
@@ -84,4 +84,4 @@ QUnit.test('Make Students', function(assert){
},
() => done()
]);
-});
\ No newline at end of file
+});
diff --git a/erpnext/education/doctype/student_applicant/tests/test_student_applicant_options.js b/erpnext/education/doctype/student_applicant/tests/test_student_applicant_options.js
index 114358f32a..daa36e75ce 100644
--- a/erpnext/education/doctype/student_applicant/tests/test_student_applicant_options.js
+++ b/erpnext/education/doctype/student_applicant/tests/test_student_applicant_options.js
@@ -107,4 +107,4 @@ QUnit.test('test student applicant', function(assert){
},
() => done()
]);
-});
\ No newline at end of file
+});
diff --git a/erpnext/education/doctype/student_attendance/student_attendance.js b/erpnext/education/doctype/student_attendance/student_attendance.js
index f025a1a539..2bbecb911f 100644
--- a/erpnext/education/doctype/student_attendance/student_attendance.js
+++ b/erpnext/education/doctype/student_attendance/student_attendance.js
@@ -2,4 +2,4 @@
// For license information, please see license.txt
cur_frm.add_fetch("course_schedule", "schedule_date", "date");
-cur_frm.add_fetch("course_schedule", "student_group", "student_group")
\ No newline at end of file
+cur_frm.add_fetch("course_schedule", "student_group", "student_group")
diff --git a/erpnext/education/doctype/student_attendance/student_attendance_dashboard.py b/erpnext/education/doctype/student_attendance/student_attendance_dashboard.py
index 9c41b8f3dc..e405b8aed9 100644
--- a/erpnext/education/doctype/student_attendance/student_attendance_dashboard.py
+++ b/erpnext/education/doctype/student_attendance/student_attendance_dashboard.py
@@ -9,4 +9,4 @@ def get_data():
'items': ['Student Monthly Attendance Sheet', 'Student Batch-Wise Attendance']
}
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/education/doctype/student_attendance/student_attendance_list.js b/erpnext/education/doctype/student_attendance/student_attendance_list.js
index 0d3e7ade15..e89b76c8d5 100644
--- a/erpnext/education/doctype/student_attendance/student_attendance_list.js
+++ b/erpnext/education/doctype/student_attendance/student_attendance_list.js
@@ -8,4 +8,4 @@ frappe.listview_settings['Student Attendance'] = {
return [__("Present"), "green", "status,=,Present"];
}
}
-};
\ No newline at end of file
+};
diff --git a/erpnext/education/doctype/student_attendance/test_student_attendance.js b/erpnext/education/doctype/student_attendance/test_student_attendance.js
index c7da6f6b24..3d30b090ba 100644
--- a/erpnext/education/doctype/student_attendance/test_student_attendance.js
+++ b/erpnext/education/doctype/student_attendance/test_student_attendance.js
@@ -28,4 +28,4 @@ QUnit.test('Test: Student Attendance', function(assert){
() => done()
]);
-});
\ No newline at end of file
+});
diff --git a/erpnext/education/doctype/student_attendance_tool/student_attendance_tool.py b/erpnext/education/doctype/student_attendance_tool/student_attendance_tool.py
index 028db91881..972973fbad 100644
--- a/erpnext/education/doctype/student_attendance_tool/student_attendance_tool.py
+++ b/erpnext/education/doctype/student_attendance_tool/student_attendance_tool.py
@@ -38,4 +38,4 @@ def get_student_attendance_records(based_on, date=None, student_group=None, cour
if student.student == attendance.student:
student.status = attendance.status
- return student_list
\ No newline at end of file
+ return student_list
diff --git a/erpnext/education/doctype/student_attendance_tool/test_student_attendance_tool.js b/erpnext/education/doctype/student_attendance_tool/test_student_attendance_tool.js
index cea0761ae8..b66d8397ba 100644
--- a/erpnext/education/doctype/student_attendance_tool/test_student_attendance_tool.js
+++ b/erpnext/education/doctype/student_attendance_tool/test_student_attendance_tool.js
@@ -82,4 +82,4 @@ QUnit.test('Test: Student Attendace Tool', function(assert){
() => done()
]);
-});
\ No newline at end of file
+});
diff --git a/erpnext/education/doctype/student_group/student_group.js b/erpnext/education/doctype/student_group/student_group.js
index 51e3b74a5c..39ee9cebd1 100644
--- a/erpnext/education/doctype/student_group/student_group.js
+++ b/erpnext/education/doctype/student_group/student_group.js
@@ -142,4 +142,4 @@ frappe.ui.form.on('Student Group Instructor', {
return { filters: [['Instructor', 'name', 'not in', instructor_list]] };
};
}
-});
\ No newline at end of file
+});
diff --git a/erpnext/education/doctype/student_group/student_group.py b/erpnext/education/doctype/student_group/student_group.py
index 0260b80864..3d4572abf7 100644
--- a/erpnext/education/doctype/student_group/student_group.py
+++ b/erpnext/education/doctype/student_group/student_group.py
@@ -128,4 +128,3 @@ def fetch_students(doctype, txt, searchfield, start, page_len, filters):
order by idx desc, name
limit %s, %s""".format(searchfield),
tuple(["%%%s%%" % txt, "%%%s%%" % txt, start, page_len]))
-
diff --git a/erpnext/education/doctype/student_group/student_group_dashboard.py b/erpnext/education/doctype/student_group/student_group_dashboard.py
index ad7a6de7b3..d37445f7b9 100644
--- a/erpnext/education/doctype/student_group/student_group_dashboard.py
+++ b/erpnext/education/doctype/student_group/student_group_dashboard.py
@@ -16,4 +16,4 @@ def get_data():
'items': ['Course Schedule']
}
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/education/doctype/student_group/test_student_group.js b/erpnext/education/doctype/student_group/test_student_group.js
index 6673343be7..4c7e47bc38 100644
--- a/erpnext/education/doctype/student_group/test_student_group.js
+++ b/erpnext/education/doctype/student_group/test_student_group.js
@@ -53,4 +53,4 @@ QUnit.test('Test: Student Group', function(assert){
() => done()
]);
-});
\ No newline at end of file
+});
diff --git a/erpnext/education/doctype/student_group_creation_tool/student_group_creation_tool.js b/erpnext/education/doctype/student_group_creation_tool/student_group_creation_tool.js
index d0d7afd701..c189e2763c 100644
--- a/erpnext/education/doctype/student_group_creation_tool/student_group_creation_tool.js
+++ b/erpnext/education/doctype/student_group_creation_tool/student_group_creation_tool.js
@@ -37,4 +37,4 @@ frappe.ui.form.on("Student Group Creation Tool", "onload", function(frm){
}
};
});
-});
\ No newline at end of file
+});
diff --git a/erpnext/education/doctype/student_group_creation_tool/student_group_creation_tool.py b/erpnext/education/doctype/student_group_creation_tool/student_group_creation_tool.py
index dc8667ec06..28ff7d618c 100644
--- a/erpnext/education/doctype/student_group_creation_tool/student_group_creation_tool.py
+++ b/erpnext/education/doctype/student_group_creation_tool/student_group_creation_tool.py
@@ -76,4 +76,4 @@ class StudentGroupCreationTool(Document):
student_group.append('students', student)
student_group.save()
- frappe.msgprint(_("{0} Student Groups created.").format(l))
\ No newline at end of file
+ frappe.msgprint(_("{0} Student Groups created.").format(l))
diff --git a/erpnext/education/doctype/student_group_creation_tool/test_student_group_creation_tool.js b/erpnext/education/doctype/student_group_creation_tool/test_student_group_creation_tool.js
index 34c10930b5..fa612ba272 100644
--- a/erpnext/education/doctype/student_group_creation_tool/test_student_group_creation_tool.js
+++ b/erpnext/education/doctype/student_group_creation_tool/test_student_group_creation_tool.js
@@ -81,4 +81,4 @@ QUnit.test('Test: Student Group Creation Tool', function(assert){
() => done()
]);
-});
\ No newline at end of file
+});
diff --git a/erpnext/education/doctype/student_group_student/student_group_student.py b/erpnext/education/doctype/student_group_student/student_group_student.py
index 820e30118d..1fe4ea1dc3 100644
--- a/erpnext/education/doctype/student_group_student/student_group_student.py
+++ b/erpnext/education/doctype/student_group_student/student_group_student.py
@@ -7,4 +7,4 @@ import frappe
from frappe.model.document import Document
class StudentGroupStudent(Document):
- pass
\ No newline at end of file
+ pass
diff --git a/erpnext/education/doctype/student_leave_application/student_leave_application_dashboard.py b/erpnext/education/doctype/student_leave_application/student_leave_application_dashboard.py
index fdcc147479..0ff6d1a76e 100644
--- a/erpnext/education/doctype/student_leave_application/student_leave_application_dashboard.py
+++ b/erpnext/education/doctype/student_leave_application/student_leave_application_dashboard.py
@@ -8,4 +8,4 @@ def get_data():
'items': ['Student Attendance']
}
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/education/doctype/student_leave_application/test_student_leave_application.js b/erpnext/education/doctype/student_leave_application/test_student_leave_application.js
index 5af9f5d50f..6bbf17babf 100644
--- a/erpnext/education/doctype/student_leave_application/test_student_leave_application.js
+++ b/erpnext/education/doctype/student_leave_application/test_student_leave_application.js
@@ -66,4 +66,4 @@ QUnit.test('Test: Student Leave Application', function(assert){
() => done()
]);
-});
\ No newline at end of file
+});
diff --git a/erpnext/education/doctype/student_leave_application/test_student_leave_application.py b/erpnext/education/doctype/student_leave_application/test_student_leave_application.py
index fcdd42825f..9cae257748 100644
--- a/erpnext/education/doctype/student_leave_application/test_student_leave_application.py
+++ b/erpnext/education/doctype/student_leave_application/test_student_leave_application.py
@@ -112,4 +112,4 @@ def create_holiday_list():
company = get_default_company() or frappe.get_all('Company')[0].name
frappe.db.set_value('Company', company, 'default_holiday_list', holiday_list)
- return holiday_list
\ No newline at end of file
+ return holiday_list
diff --git a/erpnext/education/doctype/student_log/test_student_log.js b/erpnext/education/doctype/student_log/test_student_log.js
index 5775369e52..4c90c5f6ef 100644
--- a/erpnext/education/doctype/student_log/test_student_log.js
+++ b/erpnext/education/doctype/student_log/test_student_log.js
@@ -32,4 +32,4 @@ QUnit.test('Test: Student Log', function(assert){
},
() => done()
]);
-});
\ No newline at end of file
+});
diff --git a/erpnext/education/doctype/student_report_generation_tool/student_report_generation_tool.html b/erpnext/education/doctype/student_report_generation_tool/student_report_generation_tool.html
index 72772b7b32..a9e84e6e27 100644
--- a/erpnext/education/doctype/student_report_generation_tool/student_report_generation_tool.html
+++ b/erpnext/education/doctype/student_report_generation_tool/student_report_generation_tool.html
@@ -12,67 +12,67 @@
padding: 0.75in;
margin: auto;
}
-
+
.print-format.landscape {
max-width: 11.69in;
padding: 0.2in;
}
-
+
.page-break {
padding: 30px 0px;
border-bottom: 1px dashed #888;
}
-
+
.page-break:first-child {
padding-top: 0px;
}
-
+
.page-break:last-child {
border-bottom: 0px;
}
-
+
/* mozilla hack for images in table */
body:last-child .print-format td img {
width: 100% !important;
}
-
+
@media(max-width: 767px) {
.print-format {
padding: 0.2in;
}
}
}
-
+
@media print {
.print-format p {
margin-left: 1px;
margin-right: 1px;
}
}
-
+
.data-field {
margin-top: 5px;
margin-bottom: 5px;
}
-
+
.data-field .value {
word-wrap: break-word;
}
-
+
.important .value {
font-size: 120%;
font-weight: bold;
}
-
+
.important label {
line-height: 1.8;
margin: 0px;
}
-
+
.table {
margin: 20px 0px;
}
-
+
.square-image {
width: 100%;
height: 0;
@@ -83,88 +83,88 @@
background-position: center center;
border-radius: 4px;
}
-
+
.print-item-image {
object-fit: contain;
}
-
+
.pdf-variables,
.pdf-variable,
.visible-pdf {
display: none !important;
}
-
+
.print-format {
font-size: 9pt;
font-family: "Helvetica Neue", Helvetica, Arial, "Open Sans", sans-serif;
-webkit-print-color-adjust:exact;
}
-
+
.page-break {
page-break-after: always;
}
-
+
.print-heading {
border-bottom: 1px solid #aaa;
margin-bottom: 10px;
}
-
+
.print-heading h2 {
margin: 0px;
}
.print-heading h4 {
margin-top: 5px;
}
-
+
table.no-border, table.no-border td {
border: 0px;
}
-
+
.print-format label {
/* wkhtmltopdf breaks label into multiple lines when it is inline-block */
display: block;
}
-
+
.print-format img {
max-width: 100%;
}
-
+
.print-format table td > .primary:first-child {
font-weight: bold;
}
-
+
.print-format td, .print-format th {
vertical-align: top !important;
padding: 6px !important;
}
-
+
.print-format p {
margin: 3px 0px 3px;
}
-
+
table td div {
-
+
/* needed to avoid partial cutting of text between page break in wkhtmltopdf */
page-break-inside: avoid !important;
-
+
}
-
+
/* hack for webkit specific browser */
@media (-webkit-min-device-pixel-ratio:0) {
thead, tfoot { display: table-row-group; }
}
-
+
[document-status] {
margin-bottom: 5mm;
}
-
+
.signature-img {
background: #fff;
border-radius: 3px;
margin-top: 5px;
max-height: 150px;
}
-
+
.print-heading {
text-align: right;
text-transform: uppercase;
@@ -173,16 +173,16 @@
margin-bottom: 20px;
border-bottom: 1px solid #d1d8dd;
}
-
+
.print-heading h2 {
font-size: 24px;
}
-
+
.print-format th {
background-color: #eee !important;
border-bottom: 0px !important;
}
-
+
/* modern format: for-test */
.pbi_avoid {
@@ -344,7 +344,7 @@
-
+
{{ _("Student Attendance")}}
Present {{ doc.attendance.get("Present") if doc.attendance.get("Present") != None else '0' }} days
@@ -352,7 +352,7 @@
-
+
{{ _("Parents Teacher Meeting Attendance")}}
Present {{ doc.parents_attendance if doc.parents_attendance != None else '0' }}
diff --git a/erpnext/education/doctype/topic/topic.js b/erpnext/education/doctype/topic/topic.js
index 2002b0c8e3..0c903c5a56 100644
--- a/erpnext/education/doctype/topic/topic.js
+++ b/erpnext/education/doctype/topic/topic.js
@@ -52,4 +52,4 @@ let get_courses_without_topic = function(topic) {
method: 'erpnext.education.doctype.topic.topic.get_courses_without_topic',
args: {'topic': topic}
});
-};
\ No newline at end of file
+};
diff --git a/erpnext/education/doctype/topic/topic.py b/erpnext/education/doctype/topic/topic.py
index a5253e9329..fb680d725b 100644
--- a/erpnext/education/doctype/topic/topic.py
+++ b/erpnext/education/doctype/topic/topic.py
@@ -56,4 +56,4 @@ def add_content_to_topics(content_type, content, topics):
topic.save()
frappe.db.commit()
frappe.msgprint(_('{0} {1} has been added to all the selected topics successfully.').format(content_type, frappe.bold(content)),
- title=_('Topics updated'), indicator='green')
\ No newline at end of file
+ title=_('Topics updated'), indicator='green')
diff --git a/erpnext/education/report/program_wise_fee_collection/program_wise_fee_collection.py b/erpnext/education/report/program_wise_fee_collection/program_wise_fee_collection.py
index c145359129..c0ec0357cc 100644
--- a/erpnext/education/report/program_wise_fee_collection/program_wise_fee_collection.py
+++ b/erpnext/education/report/program_wise_fee_collection/program_wise_fee_collection.py
@@ -121,4 +121,3 @@ def get_chart_data(data):
},
'type': 'bar'
}
-
diff --git a/erpnext/education/report/student_batch_wise_attendance/student_batch_wise_attendance.js b/erpnext/education/report/student_batch_wise_attendance/student_batch_wise_attendance.js
index ad04356201..9f1fcbc816 100644
--- a/erpnext/education/report/student_batch_wise_attendance/student_batch_wise_attendance.js
+++ b/erpnext/education/report/student_batch_wise_attendance/student_batch_wise_attendance.js
@@ -9,4 +9,4 @@ frappe.query_reports["Student Batch-Wise Attendance"] = {
"default": frappe.datetime.get_today(),
"reqd": 1
}]
-}
\ No newline at end of file
+}
diff --git a/erpnext/education/report/student_batch_wise_attendance/student_batch_wise_attendance.py b/erpnext/education/report/student_batch_wise_attendance/student_batch_wise_attendance.py
index 7793dcf395..e2576a0c71 100644
--- a/erpnext/education/report/student_batch_wise_attendance/student_batch_wise_attendance.py
+++ b/erpnext/education/report/student_batch_wise_attendance/student_batch_wise_attendance.py
@@ -67,4 +67,4 @@ def get_student_attendance(student_group, date):
student_group= %s and date= %s and docstatus = 1 and
(course_schedule is Null or course_schedule='') group by status""",
(student_group, date), as_dict=1)
- return student_attendance
\ No newline at end of file
+ return student_attendance
diff --git a/erpnext/education/report/student_monthly_attendance_sheet/student_monthly_attendance_sheet.js b/erpnext/education/report/student_monthly_attendance_sheet/student_monthly_attendance_sheet.js
index 104d3ec06f..62c94557d7 100644
--- a/erpnext/education/report/student_monthly_attendance_sheet/student_monthly_attendance_sheet.js
+++ b/erpnext/education/report/student_monthly_attendance_sheet/student_monthly_attendance_sheet.js
@@ -39,4 +39,4 @@ frappe.query_reports["Student Monthly Attendance Sheet"] = {
}
});
}
-}
\ No newline at end of file
+}
diff --git a/erpnext/education/web_form/student_applicant/student_applicant.js b/erpnext/education/web_form/student_applicant/student_applicant.js
index 699703c579..ffc5e98425 100644
--- a/erpnext/education/web_form/student_applicant/student_applicant.js
+++ b/erpnext/education/web_form/student_applicant/student_applicant.js
@@ -1,3 +1,3 @@
frappe.ready(function() {
// bind events here
-})
\ No newline at end of file
+})
diff --git a/erpnext/erpnext_integrations/doctype/amazon_mws_settings/amazon_mws_settings.js b/erpnext/erpnext_integrations/doctype/amazon_mws_settings/amazon_mws_settings.js
index a9925adee7..f5ea8047c6 100644
--- a/erpnext/erpnext_integrations/doctype/amazon_mws_settings/amazon_mws_settings.js
+++ b/erpnext/erpnext_integrations/doctype/amazon_mws_settings/amazon_mws_settings.js
@@ -1,3 +1,2 @@
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
-
diff --git a/erpnext/erpnext_integrations/doctype/amazon_mws_settings/xml_utils.py b/erpnext/erpnext_integrations/doctype/amazon_mws_settings/xml_utils.py
index a25a29f9e5..99ede8f31d 100644
--- a/erpnext/erpnext_integrations/doctype/amazon_mws_settings/xml_utils.py
+++ b/erpnext/erpnext_integrations/doctype/amazon_mws_settings/xml_utils.py
@@ -103,4 +103,4 @@ class xml2dict(object):
"""parse a string"""
t = ET.fromstring(s)
root_tag, root_tree = self._namespace_split(t.tag, self._parse_node(t))
- return object_dict({root_tag: root_tree})
\ No newline at end of file
+ return object_dict({root_tag: root_tree})
diff --git a/erpnext/erpnext_integrations/doctype/exotel_settings/exotel_settings.py b/erpnext/erpnext_integrations/doctype/exotel_settings/exotel_settings.py
index 6a846efad7..bff928c1c9 100644
--- a/erpnext/erpnext_integrations/doctype/exotel_settings/exotel_settings.py
+++ b/erpnext/erpnext_integrations/doctype/exotel_settings/exotel_settings.py
@@ -17,4 +17,4 @@ class ExotelSettings(Document):
response = requests.get('https://api.exotel.com/v1/Accounts/{sid}'
.format(sid = self.account_sid), auth=(self.api_key, self.api_token))
if response.status_code != 200:
- frappe.throw(_("Invalid credentials"))
\ No newline at end of file
+ frappe.throw(_("Invalid credentials"))
diff --git a/erpnext/erpnext_integrations/doctype/mpesa_settings/account_balance.html b/erpnext/erpnext_integrations/doctype/mpesa_settings/account_balance.html
index 2c4d4bbdec..b74a7187f0 100644
--- a/erpnext/erpnext_integrations/doctype/mpesa_settings/account_balance.html
+++ b/erpnext/erpnext_integrations/doctype/mpesa_settings/account_balance.html
@@ -25,4 +25,4 @@
{% else %}
Account Balance Information Not Available.
-{% endif %}
\ No newline at end of file
+{% endif %}
diff --git a/erpnext/erpnext_integrations/doctype/mpesa_settings/mpesa_connector.py b/erpnext/erpnext_integrations/doctype/mpesa_settings/mpesa_connector.py
index 554c6b0eb0..d1adeeee07 100644
--- a/erpnext/erpnext_integrations/doctype/mpesa_settings/mpesa_connector.py
+++ b/erpnext/erpnext_integrations/doctype/mpesa_settings/mpesa_connector.py
@@ -115,4 +115,4 @@ class MpesaConnector():
saf_url = "{0}{1}".format(self.base_url, "/mpesa/stkpush/v1/processrequest")
r = requests.post(saf_url, headers=headers, json=payload)
- return r.json()
\ No newline at end of file
+ return r.json()
diff --git a/erpnext/erpnext_integrations/doctype/mpesa_settings/mpesa_custom_fields.py b/erpnext/erpnext_integrations/doctype/mpesa_settings/mpesa_custom_fields.py
index 0499e88b5e..139e2fb192 100644
--- a/erpnext/erpnext_integrations/doctype/mpesa_settings/mpesa_custom_fields.py
+++ b/erpnext/erpnext_integrations/doctype/mpesa_settings/mpesa_custom_fields.py
@@ -50,4 +50,4 @@ def create_pos_settings(record_dict):
for record in record_dict:
if frappe.db.exists("POS Field", {"fieldname": record.get("fieldname")}):
continue
- frappe.get_doc(record).insert()
\ No newline at end of file
+ frappe.get_doc(record).insert()
diff --git a/erpnext/erpnext_integrations/doctype/mpesa_settings/mpesa_settings.py b/erpnext/erpnext_integrations/doctype/mpesa_settings/mpesa_settings.py
index fdfaa1b054..de93357861 100644
--- a/erpnext/erpnext_integrations/doctype/mpesa_settings/mpesa_settings.py
+++ b/erpnext/erpnext_integrations/doctype/mpesa_settings/mpesa_settings.py
@@ -276,4 +276,4 @@ def fetch_param_value(response, key, key_field):
"""Fetch the specified key from list of dictionary. Key is identified via the key field."""
for param in response:
if param[key_field] == key:
- return param["Value"]
\ No newline at end of file
+ return param["Value"]
diff --git a/erpnext/erpnext_integrations/doctype/mpesa_settings/test_mpesa_settings.py b/erpnext/erpnext_integrations/doctype/mpesa_settings/test_mpesa_settings.py
index b0e662d3f3..d4cb6b982b 100644
--- a/erpnext/erpnext_integrations/doctype/mpesa_settings/test_mpesa_settings.py
+++ b/erpnext/erpnext_integrations/doctype/mpesa_settings/test_mpesa_settings.py
@@ -355,4 +355,4 @@ def get_account_balance_callback_payload():
}
}
}
- }
\ No newline at end of file
+ }
diff --git a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_connector.py b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_connector.py
index 42d4b9b2b4..73f5927df4 100644
--- a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_connector.py
+++ b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_connector.py
@@ -50,7 +50,7 @@ class PlaidConnector():
"secret": self.settings.plaid_secret,
"products": self.products,
})
-
+
return args
def get_link_token(self, update_mode=False):
diff --git a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.js b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.js
index 37bf282450..3740d04983 100644
--- a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.js
+++ b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.js
@@ -135,4 +135,4 @@ erpnext.integrations.plaidLink = class plaidLink {
});
}, __("Select a company"), __("Continue"));
}
-};
\ No newline at end of file
+};
diff --git a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py
index 3ef069b5e2..eddcb3401f 100644
--- a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py
+++ b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py
@@ -110,7 +110,7 @@ def add_bank_accounts(response, bank, company):
frappe.msgprint(_("Bank account {0} already exists and could not be created again").format(account["name"]))
except Exception:
frappe.log_error(frappe.get_traceback(), title=_("Plaid Link Error"))
- frappe.throw(_("There was an error creating Bank Account while linking with Plaid."),
+ frappe.throw(_("There was an error creating Bank Account while linking with Plaid."),
title=_("Plaid Link Failed"))
else:
diff --git a/erpnext/erpnext_integrations/doctype/tally_migration/tally_migration.js b/erpnext/erpnext_integrations/doctype/tally_migration/tally_migration.js
index 5482b9cc69..af06b3451e 100644
--- a/erpnext/erpnext_integrations/doctype/tally_migration/tally_migration.js
+++ b/erpnext/erpnext_integrations/doctype/tally_migration/tally_migration.js
@@ -346,4 +346,4 @@ erpnext.tally_migration.get_html_rows = (logs, field) => {
}).join("");
return rows
-}
\ No newline at end of file
+}
diff --git a/erpnext/erpnext_integrations/doctype/woocommerce_settings/woocommerce_settings.py b/erpnext/erpnext_integrations/doctype/woocommerce_settings/woocommerce_settings.py
index bd072f40a1..45f261007f 100644
--- a/erpnext/erpnext_integrations/doctype/woocommerce_settings/woocommerce_settings.py
+++ b/erpnext/erpnext_integrations/doctype/woocommerce_settings/woocommerce_settings.py
@@ -27,7 +27,7 @@ class WoocommerceSettings(Document):
for doctype in ["Customer", "Address"]:
df = dict(fieldname='woocommerce_email', label='Woocommerce Email', fieldtype='Data', read_only=1, print_hide=1)
create_custom_field(doctype, df)
-
+
if not frappe.get_value("Item Group", {"name": _("WooCommerce Products")}):
item_group = frappe.new_doc("Item Group")
item_group.item_group_name = _("WooCommerce Products")
@@ -74,4 +74,4 @@ def generate_secret():
def get_series():
return {
"sales_order_series" : frappe.get_meta("Sales Order").get_options("naming_series") or "SO-WOO-",
- }
\ No newline at end of file
+ }
diff --git a/erpnext/erpnext_integrations/stripe_integration.py b/erpnext/erpnext_integrations/stripe_integration.py
index a35ca28e0a..108b4c0dd8 100644
--- a/erpnext/erpnext_integrations/stripe_integration.py
+++ b/erpnext/erpnext_integrations/stripe_integration.py
@@ -50,4 +50,4 @@ def create_subscription_on_stripe(stripe_settings):
stripe_settings.integration_request.db_set('status', 'Failed', update_modified=False)
frappe.log_error(frappe.get_traceback())
- return stripe_settings.finalize_request()
\ No newline at end of file
+ return stripe_settings.finalize_request()
diff --git a/erpnext/erpnext_integrations/utils.py b/erpnext/erpnext_integrations/utils.py
index a5e162f8b5..caafc0821e 100644
--- a/erpnext/erpnext_integrations/utils.py
+++ b/erpnext/erpnext_integrations/utils.py
@@ -52,7 +52,7 @@ def create_mode_of_payment(gateway, payment_type="General"):
"payment_gateway": gateway
}, ['payment_account'])
- mode_of_payment = frappe.db.exists("Mode of Payment", gateway)
+ mode_of_payment = frappe.db.exists("Mode of Payment", gateway)
if not mode_of_payment and payment_gateway_account:
mode_of_payment = frappe.get_doc({
"doctype": "Mode of Payment",
diff --git a/erpnext/healthcare/dashboard_chart_source/department_wise_patient_appointments/department_wise_patient_appointments.js b/erpnext/healthcare/dashboard_chart_source/department_wise_patient_appointments/department_wise_patient_appointments.js
index dd6dc666d2..e494489d21 100644
--- a/erpnext/healthcare/dashboard_chart_source/department_wise_patient_appointments/department_wise_patient_appointments.js
+++ b/erpnext/healthcare/dashboard_chart_source/department_wise_patient_appointments/department_wise_patient_appointments.js
@@ -11,4 +11,4 @@ frappe.dashboards.chart_sources["Department wise Patient Appointments"] = {
default: frappe.defaults.get_user_default("Company")
}
]
-};
\ No newline at end of file
+};
diff --git a/erpnext/healthcare/dashboard_chart_source/department_wise_patient_appointments/department_wise_patient_appointments.py b/erpnext/healthcare/dashboard_chart_source/department_wise_patient_appointments/department_wise_patient_appointments.py
index 062da6e465..eca7143e68 100644
--- a/erpnext/healthcare/dashboard_chart_source/department_wise_patient_appointments/department_wise_patient_appointments.py
+++ b/erpnext/healthcare/dashboard_chart_source/department_wise_patient_appointments/department_wise_patient_appointments.py
@@ -69,4 +69,4 @@ def get(chart_name = None, chart = None, no_cache = None, filters = None, from_d
}
],
'type': 'bar'
- }
\ No newline at end of file
+ }
diff --git a/erpnext/healthcare/doctype/appointment_type/appointment_type.js b/erpnext/healthcare/doctype/appointment_type/appointment_type.js
index 861675acea..99b7cb295a 100644
--- a/erpnext/healthcare/doctype/appointment_type/appointment_type.js
+++ b/erpnext/healthcare/doctype/appointment_type/appointment_type.js
@@ -80,4 +80,4 @@ frappe.ui.form.on('Appointment Type Service Item', {
});
}
}
-});
\ No newline at end of file
+});
diff --git a/erpnext/healthcare/doctype/clinical_procedure/test_clinical_procedure.py b/erpnext/healthcare/doctype/clinical_procedure/test_clinical_procedure.py
index 03e96a4b3b..81a3982c4b 100644
--- a/erpnext/healthcare/doctype/clinical_procedure/test_clinical_procedure.py
+++ b/erpnext/healthcare/doctype/clinical_procedure/test_clinical_procedure.py
@@ -63,4 +63,4 @@ def create_procedure(procedure_template, patient, practitioner):
procedure.company = "_Test Company"
procedure.warehouse = "_Test Warehouse - _TC"
procedure.submit()
- return procedure
\ No newline at end of file
+ return procedure
diff --git a/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template.js b/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template.js
index 1ef110dc6f..ae6b39bb18 100644
--- a/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template.js
+++ b/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template.js
@@ -188,4 +188,3 @@ frappe.tour['Clinical Procedure Template'] = [
description: __('You can also set the Medical Department for the template. After saving the document, an Item will automatically be created for billing this Clinical Procedure. You can then use this template while creating Clinical Procedures for Patients. Templates save you from filling up redundant data every single time. You can also create templates for other operations like Lab Tests, Therapy Sessions, etc.')
}
];
-
diff --git a/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template.py b/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template.py
index f32b7cf9d8..58194f10a8 100644
--- a/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template.py
+++ b/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template.py
@@ -118,4 +118,3 @@ def change_item_code_from_template(item_code, doc):
rename_doc('Item', doc.item_code, item_code, ignore_permissions=True)
frappe.db.set_value('Clinical Procedure Template', doc.name, 'item_code', item_code)
return
-
diff --git a/erpnext/healthcare/doctype/exercise_type/exercise_type.py b/erpnext/healthcare/doctype/exercise_type/exercise_type.py
index fb635c8578..ae44a2b77b 100644
--- a/erpnext/healthcare/doctype/exercise_type/exercise_type.py
+++ b/erpnext/healthcare/doctype/exercise_type/exercise_type.py
@@ -12,4 +12,3 @@ class ExerciseType(Document):
self.name = ' - '.join(filter(None, [self.exercise_name, self.difficulty_level]))
else:
self.name = self.exercise_name
-
diff --git a/erpnext/healthcare/doctype/fee_validity/fee_validity.py b/erpnext/healthcare/doctype/fee_validity/fee_validity.py
index 058bc97192..5b9c17934f 100644
--- a/erpnext/healthcare/doctype/fee_validity/fee_validity.py
+++ b/erpnext/healthcare/doctype/fee_validity/fee_validity.py
@@ -60,4 +60,4 @@ def check_is_new_patient(appointment):
})
if len(appointment_exists) and appointment_exists[0]:
return False
- return True
\ No newline at end of file
+ return True
diff --git a/erpnext/healthcare/doctype/fee_validity/test_fee_validity.py b/erpnext/healthcare/doctype/fee_validity/test_fee_validity.py
index 7e7fd82411..6ae3e12d50 100644
--- a/erpnext/healthcare/doctype/fee_validity/test_fee_validity.py
+++ b/erpnext/healthcare/doctype/fee_validity/test_fee_validity.py
@@ -47,4 +47,4 @@ class TestFeeValidity(unittest.TestCase):
# appointment should be invoiced as it is not within fee validity and the max_visits are exceeded
appointment = create_appointment(patient, practitioner, add_days(nowdate(), 10), invoice=1)
invoiced = frappe.db.get_value("Patient Appointment", appointment.name, "invoiced")
- self.assertEqual(invoiced, 1)
\ No newline at end of file
+ self.assertEqual(invoiced, 1)
diff --git a/erpnext/healthcare/doctype/healthcare_practitioner/healthcare_practitioner.js b/erpnext/healthcare/doctype/healthcare_practitioner/healthcare_practitioner.js
index fc0b24122a..44c399856c 100644
--- a/erpnext/healthcare/doctype/healthcare_practitioner/healthcare_practitioner.js
+++ b/erpnext/healthcare/doctype/healthcare_practitioner/healthcare_practitioner.js
@@ -142,4 +142,3 @@ frappe.tour['Healthcare Practitioner'] = [
description: __('If this Healthcare Practitioner also works for the In-Patient Department, set the inpatient visit charge for this Practitioner.')
}
];
-
diff --git a/erpnext/healthcare/doctype/healthcare_service_unit_type/test_healthcare_service_unit_type.py b/erpnext/healthcare/doctype/healthcare_service_unit_type/test_healthcare_service_unit_type.py
index 01cf4b0a49..3ee3377b00 100644
--- a/erpnext/healthcare/doctype/healthcare_service_unit_type/test_healthcare_service_unit_type.py
+++ b/erpnext/healthcare/doctype/healthcare_service_unit_type/test_healthcare_service_unit_type.py
@@ -30,4 +30,4 @@ def get_unit_type():
unit_type.no_of_hours = 1
unit_type.rate = 4000
unit_type.save()
- return unit_type
\ No newline at end of file
+ return unit_type
diff --git a/erpnext/healthcare/doctype/inpatient_medication_entry/test_inpatient_medication_entry.py b/erpnext/healthcare/doctype/inpatient_medication_entry/test_inpatient_medication_entry.py
index 7cb5a4814e..ff9e21252a 100644
--- a/erpnext/healthcare/doctype/inpatient_medication_entry/test_inpatient_medication_entry.py
+++ b/erpnext/healthcare/doctype/inpatient_medication_entry/test_inpatient_medication_entry.py
@@ -153,4 +153,4 @@ def make_stock_entry(warehouse=None):
# in stock uom
se_child.conversion_factor = 1.0
se_child.expense_account = expense_account
- stock_entry.submit()
\ No newline at end of file
+ stock_entry.submit()
diff --git a/erpnext/healthcare/doctype/inpatient_medication_order/test_inpatient_medication_order.py b/erpnext/healthcare/doctype/inpatient_medication_order/test_inpatient_medication_order.py
index 21776d2380..798976283b 100644
--- a/erpnext/healthcare/doctype/inpatient_medication_order/test_inpatient_medication_order.py
+++ b/erpnext/healthcare/doctype/inpatient_medication_order/test_inpatient_medication_order.py
@@ -140,4 +140,3 @@ def create_ipme(filters, update_stock=0):
ipme = ipme.get_medication_orders()
return ipme
-
diff --git a/erpnext/healthcare/doctype/patient_appointment/test_patient_appointment.py b/erpnext/healthcare/doctype/patient_appointment/test_patient_appointment.py
index 5f2dc480a1..9dd4a2c73c 100644
--- a/erpnext/healthcare/doctype/patient_appointment/test_patient_appointment.py
+++ b/erpnext/healthcare/doctype/patient_appointment/test_patient_appointment.py
@@ -295,4 +295,4 @@ def create_appointment_type(args=None):
'color': args.get('color') or '#7575ff',
'price_list': args.get('price_list') or frappe.db.get_value("Price List", {"selling": 1}),
'items': args.get('items') or items
- }).insert()
\ No newline at end of file
+ }).insert()
diff --git a/erpnext/healthcare/doctype/patient_assessment/patient_assessment.py b/erpnext/healthcare/doctype/patient_assessment/patient_assessment.py
index 3033a3e6ac..7bad20dffd 100644
--- a/erpnext/healthcare/doctype/patient_assessment/patient_assessment.py
+++ b/erpnext/healthcare/doctype/patient_assessment/patient_assessment.py
@@ -31,6 +31,3 @@ def create_patient_assessment(source_name, target_doc=None):
}, target_doc)
return doc
-
-
-
diff --git a/erpnext/healthcare/doctype/patient_encounter/patient_encounter.py b/erpnext/healthcare/doctype/patient_encounter/patient_encounter.py
index cc2141790f..2b3029efde 100644
--- a/erpnext/healthcare/doctype/patient_encounter/patient_encounter.py
+++ b/erpnext/healthcare/doctype/patient_encounter/patient_encounter.py
@@ -99,4 +99,4 @@ def create_therapy_plan(encounter):
def delete_ip_medication_order(encounter):
record = frappe.db.exists('Inpatient Medication Order', {'patient_encounter': encounter.name})
if record:
- frappe.delete_doc('Inpatient Medication Order', record, force=1)
\ No newline at end of file
+ frappe.delete_doc('Inpatient Medication Order', record, force=1)
diff --git a/erpnext/healthcare/doctype/patient_history_settings/patient_history_settings.py b/erpnext/healthcare/doctype/patient_history_settings/patient_history_settings.py
index 887d58a2e0..63b00859d7 100644
--- a/erpnext/healthcare/doctype/patient_history_settings/patient_history_settings.py
+++ b/erpnext/healthcare/doctype/patient_history_settings/patient_history_settings.py
@@ -187,4 +187,4 @@ def get_module(doc):
if not module:
module = frappe.db.get_value('DocType', doc.doctype, 'module')
- return module
\ No newline at end of file
+ return module
diff --git a/erpnext/healthcare/doctype/patient_medical_record/test_patient_medical_record.py b/erpnext/healthcare/doctype/patient_medical_record/test_patient_medical_record.py
index c1d9872a01..f8ccc8a002 100644
--- a/erpnext/healthcare/doctype/patient_medical_record/test_patient_medical_record.py
+++ b/erpnext/healthcare/doctype/patient_medical_record/test_patient_medical_record.py
@@ -88,4 +88,4 @@ def create_lab_test(template, patient):
lab_test.template = template
lab_test.save()
lab_test.submit()
- return lab_test
\ No newline at end of file
+ return lab_test
diff --git a/erpnext/healthcare/doctype/therapy_plan_template/therapy_plan_template.py b/erpnext/healthcare/doctype/therapy_plan_template/therapy_plan_template.py
index 748c12c689..635d4beb8d 100644
--- a/erpnext/healthcare/doctype/therapy_plan_template/therapy_plan_template.py
+++ b/erpnext/healthcare/doctype/therapy_plan_template/therapy_plan_template.py
@@ -70,4 +70,4 @@ class TherapyPlanTemplate(Document):
item_price.item_name = self.item_name
item_price.price_list_rate = self.total_amount
item_price.ignore_mandatory = True
- item_price.save(ignore_permissions=True)
\ No newline at end of file
+ item_price.save(ignore_permissions=True)
diff --git a/erpnext/healthcare/doctype/therapy_session/therapy_session.js b/erpnext/healthcare/doctype/therapy_session/therapy_session.js
index fd20003693..fbfa774c91 100644
--- a/erpnext/healthcare/doctype/therapy_session/therapy_session.js
+++ b/erpnext/healthcare/doctype/therapy_session/therapy_session.js
@@ -168,4 +168,4 @@ frappe.ui.form.on('Therapy Session', {
});
}
}
-});
\ No newline at end of file
+});
diff --git a/erpnext/healthcare/doctype/therapy_type/test_therapy_type.py b/erpnext/healthcare/doctype/therapy_type/test_therapy_type.py
index 21f6369975..a5dad293e3 100644
--- a/erpnext/healthcare/doctype/therapy_type/test_therapy_type.py
+++ b/erpnext/healthcare/doctype/therapy_type/test_therapy_type.py
@@ -47,4 +47,4 @@ def create_exercise_type():
'description': 'Squat and Rise'
})
exercise_type.save()
- return exercise_type
\ No newline at end of file
+ return exercise_type
diff --git a/erpnext/healthcare/doctype/vital_signs/vital_signs.py b/erpnext/healthcare/doctype/vital_signs/vital_signs.py
index 35c823d739..4bb3940ae0 100644
--- a/erpnext/healthcare/doctype/vital_signs/vital_signs.py
+++ b/erpnext/healthcare/doctype/vital_signs/vital_signs.py
@@ -15,4 +15,3 @@ class VitalSigns(Document):
def set_title(self):
self.title = _('{0} on {1}').format(self.patient_name or self.patient,
frappe.utils.format_date(self.signs_date))[:100]
-
diff --git a/erpnext/healthcare/page/patient_history/patient_history.html b/erpnext/healthcare/page/patient_history/patient_history.html
index be486c62d1..f1706557f4 100644
--- a/erpnext/healthcare/page/patient_history/patient_history.html
+++ b/erpnext/healthcare/page/patient_history/patient_history.html
@@ -23,4 +23,4 @@
More..
-
\ No newline at end of file
+
diff --git a/erpnext/healthcare/page/patient_progress/patient_progress.html b/erpnext/healthcare/page/patient_progress/patient_progress.html
index c20537ea81..30064bd165 100644
--- a/erpnext/healthcare/page/patient_progress/patient_progress.html
+++ b/erpnext/healthcare/page/patient_progress/patient_progress.html
@@ -65,4 +65,4 @@
-
\ No newline at end of file
+
diff --git a/erpnext/healthcare/page/patient_progress/patient_progress.js b/erpnext/healthcare/page/patient_progress/patient_progress.js
index 2410b0ce84..4b7599df29 100644
--- a/erpnext/healthcare/page/patient_progress/patient_progress.js
+++ b/erpnext/healthcare/page/patient_progress/patient_progress.js
@@ -528,4 +528,4 @@ class PatientProgress {
}
$(parent).find('.chart-container').hide();
}
-}
\ No newline at end of file
+}
diff --git a/erpnext/healthcare/page/patient_progress/patient_progress.py b/erpnext/healthcare/page/patient_progress/patient_progress.py
index a04fb2b592..46bfb3db5d 100644
--- a/erpnext/healthcare/page/patient_progress/patient_progress.py
+++ b/erpnext/healthcare/page/patient_progress/patient_progress.py
@@ -194,4 +194,3 @@ def get_date_range(time_span):
return time_span
except json.decoder.JSONDecodeError:
return get_timespan_date_range(time_span.lower())
-
diff --git a/erpnext/healthcare/page/patient_progress/patient_progress_sidebar.html b/erpnext/healthcare/page/patient_progress/patient_progress_sidebar.html
index cd62dd3903..4ee65738ba 100644
--- a/erpnext/healthcare/page/patient_progress/patient_progress_sidebar.html
+++ b/erpnext/healthcare/page/patient_progress/patient_progress_sidebar.html
@@ -26,4 +26,4 @@
{%=__("Therapy Plan") %}
{%=__("Patient History") %}
-
\ No newline at end of file
+
diff --git a/erpnext/healthcare/report/inpatient_medication_orders/inpatient_medication_orders.py b/erpnext/healthcare/report/inpatient_medication_orders/inpatient_medication_orders.py
index b9077301ba..28b60bdcc9 100644
--- a/erpnext/healthcare/report/inpatient_medication_orders/inpatient_medication_orders.py
+++ b/erpnext/healthcare/report/inpatient_medication_orders/inpatient_medication_orders.py
@@ -195,4 +195,4 @@ def get_chart_data(data):
chart["fieldtype"] = "Data"
- return chart
\ No newline at end of file
+ return chart
diff --git a/erpnext/healthcare/report/patient_appointment_analytics/patient_appointment_analytics.py b/erpnext/healthcare/report/patient_appointment_analytics/patient_appointment_analytics.py
index 9c35dbb3ea..9a4840acfe 100644
--- a/erpnext/healthcare/report/patient_appointment_analytics/patient_appointment_analytics.py
+++ b/erpnext/healthcare/report/patient_appointment_analytics/patient_appointment_analytics.py
@@ -191,4 +191,4 @@ class Analytics(object):
'datasets': []
},
"type": "line"
- }
\ No newline at end of file
+ }
diff --git a/erpnext/healthcare/setup.py b/erpnext/healthcare/setup.py
index bf4df7e4c8..891272ddf8 100644
--- a/erpnext/healthcare/setup.py
+++ b/erpnext/healthcare/setup.py
@@ -292,4 +292,4 @@ def get_patient_history_config():
{"label": "Medication Orders", "fieldname": "medication_orders", "fieldtype": "Table"},
{"label": "Total Orders", "fieldname": "total_orders", "fieldtype": "Float"}
])
- }
\ No newline at end of file
+ }
diff --git a/erpnext/healthcare/web_form/patient_registration/patient_registration.js b/erpnext/healthcare/web_form/patient_registration/patient_registration.js
index 7da3f1fb41..f09e540919 100644
--- a/erpnext/healthcare/web_form/patient_registration/patient_registration.js
+++ b/erpnext/healthcare/web_form/patient_registration/patient_registration.js
@@ -1,3 +1,3 @@
frappe.ready(function() {
// bind events here
-});
\ No newline at end of file
+});
diff --git a/erpnext/hotels/doctype/hotel_room/hotel_room.py b/erpnext/hotels/doctype/hotel_room/hotel_room.py
index 8471aee4a0..6a2fc02574 100644
--- a/erpnext/hotels/doctype/hotel_room/hotel_room.py
+++ b/erpnext/hotels/doctype/hotel_room/hotel_room.py
@@ -10,4 +10,4 @@ class HotelRoom(Document):
def validate(self):
if not self.capacity:
self.capacity, self.extra_bed_capacity = frappe.db.get_value('Hotel Room Type',
- self.hotel_room_type, ['capacity', 'extra_bed_capacity'])
\ No newline at end of file
+ self.hotel_room_type, ['capacity', 'extra_bed_capacity'])
diff --git a/erpnext/hotels/doctype/hotel_room_reservation/hotel_room_reservation_calendar.js b/erpnext/hotels/doctype/hotel_room_reservation/hotel_room_reservation_calendar.js
index 7f7322cf4b..7bde292a2b 100644
--- a/erpnext/hotels/doctype/hotel_room_reservation/hotel_room_reservation_calendar.js
+++ b/erpnext/hotels/doctype/hotel_room_reservation/hotel_room_reservation_calendar.js
@@ -6,4 +6,4 @@ frappe.views.calendar["Hotel Room Reservation"] = {
"title": "guest_name",
"status": "status"
}
-}
\ No newline at end of file
+}
diff --git a/erpnext/hotels/report/hotel_room_occupancy/hotel_room_occupancy.py b/erpnext/hotels/report/hotel_room_occupancy/hotel_room_occupancy.py
index f77d43b314..259edb9c06 100644
--- a/erpnext/hotels/report/hotel_room_occupancy/hotel_room_occupancy.py
+++ b/erpnext/hotels/report/hotel_room_occupancy/hotel_room_occupancy.py
@@ -30,4 +30,4 @@ def get_data(filters):
out.append([room_type.name, total_booked])
- return out
\ No newline at end of file
+ return out
diff --git a/erpnext/hr/doctype/appraisal/appraisal.js b/erpnext/hr/doctype/appraisal/appraisal.js
index 1a30ceac6d..50612b923e 100644
--- a/erpnext/hr/doctype/appraisal/appraisal.js
+++ b/erpnext/hr/doctype/appraisal/appraisal.js
@@ -15,7 +15,7 @@ frappe.ui.form.on('Appraisal', {
frm.set_value('status', 'Draft');
}
},
-
+
kra_template: function(frm) {
frm.doc.goals = [];
erpnext.utils.map_current_doc({
diff --git a/erpnext/hr/doctype/appraisal/test_appraisal.js b/erpnext/hr/doctype/appraisal/test_appraisal.js
index 9ca17e2e22..fb1354c3f6 100644
--- a/erpnext/hr/doctype/appraisal/test_appraisal.js
+++ b/erpnext/hr/doctype/appraisal/test_appraisal.js
@@ -55,4 +55,3 @@ QUnit.test("Test: Expense Claim [HR]", function (assert) {
() => done()
]);
});
-
diff --git a/erpnext/hr/doctype/appraisal_goal/appraisal_goal.py b/erpnext/hr/doctype/appraisal_goal/appraisal_goal.py
index a6868ee2b1..11d9f3944d 100644
--- a/erpnext/hr/doctype/appraisal_goal/appraisal_goal.py
+++ b/erpnext/hr/doctype/appraisal_goal/appraisal_goal.py
@@ -7,4 +7,4 @@ import frappe
from frappe.model.document import Document
class AppraisalGoal(Document):
- pass
\ No newline at end of file
+ pass
diff --git a/erpnext/hr/doctype/appraisal_template/appraisal_template_dashboard.py b/erpnext/hr/doctype/appraisal_template/appraisal_template_dashboard.py
index 309427e30c..392b370e6c 100644
--- a/erpnext/hr/doctype/appraisal_template/appraisal_template_dashboard.py
+++ b/erpnext/hr/doctype/appraisal_template/appraisal_template_dashboard.py
@@ -9,4 +9,4 @@ def get_data():
'items': ['Appraisal']
},
],
- }
\ No newline at end of file
+ }
diff --git a/erpnext/hr/doctype/appraisal_template/test_appraisal_template.js b/erpnext/hr/doctype/appraisal_template/test_appraisal_template.js
index 0403cad068..3eb64e0850 100644
--- a/erpnext/hr/doctype/appraisal_template/test_appraisal_template.js
+++ b/erpnext/hr/doctype/appraisal_template/test_appraisal_template.js
@@ -27,4 +27,3 @@ QUnit.test("Test: Appraisal Template [HR]", function (assert) {
() => done()
]);
});
-
diff --git a/erpnext/hr/doctype/appraisal_template_goal/appraisal_template_goal.py b/erpnext/hr/doctype/appraisal_template_goal/appraisal_template_goal.py
index ca58e0c320..b3c5704fa5 100644
--- a/erpnext/hr/doctype/appraisal_template_goal/appraisal_template_goal.py
+++ b/erpnext/hr/doctype/appraisal_template_goal/appraisal_template_goal.py
@@ -7,4 +7,4 @@ import frappe
from frappe.model.document import Document
class AppraisalTemplateGoal(Document):
- pass
\ No newline at end of file
+ pass
diff --git a/erpnext/hr/doctype/attendance/attendance_calendar.js b/erpnext/hr/doctype/attendance/attendance_calendar.js
index 4566489696..d9f6d2eb3e 100644
--- a/erpnext/hr/doctype/attendance/attendance_calendar.js
+++ b/erpnext/hr/doctype/attendance/attendance_calendar.js
@@ -9,4 +9,4 @@ frappe.views.calendar["Attendance"] = {
}
},
get_events_method: "erpnext.hr.doctype.attendance.attendance.get_events"
-};
\ No newline at end of file
+};
diff --git a/erpnext/hr/doctype/attendance/test_attendance.js b/erpnext/hr/doctype/attendance/test_attendance.js
index 8f30e8cc16..b3e7fef02a 100644
--- a/erpnext/hr/doctype/attendance/test_attendance.js
+++ b/erpnext/hr/doctype/attendance/test_attendance.js
@@ -36,4 +36,4 @@ QUnit.test("Test: Attendance [HR]", function (assert) {
"attendance for Present day is marked"),
() => done()
]);
-});
\ No newline at end of file
+});
diff --git a/erpnext/hr/doctype/attendance_request/attendance_request_dashboard.py b/erpnext/hr/doctype/attendance_request/attendance_request_dashboard.py
index cfdd6d3aef..2d3eb00011 100644
--- a/erpnext/hr/doctype/attendance_request/attendance_request_dashboard.py
+++ b/erpnext/hr/doctype/attendance_request/attendance_request_dashboard.py
@@ -8,4 +8,4 @@ def get_data():
'items': ['Attendance']
}
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/hr/doctype/branch/branch.py b/erpnext/hr/doctype/branch/branch.py
index fab2ffc1a3..a847c8e217 100644
--- a/erpnext/hr/doctype/branch/branch.py
+++ b/erpnext/hr/doctype/branch/branch.py
@@ -7,4 +7,4 @@ import frappe
from frappe.model.document import Document
class Branch(Document):
- pass
\ No newline at end of file
+ pass
diff --git a/erpnext/hr/doctype/branch/test_branch.js b/erpnext/hr/doctype/branch/test_branch.js
index c315385f11..82a6ae103e 100644
--- a/erpnext/hr/doctype/branch/test_branch.js
+++ b/erpnext/hr/doctype/branch/test_branch.js
@@ -20,4 +20,4 @@ QUnit.test("Test: Branch [HR]", function (assert) {
'name of branch correctly saved'),
() => done()
]);
-});
\ No newline at end of file
+});
diff --git a/erpnext/hr/doctype/branch/test_branch.py b/erpnext/hr/doctype/branch/test_branch.py
index 5ba02b36b8..807698ba0a 100644
--- a/erpnext/hr/doctype/branch/test_branch.py
+++ b/erpnext/hr/doctype/branch/test_branch.py
@@ -4,4 +4,4 @@ from __future__ import unicode_literals
import frappe
-test_records = frappe.get_test_records('Branch')
\ No newline at end of file
+test_records = frappe.get_test_records('Branch')
diff --git a/erpnext/hr/doctype/daily_work_summary/test_daily_work_summary.js b/erpnext/hr/doctype/daily_work_summary/test_daily_work_summary.js
index d2ceb8bd52..1533517147 100644
--- a/erpnext/hr/doctype/daily_work_summary/test_daily_work_summary.js
+++ b/erpnext/hr/doctype/daily_work_summary/test_daily_work_summary.js
@@ -20,4 +20,4 @@ QUnit.test("test: Daily Work Summary", function (assert) {
() => done()
]);
-});
\ No newline at end of file
+});
diff --git a/erpnext/hr/doctype/department/department_tree.js b/erpnext/hr/doctype/department/department_tree.js
index 52d864bc0e..5c7726de6a 100644
--- a/erpnext/hr/doctype/department/department_tree.js
+++ b/erpnext/hr/doctype/department/department_tree.js
@@ -25,4 +25,4 @@ frappe.treeview_settings["Department"] = {
onload: function(treeview) {
treeview.make_tree();
}
-};
\ No newline at end of file
+};
diff --git a/erpnext/hr/doctype/department/test_department.js b/erpnext/hr/doctype/department/test_department.js
index 3a571f7653..e73779c97c 100644
--- a/erpnext/hr/doctype/department/test_department.js
+++ b/erpnext/hr/doctype/department/test_department.js
@@ -20,4 +20,4 @@ QUnit.test("Test: Department [HR]", function (assert) {
'name of department correctly saved'),
() => done()
]);
-});
\ No newline at end of file
+});
diff --git a/erpnext/hr/doctype/department/test_department.py b/erpnext/hr/doctype/department/test_department.py
index 2eeca26e30..e4f6645ee4 100644
--- a/erpnext/hr/doctype/department/test_department.py
+++ b/erpnext/hr/doctype/department/test_department.py
@@ -21,4 +21,4 @@ def create_department(department_name, parent_department=None):
return doc
-test_records = frappe.get_test_records('Department')
\ No newline at end of file
+test_records = frappe.get_test_records('Department')
diff --git a/erpnext/hr/doctype/designation/designation.py b/erpnext/hr/doctype/designation/designation.py
index efd864ad59..a3f84aab5f 100644
--- a/erpnext/hr/doctype/designation/designation.py
+++ b/erpnext/hr/doctype/designation/designation.py
@@ -7,4 +7,4 @@ import frappe
from frappe.model.document import Document
class Designation(Document):
- pass
\ No newline at end of file
+ pass
diff --git a/erpnext/hr/doctype/designation/test_designation.js b/erpnext/hr/doctype/designation/test_designation.js
index 45c3417191..00adf8293f 100644
--- a/erpnext/hr/doctype/designation/test_designation.js
+++ b/erpnext/hr/doctype/designation/test_designation.js
@@ -20,4 +20,4 @@ QUnit.test("Test: Designation [HR]", function (assert) {
'name of designation correctly saved'),
() => done()
]);
-});
\ No newline at end of file
+});
diff --git a/erpnext/hr/doctype/designation/test_designation.py b/erpnext/hr/doctype/designation/test_designation.py
index 3b300941a6..2778862a1c 100644
--- a/erpnext/hr/doctype/designation/test_designation.py
+++ b/erpnext/hr/doctype/designation/test_designation.py
@@ -17,4 +17,4 @@ def create_designation(**args):
"description": args.description or "_Test description"
})
designation.save()
- return designation
\ No newline at end of file
+ return designation
diff --git a/erpnext/hr/doctype/employee/employee.py b/erpnext/hr/doctype/employee/employee.py
index 5ca47560b1..f4280152c5 100755
--- a/erpnext/hr/doctype/employee/employee.py
+++ b/erpnext/hr/doctype/employee/employee.py
@@ -520,4 +520,4 @@ def has_upload_permission(doc, ptype='read', user=None):
user = frappe.session.user
if get_doc_permissions(doc, user=user, ptype=ptype).get(ptype):
return True
- return doc.user_id == user
\ No newline at end of file
+ return doc.user_id == user
diff --git a/erpnext/hr/doctype/employee/employee_tree.js b/erpnext/hr/doctype/employee/employee_tree.js
index 9ab091a1eb..7d6a70013d 100644
--- a/erpnext/hr/doctype/employee/employee_tree.js
+++ b/erpnext/hr/doctype/employee/employee_tree.js
@@ -33,4 +33,4 @@ frappe.treeview_settings['Employee'] = {
condition: 'frappe.boot.user.can_create.indexOf("Employee") !== -1'
}
],
-};
\ No newline at end of file
+};
diff --git a/erpnext/hr/doctype/employee/test_employee.js b/erpnext/hr/doctype/employee/test_employee.js
index 200dcd7966..3a41458480 100644
--- a/erpnext/hr/doctype/employee/test_employee.js
+++ b/erpnext/hr/doctype/employee/test_employee.js
@@ -37,4 +37,4 @@ QUnit.test("Test: Employee [HR]", function (assert) {
() => frappe.timeout(10),
() => done()
]);
-});
\ No newline at end of file
+});
diff --git a/erpnext/hr/doctype/employee_advance/test_employee_advance.py b/erpnext/hr/doctype/employee_advance/test_employee_advance.py
index c88b2b8e49..100968bb7a 100644
--- a/erpnext/hr/doctype/employee_advance/test_employee_advance.py
+++ b/erpnext/hr/doctype/employee_advance/test_employee_advance.py
@@ -48,4 +48,4 @@ def make_employee_advance(employee_name):
doc.insert()
doc.submit()
- return doc
\ No newline at end of file
+ return doc
diff --git a/erpnext/hr/doctype/employee_attendance_tool/employee_attendance_tool.css b/erpnext/hr/doctype/employee_attendance_tool/employee_attendance_tool.css
index d25fb2247e..c8d6644b2f 100644
--- a/erpnext/hr/doctype/employee_attendance_tool/employee_attendance_tool.css
+++ b/erpnext/hr/doctype/employee_attendance_tool/employee_attendance_tool.css
@@ -18,4 +18,4 @@
.checkbox{
margin-top: -3px;
-}
\ No newline at end of file
+}
diff --git a/erpnext/hr/doctype/employee_attendance_tool/employee_attendance_tool.js b/erpnext/hr/doctype/employee_attendance_tool/employee_attendance_tool.js
index ab965d54e3..5ae8c6bd03 100644
--- a/erpnext/hr/doctype/employee_attendance_tool/employee_attendance_tool.js
+++ b/erpnext/hr/doctype/employee_attendance_tool/employee_attendance_tool.js
@@ -267,5 +267,3 @@ erpnext.EmployeeSelector = class EmployeeSelector {
mark_employee_toolbar.appendTo($(this.wrapper));
}
};
-
-
diff --git a/erpnext/hr/doctype/employee_attendance_tool/test_employee_attendance_tool.js b/erpnext/hr/doctype/employee_attendance_tool/test_employee_attendance_tool.js
index 2827d4ba28..48d4344df2 100644
--- a/erpnext/hr/doctype/employee_attendance_tool/test_employee_attendance_tool.js
+++ b/erpnext/hr/doctype/employee_attendance_tool/test_employee_attendance_tool.js
@@ -58,4 +58,4 @@ QUnit.test("Test: Employee attendance tool [HR]", function (assert) {
},
() => done()
]);
-});
\ No newline at end of file
+});
diff --git a/erpnext/hr/doctype/employee_checkin/employee_checkin.py b/erpnext/hr/doctype/employee_checkin/employee_checkin.py
index 60ea0f9895..6c0cd4f963 100644
--- a/erpnext/hr/doctype/employee_checkin/employee_checkin.py
+++ b/erpnext/hr/doctype/employee_checkin/employee_checkin.py
@@ -176,4 +176,3 @@ def time_diff_in_hours(start, end):
def find_index_in_dict(dict_list, key, value):
return next((index for (index, d) in enumerate(dict_list) if d[key] == value), None)
-
diff --git a/erpnext/hr/doctype/employee_checkin/test_employee_checkin.py b/erpnext/hr/doctype/employee_checkin/test_employee_checkin.py
index 9f12ef24e6..7ba511f08d 100644
--- a/erpnext/hr/doctype/employee_checkin/test_employee_checkin.py
+++ b/erpnext/hr/doctype/employee_checkin/test_employee_checkin.py
@@ -42,11 +42,11 @@ class TestEmployeeCheckin(unittest.TestCase):
self.assertEqual(logs_count, 4)
attendance_count = frappe.db.count('Attendance', {'status':'Present', 'working_hours':8.2,
'employee':employee, 'attendance_date':now_date})
- self.assertEqual(attendance_count, 1)
+ self.assertEqual(attendance_count, 1)
def test_calculate_working_hours(self):
check_in_out_type = ['Alternating entries as IN and OUT during the same shift',
- 'Strictly based on Log Type in Employee Checkin']
+ 'Strictly based on Log Type in Employee Checkin']
working_hours_calc_type = ['First Check-in and Last Check-out',
'Every Valid Check-in and Check-out']
logs_type_1 = [
diff --git a/erpnext/hr/doctype/employee_education/employee_education.py b/erpnext/hr/doctype/employee_education/employee_education.py
index a1d449291c..f0a76172b2 100644
--- a/erpnext/hr/doctype/employee_education/employee_education.py
+++ b/erpnext/hr/doctype/employee_education/employee_education.py
@@ -7,4 +7,4 @@ import frappe
from frappe.model.document import Document
class EmployeeEducation(Document):
- pass
\ No newline at end of file
+ pass
diff --git a/erpnext/hr/doctype/employee_external_work_history/employee_external_work_history.py b/erpnext/hr/doctype/employee_external_work_history/employee_external_work_history.py
index c7166309f3..517ef57be8 100644
--- a/erpnext/hr/doctype/employee_external_work_history/employee_external_work_history.py
+++ b/erpnext/hr/doctype/employee_external_work_history/employee_external_work_history.py
@@ -7,4 +7,4 @@ import frappe
from frappe.model.document import Document
class EmployeeExternalWorkHistory(Document):
- pass
\ No newline at end of file
+ pass
diff --git a/erpnext/hr/doctype/employee_grade/employee_grade_dashboard.py b/erpnext/hr/doctype/employee_grade/employee_grade_dashboard.py
index f2656e9a2b..df67910418 100644
--- a/erpnext/hr/doctype/employee_grade/employee_grade_dashboard.py
+++ b/erpnext/hr/doctype/employee_grade/employee_grade_dashboard.py
@@ -10,4 +10,4 @@ def get_data():
'items': ['Employee Onboarding Template', 'Employee Separation Template']
}
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/hr/doctype/employee_grievance/employee_grievance.py b/erpnext/hr/doctype/employee_grievance/employee_grievance.py
index 503b5ea444..17055829ef 100644
--- a/erpnext/hr/doctype/employee_grievance/employee_grievance.py
+++ b/erpnext/hr/doctype/employee_grievance/employee_grievance.py
@@ -12,4 +12,3 @@ class EmployeeGrievance(Document):
bold("Invalid"),
bold("Resolved"))
)
-
diff --git a/erpnext/hr/doctype/employee_grievance/employee_grievance_list.js b/erpnext/hr/doctype/employee_grievance/employee_grievance_list.js
index fc08e21609..11672ca4e0 100644
--- a/erpnext/hr/doctype/employee_grievance/employee_grievance_list.js
+++ b/erpnext/hr/doctype/employee_grievance/employee_grievance_list.js
@@ -9,4 +9,4 @@ frappe.listview_settings["Employee Grievance"] = {
};
return [__(doc.status), colors[doc.status], "status,=," + doc.status];
}
-};
\ No newline at end of file
+};
diff --git a/erpnext/hr/doctype/employee_grievance/test_employee_grievance.py b/erpnext/hr/doctype/employee_grievance/test_employee_grievance.py
index a615b20a5a..ed897ee103 100644
--- a/erpnext/hr/doctype/employee_grievance/test_employee_grievance.py
+++ b/erpnext/hr/doctype/employee_grievance/test_employee_grievance.py
@@ -48,4 +48,3 @@ def create_grievance_type():
grievance_type.save()
return grievance_type.name
-
diff --git a/erpnext/hr/doctype/employee_group/test_employee_group.py b/erpnext/hr/doctype/employee_group/test_employee_group.py
index 3a6bf8594b..26a61c407b 100644
--- a/erpnext/hr/doctype/employee_group/test_employee_group.py
+++ b/erpnext/hr/doctype/employee_group/test_employee_group.py
@@ -29,4 +29,4 @@ def make_employee_group():
def get_employee_group():
employee_group = frappe.db.exists("Employee Group", "_Test Employee Group")
- return employee_group
\ No newline at end of file
+ return employee_group
diff --git a/erpnext/hr/doctype/employee_internal_work_history/employee_internal_work_history.py b/erpnext/hr/doctype/employee_internal_work_history/employee_internal_work_history.py
index d0f3d8d016..2f385a8113 100644
--- a/erpnext/hr/doctype/employee_internal_work_history/employee_internal_work_history.py
+++ b/erpnext/hr/doctype/employee_internal_work_history/employee_internal_work_history.py
@@ -7,4 +7,4 @@ import frappe
from frappe.model.document import Document
class EmployeeInternalWorkHistory(Document):
- pass
\ No newline at end of file
+ pass
diff --git a/erpnext/hr/doctype/employee_onboarding/employee_onboarding.py b/erpnext/hr/doctype/employee_onboarding/employee_onboarding.py
index 55fe317b9e..ca9b2987a6 100644
--- a/erpnext/hr/doctype/employee_onboarding/employee_onboarding.py
+++ b/erpnext/hr/doctype/employee_onboarding/employee_onboarding.py
@@ -57,4 +57,3 @@ def make_employee(source_name, target_doc=None):
}}
}, target_doc, set_missing_values)
return doc
-
diff --git a/erpnext/hr/doctype/employee_onboarding/test_employee_onboarding.py b/erpnext/hr/doctype/employee_onboarding/test_employee_onboarding.py
index 5f7756bcad..0445270b9f 100644
--- a/erpnext/hr/doctype/employee_onboarding/test_employee_onboarding.py
+++ b/erpnext/hr/doctype/employee_onboarding/test_employee_onboarding.py
@@ -101,4 +101,4 @@ def create_employee_onboarding():
onboarding.insert()
onboarding.submit()
- return onboarding
\ No newline at end of file
+ return onboarding
diff --git a/erpnext/hr/doctype/employee_onboarding_template/employee_onboarding_template_dashboard.py b/erpnext/hr/doctype/employee_onboarding_template/employee_onboarding_template_dashboard.py
index 837da53016..ab0eb2f5dc 100644
--- a/erpnext/hr/doctype/employee_onboarding_template/employee_onboarding_template_dashboard.py
+++ b/erpnext/hr/doctype/employee_onboarding_template/employee_onboarding_template_dashboard.py
@@ -9,4 +9,4 @@ def get_data():
'items': ['Employee Onboarding']
},
],
- }
\ No newline at end of file
+ }
diff --git a/erpnext/hr/doctype/employee_referral/employee_referral.py b/erpnext/hr/doctype/employee_referral/employee_referral.py
index 0493306166..547a95e3bd 100644
--- a/erpnext/hr/doctype/employee_referral/employee_referral.py
+++ b/erpnext/hr/doctype/employee_referral/employee_referral.py
@@ -70,4 +70,3 @@ def create_additional_salary(doc):
additional_salary.ref_docname = doc.name
return additional_salary
-
diff --git a/erpnext/hr/doctype/employee_referral/employee_referral_dashboard.py b/erpnext/hr/doctype/employee_referral/employee_referral_dashboard.py
index afa2a1ff1f..caca2961a1 100644
--- a/erpnext/hr/doctype/employee_referral/employee_referral_dashboard.py
+++ b/erpnext/hr/doctype/employee_referral/employee_referral_dashboard.py
@@ -12,4 +12,4 @@ def get_data():
},
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/hr/doctype/employee_referral/employee_referral_list.js b/erpnext/hr/doctype/employee_referral/employee_referral_list.js
index 7533ab635f..38dfc4d4c8 100644
--- a/erpnext/hr/doctype/employee_referral/employee_referral_list.js
+++ b/erpnext/hr/doctype/employee_referral/employee_referral_list.js
@@ -11,4 +11,4 @@ frappe.listview_settings['Employee Referral'] = {
return [__(doc.status), "red", "status,=," + doc.status];
}
},
-};
\ No newline at end of file
+};
diff --git a/erpnext/hr/doctype/employee_referral/test_employee_referral.py b/erpnext/hr/doctype/employee_referral/test_employee_referral.py
index a674f39026..599f326224 100644
--- a/erpnext/hr/doctype/employee_referral/test_employee_referral.py
+++ b/erpnext/hr/doctype/employee_referral/test_employee_referral.py
@@ -57,4 +57,4 @@ def create_employee_referral():
emp_ref.save()
emp_ref.submit()
- return emp_ref
\ No newline at end of file
+ return emp_ref
diff --git a/erpnext/hr/doctype/employee_separation/test_employee_separation.py b/erpnext/hr/doctype/employee_separation/test_employee_separation.py
index f787d9c656..d63501a931 100644
--- a/erpnext/hr/doctype/employee_separation/test_employee_separation.py
+++ b/erpnext/hr/doctype/employee_separation/test_employee_separation.py
@@ -45,4 +45,4 @@ def create_employee_separation():
separation.boarding_status = 'Pending'
separation.insert()
separation.submit()
- return separation
\ No newline at end of file
+ return separation
diff --git a/erpnext/hr/doctype/employee_separation_template/employee_separation_template_dashboard.py b/erpnext/hr/doctype/employee_separation_template/employee_separation_template_dashboard.py
index 39345f0766..75f985cec3 100644
--- a/erpnext/hr/doctype/employee_separation_template/employee_separation_template_dashboard.py
+++ b/erpnext/hr/doctype/employee_separation_template/employee_separation_template_dashboard.py
@@ -9,4 +9,4 @@ def get_data():
'items': ['Employee Separation']
},
],
- }
\ No newline at end of file
+ }
diff --git a/erpnext/hr/doctype/employment_type/employment_type.py b/erpnext/hr/doctype/employment_type/employment_type.py
index fb306b65d2..00aa6bb9bc 100644
--- a/erpnext/hr/doctype/employment_type/employment_type.py
+++ b/erpnext/hr/doctype/employment_type/employment_type.py
@@ -7,4 +7,4 @@ import frappe
from frappe.model.document import Document
class EmploymentType(Document):
- pass
\ No newline at end of file
+ pass
diff --git a/erpnext/hr/doctype/employment_type/test_employment_type.js b/erpnext/hr/doctype/employment_type/test_employment_type.js
index 9835aabd48..fd7c6a1ce3 100644
--- a/erpnext/hr/doctype/employment_type/test_employment_type.js
+++ b/erpnext/hr/doctype/employment_type/test_employment_type.js
@@ -19,4 +19,4 @@ QUnit.test("Test: Employment type [HR]", function (assert) {
'name of employment type correctly saved'),
() => done()
]);
-});
\ No newline at end of file
+});
diff --git a/erpnext/hr/doctype/employment_type/test_employment_type.py b/erpnext/hr/doctype/employment_type/test_employment_type.py
index e138136605..0297ffa01a 100644
--- a/erpnext/hr/doctype/employment_type/test_employment_type.py
+++ b/erpnext/hr/doctype/employment_type/test_employment_type.py
@@ -4,4 +4,4 @@ from __future__ import unicode_literals
import frappe
-test_records = frappe.get_test_records('Employment Type')
\ No newline at end of file
+test_records = frappe.get_test_records('Employment Type')
diff --git a/erpnext/hr/doctype/expense_claim/expense_claim.js b/erpnext/hr/doctype/expense_claim/expense_claim.js
index 629341ff2a..3c4c672816 100644
--- a/erpnext/hr/doctype/expense_claim/expense_claim.js
+++ b/erpnext/hr/doctype/expense_claim/expense_claim.js
@@ -442,4 +442,4 @@ frappe.ui.form.on("Expense Taxes and Charges", {
tax_amount: function(frm, cdt, cdn) {
frm.trigger("calculate_total_tax", cdt, cdn);
}
-});
\ No newline at end of file
+});
diff --git a/erpnext/hr/doctype/expense_claim/expense_claim_dashboard.py b/erpnext/hr/doctype/expense_claim/expense_claim_dashboard.py
index 7de8f4fc13..fe97350701 100644
--- a/erpnext/hr/doctype/expense_claim/expense_claim_dashboard.py
+++ b/erpnext/hr/doctype/expense_claim/expense_claim_dashboard.py
@@ -17,4 +17,4 @@ def get_data():
'items': ['Employee Advance']
},
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/hr/doctype/expense_claim/test_expense_claim.js b/erpnext/hr/doctype/expense_claim/test_expense_claim.js
index d0c43d3be4..2529faec98 100644
--- a/erpnext/hr/doctype/expense_claim/test_expense_claim.js
+++ b/erpnext/hr/doctype/expense_claim/test_expense_claim.js
@@ -42,4 +42,3 @@ QUnit.test("Test: Expense Claim [HR]", function (assert) {
() => done()
]);
});
-
diff --git a/erpnext/hr/doctype/expense_claim/test_expense_claim.py b/erpnext/hr/doctype/expense_claim/test_expense_claim.py
index 96ea686706..c2bd1e9f9f 100644
--- a/erpnext/hr/doctype/expense_claim/test_expense_claim.py
+++ b/erpnext/hr/doctype/expense_claim/test_expense_claim.py
@@ -72,7 +72,7 @@ class TestExpenseClaim(unittest.TestCase):
def test_expense_claim_gl_entry(self):
payable_account = get_payable_account(company_name)
taxes = generate_taxes()
- expense_claim = make_expense_claim(payable_account, 300, 200, company_name, "Travel Expenses - _TC4",
+ expense_claim = make_expense_claim(payable_account, 300, 200, company_name, "Travel Expenses - _TC4",
do_not_submit=True, taxes=taxes)
expense_claim.submit()
diff --git a/erpnext/hr/doctype/expense_claim_detail/expense_claim_detail.py b/erpnext/hr/doctype/expense_claim_detail/expense_claim_detail.py
index 8bfa1ade07..5d48990c5c 100644
--- a/erpnext/hr/doctype/expense_claim_detail/expense_claim_detail.py
+++ b/erpnext/hr/doctype/expense_claim_detail/expense_claim_detail.py
@@ -7,4 +7,4 @@ import frappe
from frappe.model.document import Document
class ExpenseClaimDetail(Document):
- pass
\ No newline at end of file
+ pass
diff --git a/erpnext/hr/doctype/expense_claim_type/expense_claim_type.py b/erpnext/hr/doctype/expense_claim_type/expense_claim_type.py
index 2595506486..a637a54021 100644
--- a/erpnext/hr/doctype/expense_claim_type/expense_claim_type.py
+++ b/erpnext/hr/doctype/expense_claim_type/expense_claim_type.py
@@ -25,4 +25,4 @@ class ExpenseClaimType(Document):
"""Error when Company of Ledger account doesn't match with Company Selected"""
if frappe.db.get_value("Account", entry.default_account, "company") != entry.company:
frappe.throw(_("Account {0} does not match with Company {1}"
- ).format(entry.default_account, entry.company))
\ No newline at end of file
+ ).format(entry.default_account, entry.company))
diff --git a/erpnext/hr/doctype/expense_claim_type/test_expense_claim_type.js b/erpnext/hr/doctype/expense_claim_type/test_expense_claim_type.js
index 62234e08a0..3c9ed35313 100644
--- a/erpnext/hr/doctype/expense_claim_type/test_expense_claim_type.js
+++ b/erpnext/hr/doctype/expense_claim_type/test_expense_claim_type.js
@@ -27,4 +27,3 @@ QUnit.test("Test: Expense Claim Type [HR]", function (assert) {
() => done()
]);
});
-
diff --git a/erpnext/hr/doctype/holiday/holiday.py b/erpnext/hr/doctype/holiday/holiday.py
index aabab0b0d3..78a95b9b74 100644
--- a/erpnext/hr/doctype/holiday/holiday.py
+++ b/erpnext/hr/doctype/holiday/holiday.py
@@ -7,4 +7,4 @@ import frappe
from frappe.model.document import Document
class Holiday(Document):
- pass
\ No newline at end of file
+ pass
diff --git a/erpnext/hr/doctype/holiday_list/holiday_list_dashboard.py b/erpnext/hr/doctype/holiday_list/holiday_list_dashboard.py
index 22e1de0c34..05641c7dc2 100644
--- a/erpnext/hr/doctype/holiday_list/holiday_list_dashboard.py
+++ b/erpnext/hr/doctype/holiday_list/holiday_list_dashboard.py
@@ -18,4 +18,4 @@ def get_data():
'items': ['Service Level', 'Service Level Agreement']
}
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/hr/doctype/holiday_list/test_holiday_list.js b/erpnext/hr/doctype/holiday_list/test_holiday_list.js
index bfcafa9460..ce766143a6 100644
--- a/erpnext/hr/doctype/holiday_list/test_holiday_list.js
+++ b/erpnext/hr/doctype/holiday_list/test_holiday_list.js
@@ -39,4 +39,4 @@ QUnit.test("Test: Holiday list [HR]", function (assert) {
},
() => done()
]);
-});
\ No newline at end of file
+});
diff --git a/erpnext/hr/doctype/hr_settings/hr_settings.js b/erpnext/hr/doctype/hr_settings/hr_settings.js
index fd082fda09..ec99472d9b 100644
--- a/erpnext/hr/doctype/hr_settings/hr_settings.js
+++ b/erpnext/hr/doctype/hr_settings/hr_settings.js
@@ -5,4 +5,4 @@ frappe.ui.form.on('HR Settings', {
restrict_backdated_leave_application: function(frm) {
frm.toggle_reqd("role_allowed_to_create_backdated_leave_application", frm.doc.restrict_backdated_leave_application);
}
-});
\ No newline at end of file
+});
diff --git a/erpnext/hr/doctype/hr_settings/hr_settings.py b/erpnext/hr/doctype/hr_settings/hr_settings.py
index ced98fb9a5..c99df269cc 100644
--- a/erpnext/hr/doctype/hr_settings/hr_settings.py
+++ b/erpnext/hr/doctype/hr_settings/hr_settings.py
@@ -15,4 +15,3 @@ class HRSettings(Document):
from erpnext.setup.doctype.naming_series.naming_series import set_by_naming_series
set_by_naming_series("Employee", "employee_number",
self.get("emp_created_by")=="Naming Series", hide_name_field=True)
-
diff --git a/erpnext/hr/doctype/job_applicant/job_applicant.js b/erpnext/hr/doctype/job_applicant/job_applicant.js
index c62515597c..7658bc9353 100644
--- a/erpnext/hr/doctype/job_applicant/job_applicant.js
+++ b/erpnext/hr/doctype/job_applicant/job_applicant.js
@@ -38,4 +38,4 @@ frappe.ui.form.on("Job Applicant", {
});
}
-});
\ No newline at end of file
+});
diff --git a/erpnext/hr/doctype/job_applicant/job_applicant.py b/erpnext/hr/doctype/job_applicant/job_applicant.py
index 0594ba395b..14aeb03a87 100644
--- a/erpnext/hr/doctype/job_applicant/job_applicant.py
+++ b/erpnext/hr/doctype/job_applicant/job_applicant.py
@@ -50,4 +50,3 @@ class JobApplicant(Document):
if names:
frappe.throw(_("Email Address must be unique, already exists for {0}").format(comma_and(names)), frappe.DuplicateEntryError)
-
diff --git a/erpnext/hr/doctype/job_applicant/job_applicant_dashboard.py b/erpnext/hr/doctype/job_applicant/job_applicant_dashboard.py
index 7f131151e1..ed97978a8a 100644
--- a/erpnext/hr/doctype/job_applicant/job_applicant_dashboard.py
+++ b/erpnext/hr/doctype/job_applicant/job_applicant_dashboard.py
@@ -12,4 +12,4 @@ def get_data():
'items': ['Job Offer']
},
],
- }
\ No newline at end of file
+ }
diff --git a/erpnext/hr/doctype/job_applicant/test_job_applicant.js b/erpnext/hr/doctype/job_applicant/test_job_applicant.js
index b5391c8bf3..741a182add 100644
--- a/erpnext/hr/doctype/job_applicant/test_job_applicant.js
+++ b/erpnext/hr/doctype/job_applicant/test_job_applicant.js
@@ -26,4 +26,3 @@ QUnit.test("Test: Job Opening [HR]", function (assert) {
() => done()
]);
});
-
diff --git a/erpnext/hr/doctype/job_offer/test_job_offer.js b/erpnext/hr/doctype/job_offer/test_job_offer.js
index c9d7d2bef7..5339b9c3d6 100644
--- a/erpnext/hr/doctype/job_offer/test_job_offer.js
+++ b/erpnext/hr/doctype/job_offer/test_job_offer.js
@@ -48,4 +48,4 @@ QUnit.test("Test: Job Offer [HR]", function (assert) {
() => frappe.timeout(2),
() => done()
]);
-});
\ No newline at end of file
+});
diff --git a/erpnext/hr/doctype/job_offer/test_job_offer.py b/erpnext/hr/doctype/job_offer/test_job_offer.py
index b3e1dc8d87..edb21321fc 100644
--- a/erpnext/hr/doctype/job_offer/test_job_offer.py
+++ b/erpnext/hr/doctype/job_offer/test_job_offer.py
@@ -79,4 +79,4 @@ def create_staffing_plan(**args):
})
staffing_plan.insert()
staffing_plan.submit()
- return staffing_plan
\ No newline at end of file
+ return staffing_plan
diff --git a/erpnext/hr/doctype/job_opening/job_opening_dashboard.py b/erpnext/hr/doctype/job_opening/job_opening_dashboard.py
index c0890b4f57..31ef33ef2c 100644
--- a/erpnext/hr/doctype/job_opening/job_opening_dashboard.py
+++ b/erpnext/hr/doctype/job_opening/job_opening_dashboard.py
@@ -9,4 +9,4 @@ def get_data():
'items': ['Job Applicant']
}
],
- }
\ No newline at end of file
+ }
diff --git a/erpnext/hr/doctype/job_opening/templates/job_opening_row.html b/erpnext/hr/doctype/job_opening/templates/job_opening_row.html
index c015101600..69bf49bef7 100644
--- a/erpnext/hr/doctype/job_opening/templates/job_opening_row.html
+++ b/erpnext/hr/doctype/job_opening/templates/job_opening_row.html
@@ -1,16 +1,16 @@
{{ doc.job_title }}
{{ doc.description }}
- {%- if doc.publish_salary_range -%}
+ {%- if doc.publish_salary_range -%}
{{_("Salary range per month")}}: {{ frappe.format_value(frappe.utils.flt(doc.lower_range), currency=doc.currency) }} - {{ frappe.format_value(frappe.utils.flt(doc.upper_range), currency=doc.currency) }}
{% endif %}
{%- if doc.job_application_route -%}
-
{{ _("Apply Now") }}
{% else %}
-
{{ _("Apply Now") }}
{% endif %}
diff --git a/erpnext/hr/doctype/job_opening/test_job_opening.js b/erpnext/hr/doctype/job_opening/test_job_opening.js
index b9e6c0a8b2..cc2f027e85 100644
--- a/erpnext/hr/doctype/job_opening/test_job_opening.js
+++ b/erpnext/hr/doctype/job_opening/test_job_opening.js
@@ -24,4 +24,3 @@ QUnit.test("Test: Job Opening [HR]", function (assert) {
() => done()
]);
});
-
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.js b/erpnext/hr/doctype/leave_allocation/leave_allocation.js
index e9e129cdd2..d94764104d 100755
--- a/erpnext/hr/doctype/leave_allocation/leave_allocation.js
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.js
@@ -100,4 +100,4 @@ frappe.ui.form.on("Leave Allocation", {
frm.set_value("total_leaves_allocated", flt(frm.doc.new_leaves_allocated));
}
}
-});
\ No newline at end of file
+});
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation_dashboard.py b/erpnext/hr/doctype/leave_allocation/leave_allocation_dashboard.py
index 7456aebb45..7a063d92ea 100644
--- a/erpnext/hr/doctype/leave_allocation/leave_allocation_dashboard.py
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation_dashboard.py
@@ -17,4 +17,4 @@ def get_data():
'items': ['Employee Leave Balance']
}
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/hr/doctype/leave_allocation/test_leave_allocation.js b/erpnext/hr/doctype/leave_allocation/test_leave_allocation.js
index 0ef78f2f88..d5364fc8b2 100644
--- a/erpnext/hr/doctype/leave_allocation/test_leave_allocation.js
+++ b/erpnext/hr/doctype/leave_allocation/test_leave_allocation.js
@@ -38,4 +38,4 @@ QUnit.test("Test: Leave allocation [HR]", function (assert) {
"total leave calculation is correctly set"),
() => done()
]);
-});
\ No newline at end of file
+});
diff --git a/erpnext/hr/doctype/leave_application/leave_application_calendar.js b/erpnext/hr/doctype/leave_application/leave_application_calendar.js
index 0286f30064..31faadb107 100644
--- a/erpnext/hr/doctype/leave_application/leave_application_calendar.js
+++ b/erpnext/hr/doctype/leave_application/leave_application_calendar.js
@@ -17,4 +17,4 @@ frappe.views.calendar["Leave Application"] = {
}
},
get_events_method: "erpnext.hr.doctype.leave_application.leave_application.get_events"
-}
\ No newline at end of file
+}
diff --git a/erpnext/hr/doctype/leave_application/leave_application_dashboard.py b/erpnext/hr/doctype/leave_application/leave_application_dashboard.py
index c1d6a6665b..c45717f587 100644
--- a/erpnext/hr/doctype/leave_application/leave_application_dashboard.py
+++ b/erpnext/hr/doctype/leave_application/leave_application_dashboard.py
@@ -17,4 +17,4 @@ def get_data():
'items': ['Employee Leave Balance']
}
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/hr/doctype/leave_application/leave_application_email_template.html b/erpnext/hr/doctype/leave_application/leave_application_email_template.html
index 209302e8f3..14ca41bebc 100644
--- a/erpnext/hr/doctype/leave_application/leave_application_email_template.html
+++ b/erpnext/hr/doctype/leave_application/leave_application_email_template.html
@@ -21,5 +21,5 @@
Status
{{status}}
-
+
diff --git a/erpnext/hr/doctype/leave_application/test_leave_application.js b/erpnext/hr/doctype/leave_application/test_leave_application.js
index 6d7b6a7058..0866b0b6d2 100644
--- a/erpnext/hr/doctype/leave_application/test_leave_application.js
+++ b/erpnext/hr/doctype/leave_application/test_leave_application.js
@@ -39,4 +39,4 @@ QUnit.test("Test: Leave application [HR]", function (assert) {
// "leave for correct employee is submitted"),
() => done()
]);
-});
\ No newline at end of file
+});
diff --git a/erpnext/hr/doctype/leave_block_list/leave_block_list_dashboard.py b/erpnext/hr/doctype/leave_block_list/leave_block_list_dashboard.py
index 2aa54984ec..45aa4915bc 100644
--- a/erpnext/hr/doctype/leave_block_list/leave_block_list_dashboard.py
+++ b/erpnext/hr/doctype/leave_block_list/leave_block_list_dashboard.py
@@ -8,4 +8,4 @@ def get_data():
'items': ['Department']
}
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/hr/doctype/leave_block_list/test_leave_block_list.js b/erpnext/hr/doctype/leave_block_list/test_leave_block_list.js
index 453787865c..b39601b490 100644
--- a/erpnext/hr/doctype/leave_block_list/test_leave_block_list.js
+++ b/erpnext/hr/doctype/leave_block_list/test_leave_block_list.js
@@ -24,4 +24,4 @@ QUnit.test("Test: Leave block list [HR]", function (assert) {
'name of blocked leave list correctly saved'),
() => done()
]);
-});
\ No newline at end of file
+});
diff --git a/erpnext/hr/doctype/leave_block_list_allow/leave_block_list_allow.py b/erpnext/hr/doctype/leave_block_list_allow/leave_block_list_allow.py
index be06b768bf..8e5a09e01e 100644
--- a/erpnext/hr/doctype/leave_block_list_allow/leave_block_list_allow.py
+++ b/erpnext/hr/doctype/leave_block_list_allow/leave_block_list_allow.py
@@ -9,4 +9,4 @@ import frappe
from frappe.model.document import Document
class LeaveBlockListAllow(Document):
- pass
\ No newline at end of file
+ pass
diff --git a/erpnext/hr/doctype/leave_block_list_date/leave_block_list_date.py b/erpnext/hr/doctype/leave_block_list_date/leave_block_list_date.py
index f4028f54eb..54978a1e83 100644
--- a/erpnext/hr/doctype/leave_block_list_date/leave_block_list_date.py
+++ b/erpnext/hr/doctype/leave_block_list_date/leave_block_list_date.py
@@ -9,4 +9,4 @@ import frappe
from frappe.model.document import Document
class LeaveBlockListDate(Document):
- pass
\ No newline at end of file
+ pass
diff --git a/erpnext/hr/doctype/leave_control_panel/leave_control_panel.js b/erpnext/hr/doctype/leave_control_panel/leave_control_panel.js
index b60e225a72..4a450807cc 100644
--- a/erpnext/hr/doctype/leave_control_panel/leave_control_panel.js
+++ b/erpnext/hr/doctype/leave_control_panel/leave_control_panel.js
@@ -21,4 +21,4 @@ frappe.ui.form.on("Leave Control Panel", {
});
}
}
-});
\ No newline at end of file
+});
diff --git a/erpnext/hr/doctype/leave_control_panel/test_leave_control_panel.js b/erpnext/hr/doctype/leave_control_panel/test_leave_control_panel.js
index 2b5cec1c1e..9d37327717 100644
--- a/erpnext/hr/doctype/leave_control_panel/test_leave_control_panel.js
+++ b/erpnext/hr/doctype/leave_control_panel/test_leave_control_panel.js
@@ -47,4 +47,4 @@ QUnit.test("Test: Leave control panel [HR]", function (assert) {
},
() => done()
]);
-});
\ No newline at end of file
+});
diff --git a/erpnext/hr/doctype/leave_encashment/leave_encashment.py b/erpnext/hr/doctype/leave_encashment/leave_encashment.py
index 912bd8ad92..d136210a04 100644
--- a/erpnext/hr/doctype/leave_encashment/leave_encashment.py
+++ b/erpnext/hr/doctype/leave_encashment/leave_encashment.py
@@ -134,4 +134,4 @@ def create_leave_encashment(leave_allocation):
leave_type=allocation.leave_type,
encashment_date=allocation.to_date
))
- leave_encashment.insert(ignore_permissions=True)
\ No newline at end of file
+ leave_encashment.insert(ignore_permissions=True)
diff --git a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
index cf13036181..33a6243e60 100644
--- a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
+++ b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
@@ -185,4 +185,4 @@ def expire_carried_forward_allocation(allocation):
from_date=allocation.to_date,
to_date=allocation.to_date
)
- create_leave_ledger_entry(allocation, args)
\ No newline at end of file
+ create_leave_ledger_entry(allocation, args)
diff --git a/erpnext/hr/doctype/leave_period/leave_period_dashboard.py b/erpnext/hr/doctype/leave_period/leave_period_dashboard.py
index 1572de3cb7..7c2c9632d8 100644
--- a/erpnext/hr/doctype/leave_period/leave_period_dashboard.py
+++ b/erpnext/hr/doctype/leave_period/leave_period_dashboard.py
@@ -10,4 +10,4 @@ def get_data():
'items': ['Leave Allocation']
}
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/hr/doctype/leave_period/test_leave_period.py b/erpnext/hr/doctype/leave_period/test_leave_period.py
index b5857bcd8f..cbb34371fc 100644
--- a/erpnext/hr/doctype/leave_period/test_leave_period.py
+++ b/erpnext/hr/doctype/leave_period/test_leave_period.py
@@ -27,4 +27,4 @@ def create_leave_period(from_date, to_date, company=None):
"to_date": to_date,
"is_active": 1
}).insert()
- return leave_period
\ No newline at end of file
+ return leave_period
diff --git a/erpnext/hr/doctype/leave_policy/leave_policy_dashboard.py b/erpnext/hr/doctype/leave_policy/leave_policy_dashboard.py
index ff7f0422e0..474f3a77ad 100644
--- a/erpnext/hr/doctype/leave_policy/leave_policy_dashboard.py
+++ b/erpnext/hr/doctype/leave_policy/leave_policy_dashboard.py
@@ -10,4 +10,4 @@ def get_data():
'items': ['Leave Policy Assignment', 'Leave Allocation']
},
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/hr/doctype/leave_policy/test_leave_policy.py b/erpnext/hr/doctype/leave_policy/test_leave_policy.py
index fc868ea15a..af7567b5bc 100644
--- a/erpnext/hr/doctype/leave_policy/test_leave_policy.py
+++ b/erpnext/hr/doctype/leave_policy/test_leave_policy.py
@@ -28,4 +28,4 @@ def create_leave_policy(**args):
"leave_type": args.leave_type or "_Test Leave Type",
"annual_allocation": args.annual_allocation or 10
}]
- })
\ No newline at end of file
+ })
diff --git a/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment_dashboard.py b/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment_dashboard.py
index 4bb0535cf8..a2f7f5866b 100644
--- a/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment_dashboard.py
+++ b/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment_dashboard.py
@@ -10,4 +10,4 @@ def get_data():
'items': ['Leave Allocation']
},
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment_list.js b/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment_list.js
index 8fe4b8f8ef..8b954c46a1 100644
--- a/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment_list.js
+++ b/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment_list.js
@@ -105,4 +105,4 @@ frappe.listview_settings['Leave Policy Assignment'] = {
});
}
}
-};
\ No newline at end of file
+};
diff --git a/erpnext/hr/doctype/leave_policy_assignment/test_leave_policy_assignment.py b/erpnext/hr/doctype/leave_policy_assignment/test_leave_policy_assignment.py
index 9a14e3588d..0089804f51 100644
--- a/erpnext/hr/doctype/leave_policy_assignment/test_leave_policy_assignment.py
+++ b/erpnext/hr/doctype/leave_policy_assignment/test_leave_policy_assignment.py
@@ -99,5 +99,3 @@ class TestLeavePolicyAssignment(unittest.TestCase):
def tearDown(self):
for doctype in ["Leave Application", "Leave Allocation", "Leave Policy Assignment", "Leave Ledger Entry"]:
frappe.db.sql("delete from `tab{0}`".format(doctype)) #nosec
-
-
diff --git a/erpnext/hr/doctype/leave_type/leave_type_dashboard.py b/erpnext/hr/doctype/leave_type/leave_type_dashboard.py
index 5cae9a8809..c8944fcb9e 100644
--- a/erpnext/hr/doctype/leave_type/leave_type_dashboard.py
+++ b/erpnext/hr/doctype/leave_type/leave_type_dashboard.py
@@ -11,4 +11,4 @@ def get_data():
'items': ['Attendance', 'Leave Encashment']
}
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/hr/doctype/leave_type/test_leave_type.js b/erpnext/hr/doctype/leave_type/test_leave_type.js
index d939a24810..db910cde51 100644
--- a/erpnext/hr/doctype/leave_type/test_leave_type.js
+++ b/erpnext/hr/doctype/leave_type/test_leave_type.js
@@ -19,4 +19,4 @@ QUnit.test("Test: Leave type [HR]", function (assert) {
'leave type correctly saved'),
() => done()
]);
-});
\ No newline at end of file
+});
diff --git a/erpnext/hr/doctype/leave_type/test_leave_type.py b/erpnext/hr/doctype/leave_type/test_leave_type.py
index 7fef2975c8..048dddd3ef 100644
--- a/erpnext/hr/doctype/leave_type/test_leave_type.py
+++ b/erpnext/hr/doctype/leave_type/test_leave_type.py
@@ -28,4 +28,4 @@ def create_leave_type(**args):
if leave_type.is_ppl:
leave_type.fraction_of_daily_salary_per_leave = args.fraction_of_daily_salary_per_leave or 0.5
- return leave_type
\ No newline at end of file
+ return leave_type
diff --git a/erpnext/hr/doctype/shift_assignment/shift_assignment_calendar.js b/erpnext/hr/doctype/shift_assignment/shift_assignment_calendar.js
index bb692e1402..5d2360f10f 100644
--- a/erpnext/hr/doctype/shift_assignment/shift_assignment_calendar.js
+++ b/erpnext/hr/doctype/shift_assignment/shift_assignment_calendar.js
@@ -10,4 +10,4 @@ frappe.views.calendar["Shift Assignment"] = {
"allDay": "allDay",
},
get_events_method: "erpnext.hr.doctype.shift_assignment.shift_assignment.get_events"
-}
\ No newline at end of file
+}
diff --git a/erpnext/hr/doctype/shift_assignment/test_shift_assignment.py b/erpnext/hr/doctype/shift_assignment/test_shift_assignment.py
index 4c3c1ed579..07d92fe61d 100644
--- a/erpnext/hr/doctype/shift_assignment/test_shift_assignment.py
+++ b/erpnext/hr/doctype/shift_assignment/test_shift_assignment.py
@@ -77,4 +77,4 @@ class TestShiftAssignment(unittest.TestCase):
"status": 'Active'
})
- self.assertRaises(frappe.ValidationError, shift_assignment_3.save)
\ No newline at end of file
+ self.assertRaises(frappe.ValidationError, shift_assignment_3.save)
diff --git a/erpnext/hr/doctype/shift_request/shift_request.py b/erpnext/hr/doctype/shift_request/shift_request.py
index 6461f07552..2731da125a 100644
--- a/erpnext/hr/doctype/shift_request/shift_request.py
+++ b/erpnext/hr/doctype/shift_request/shift_request.py
@@ -94,4 +94,4 @@ class ShiftRequest(Document):
msg = _("Employee {0} has already applied for {1} between {2} and {3} : ").format(self.employee,
d['shift_type'], formatdate(d['from_date']), formatdate(d['to_date'])) \
+ """
{0} """.format(d["name"])
- frappe.throw(msg, OverlapError)
\ No newline at end of file
+ frappe.throw(msg, OverlapError)
diff --git a/erpnext/hr/doctype/shift_request/shift_request_dashboard.py b/erpnext/hr/doctype/shift_request/shift_request_dashboard.py
index e3bf5df949..f70b61a20a 100644
--- a/erpnext/hr/doctype/shift_request/shift_request_dashboard.py
+++ b/erpnext/hr/doctype/shift_request/shift_request_dashboard.py
@@ -9,4 +9,4 @@ def get_data():
'items': ['Shift Assignment']
},
],
- }
\ No newline at end of file
+ }
diff --git a/erpnext/hr/doctype/shift_request/test_shift_request.py b/erpnext/hr/doctype/shift_request/test_shift_request.py
index 3525540cdf..60b7676e25 100644
--- a/erpnext/hr/doctype/shift_request/test_shift_request.py
+++ b/erpnext/hr/doctype/shift_request/test_shift_request.py
@@ -106,4 +106,4 @@ def make_shift_request(approver, do_not_submit=0):
return shift_request
shift_request.submit()
- return shift_request
\ No newline at end of file
+ return shift_request
diff --git a/erpnext/hr/doctype/staffing_plan/staffing_plan_dashboard.py b/erpnext/hr/doctype/staffing_plan/staffing_plan_dashboard.py
index 35a303f0fb..8e89d53c8e 100644
--- a/erpnext/hr/doctype/staffing_plan/staffing_plan_dashboard.py
+++ b/erpnext/hr/doctype/staffing_plan/staffing_plan_dashboard.py
@@ -9,4 +9,4 @@ def get_data():
'items': ['Job Opening']
}
],
- }
\ No newline at end of file
+ }
diff --git a/erpnext/hr/doctype/staffing_plan/test_staffing_plan.py b/erpnext/hr/doctype/staffing_plan/test_staffing_plan.py
index 628255b11f..1c6218e9a7 100644
--- a/erpnext/hr/doctype/staffing_plan/test_staffing_plan.py
+++ b/erpnext/hr/doctype/staffing_plan/test_staffing_plan.py
@@ -94,4 +94,4 @@ def make_company():
company.parent_company = "_Test Company 3"
company.default_currency = "INR"
company.country = "Pakistan"
- company.insert()
\ No newline at end of file
+ company.insert()
diff --git a/erpnext/hr/doctype/training_event/test_training_event.py b/erpnext/hr/doctype/training_event/test_training_event.py
index 9b32136bfb..6a275b330c 100644
--- a/erpnext/hr/doctype/training_event/test_training_event.py
+++ b/erpnext/hr/doctype/training_event/test_training_event.py
@@ -58,4 +58,4 @@ def create_training_event(attendees):
"end_time": add_days(today(), 6),
"introduction": "Welcome to the Basic Training Event",
"employees": attendees
- }).insert()
\ No newline at end of file
+ }).insert()
diff --git a/erpnext/hr/doctype/training_event/tests/test_training_event.js b/erpnext/hr/doctype/training_event/tests/test_training_event.js
index 8ff4fecd6e..08031a1963 100644
--- a/erpnext/hr/doctype/training_event/tests/test_training_event.js
+++ b/erpnext/hr/doctype/training_event/tests/test_training_event.js
@@ -56,4 +56,4 @@ QUnit.test("Test: Training Event [HR]", function (assert) {
() => frappe.timeout(2),
() => done()
]);
-});
\ No newline at end of file
+});
diff --git a/erpnext/hr/doctype/training_event/training_event.js b/erpnext/hr/doctype/training_event/training_event.js
index d5f6e5f573..642e6a1fd7 100644
--- a/erpnext/hr/doctype/training_event/training_event.js
+++ b/erpnext/hr/doctype/training_event/training_event.js
@@ -46,4 +46,3 @@ frappe.ui.form.on("Training Event Employee", {
frm.events.set_employee_query(frm);
}
});
-
diff --git a/erpnext/hr/doctype/training_event/training_event_dashboard.py b/erpnext/hr/doctype/training_event/training_event_dashboard.py
index 1c1645c766..19afd8dd6e 100644
--- a/erpnext/hr/doctype/training_event/training_event_dashboard.py
+++ b/erpnext/hr/doctype/training_event/training_event_dashboard.py
@@ -9,4 +9,4 @@ def get_data():
'items': ['Training Result', 'Training Feedback']
},
],
- }
\ No newline at end of file
+ }
diff --git a/erpnext/hr/doctype/training_feedback/test_training_feedback.js b/erpnext/hr/doctype/training_feedback/test_training_feedback.js
index 9daa51f927..5c825aea7f 100644
--- a/erpnext/hr/doctype/training_feedback/test_training_feedback.js
+++ b/erpnext/hr/doctype/training_feedback/test_training_feedback.js
@@ -49,4 +49,3 @@ QUnit.test("Test: Training Feedback [HR]", function (assert) {
() => done()
]);
});
-
diff --git a/erpnext/hr/doctype/training_feedback/test_training_feedback.py b/erpnext/hr/doctype/training_feedback/test_training_feedback.py
index c30a3ad34c..4c0c18029d 100644
--- a/erpnext/hr/doctype/training_feedback/test_training_feedback.py
+++ b/erpnext/hr/doctype/training_feedback/test_training_feedback.py
@@ -64,4 +64,4 @@ def create_training_feedback(event, employee):
"training_event": event,
"employee": employee,
"feedback": "Test"
- })
\ No newline at end of file
+ })
diff --git a/erpnext/hr/doctype/training_feedback/training_feedback.js b/erpnext/hr/doctype/training_feedback/training_feedback.js
index 0dea098a67..5e875c1b43 100644
--- a/erpnext/hr/doctype/training_feedback/training_feedback.js
+++ b/erpnext/hr/doctype/training_feedback/training_feedback.js
@@ -7,4 +7,4 @@ frappe.ui.form.on('Training Feedback', {
frm.add_fetch("training_event", "event_name", "event_name");
frm.add_fetch("training_event", "trainer_name", "trainer_name");
}
-});
\ No newline at end of file
+});
diff --git a/erpnext/hr/doctype/training_feedback/training_feedback.py b/erpnext/hr/doctype/training_feedback/training_feedback.py
index 0d32de793c..3d4b9b3ea9 100644
--- a/erpnext/hr/doctype/training_feedback/training_feedback.py
+++ b/erpnext/hr/doctype/training_feedback/training_feedback.py
@@ -42,4 +42,3 @@ class TrainingFeedback(Document):
if employee:
frappe.db.set_value("Training Event Employee", employee, "status", "Completed")
-
diff --git a/erpnext/hr/doctype/training_program/training_program.js b/erpnext/hr/doctype/training_program/training_program.js
index 7d85cab59d..a4ccf54063 100644
--- a/erpnext/hr/doctype/training_program/training_program.js
+++ b/erpnext/hr/doctype/training_program/training_program.js
@@ -2,4 +2,4 @@
// For license information, please see license.txt
frappe.ui.form.on('Training Program', {
-});
\ No newline at end of file
+});
diff --git a/erpnext/hr/doctype/training_program/training_program_dashboard.py b/erpnext/hr/doctype/training_program/training_program_dashboard.py
index 441a71bba7..0fc18a8029 100644
--- a/erpnext/hr/doctype/training_program/training_program_dashboard.py
+++ b/erpnext/hr/doctype/training_program/training_program_dashboard.py
@@ -10,4 +10,4 @@ def get_data():
'items': ['Training Event']
},
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/hr/doctype/training_result/training_result.js b/erpnext/hr/doctype/training_result/training_result.js
index 62ac383ab7..5cdbcad805 100644
--- a/erpnext/hr/doctype/training_result/training_result.js
+++ b/erpnext/hr/doctype/training_result/training_result.js
@@ -11,7 +11,7 @@ frappe.ui.form.on('Training Result', {
},
training_event: function(frm) {
- if (frm.doc.training_event && !frm.doc.docstatus && !frm.doc.employees) {
+ if (frm.doc.training_event && !frm.doc.docstatus && !frm.doc.employees) {
frappe.call({
method: "erpnext.hr.doctype.training_result.training_result.get_employees",
args: {
diff --git a/erpnext/hr/doctype/training_result_employee/test_training_result.js b/erpnext/hr/doctype/training_result_employee/test_training_result.js
index 2ebf8962ee..3f39750835 100644
--- a/erpnext/hr/doctype/training_result_employee/test_training_result.js
+++ b/erpnext/hr/doctype/training_result_employee/test_training_result.js
@@ -50,4 +50,3 @@ QUnit.test("Test: Training Result [HR]", function (assert) {
() => done()
]);
});
-
diff --git a/erpnext/hr/doctype/vehicle/vehicle_dashboard.py b/erpnext/hr/doctype/vehicle/vehicle_dashboard.py
index 761c70182b..628c8972ce 100644
--- a/erpnext/hr/doctype/vehicle/vehicle_dashboard.py
+++ b/erpnext/hr/doctype/vehicle/vehicle_dashboard.py
@@ -17,4 +17,4 @@ def get_data():
'items': ['Delivery Trip']
}
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/hr/doctype/vehicle_log/test_vehicle_log.py b/erpnext/hr/doctype/vehicle_log/test_vehicle_log.py
index ed52c4e122..ed02120cca 100644
--- a/erpnext/hr/doctype/vehicle_log/test_vehicle_log.py
+++ b/erpnext/hr/doctype/vehicle_log/test_vehicle_log.py
@@ -115,4 +115,4 @@ def make_vehicle_log(license_plate, employee_id, with_services=False):
vehicle_log.save()
vehicle_log.submit()
- return vehicle_log
\ No newline at end of file
+ return vehicle_log
diff --git a/erpnext/hr/doctype/vehicle_log/vehicle_log.js b/erpnext/hr/doctype/vehicle_log/vehicle_log.js
index 6f3a0dc40e..14fe9a02da 100644
--- a/erpnext/hr/doctype/vehicle_log/vehicle_log.js
+++ b/erpnext/hr/doctype/vehicle_log/vehicle_log.js
@@ -24,4 +24,3 @@ frappe.ui.form.on("Vehicle Log", {
});
}
});
-
diff --git a/erpnext/hr/notification/training_feedback/training_feedback.html b/erpnext/hr/notification/training_feedback/training_feedback.html
index fd8fef9e82..b49662a6eb 100644
--- a/erpnext/hr/notification/training_feedback/training_feedback.html
+++ b/erpnext/hr/notification/training_feedback/training_feedback.html
@@ -3,4 +3,4 @@
You attended training {{ frappe.utils.get_link_to_form(
"Training Event", doc.training_event) }}
-
{{ _("Please share your feedback to the training by clicking on 'Training Feedback' and then 'New'") }}
\ No newline at end of file
+
{{ _("Please share your feedback to the training by clicking on 'Training Feedback' and then 'New'") }}
diff --git a/erpnext/hr/notification/training_scheduled/training_scheduled.html b/erpnext/hr/notification/training_scheduled/training_scheduled.html
index 374038ac20..50f6d07a47 100644
--- a/erpnext/hr/notification/training_scheduled/training_scheduled.html
+++ b/erpnext/hr/notification/training_scheduled/training_scheduled.html
@@ -41,4 +41,4 @@
-
\ No newline at end of file
+
diff --git a/erpnext/hr/page/organizational_chart/organizational_chart.js b/erpnext/hr/page/organizational_chart/organizational_chart.js
index 08f2c94ad4..81162a4c9a 100644
--- a/erpnext/hr/page/organizational_chart/organizational_chart.js
+++ b/erpnext/hr/page/organizational_chart/organizational_chart.js
@@ -18,4 +18,4 @@ frappe.pages['organizational-chart'].on_page_load = function(wrapper) {
organizational_chart.show();
});
});
-};
\ No newline at end of file
+};
diff --git a/erpnext/hr/page/organizational_chart/organizational_chart.py b/erpnext/hr/page/organizational_chart/organizational_chart.py
index 2983198217..4423d29e40 100644
--- a/erpnext/hr/page/organizational_chart/organizational_chart.py
+++ b/erpnext/hr/page/organizational_chart/organizational_chart.py
@@ -45,4 +45,4 @@ def get_connections(employee):
num_connections += len(descendants)
nodes_to_expand.extend(descendants)
- return num_connections
\ No newline at end of file
+ return num_connections
diff --git a/erpnext/hr/page/team_updates/team_updates.py b/erpnext/hr/page/team_updates/team_updates.py
index a6cf935985..58cdc4b7e1 100644
--- a/erpnext/hr/page/team_updates/team_updates.py
+++ b/erpnext/hr/page/team_updates/team_updates.py
@@ -17,4 +17,4 @@ def get_data(start=0):
if d.text_content:
d.content = frappe.utils.md_to_html(EmailReplyParser.parse_reply(d.text_content))
- return data
\ No newline at end of file
+ return data
diff --git a/erpnext/hr/print_format/standard_appointment_letter/standard_appointment_letter.html b/erpnext/hr/print_format/standard_appointment_letter/standard_appointment_letter.html
index d60582e1a1..87daafcaae 100644
--- a/erpnext/hr/print_format/standard_appointment_letter/standard_appointment_letter.html
+++ b/erpnext/hr/print_format/standard_appointment_letter/standard_appointment_letter.html
@@ -35,4 +35,4 @@
________________
{{ doc.applicant_name }}
-
\ No newline at end of file
+
diff --git a/erpnext/hr/report/daily_work_summary_replies/daily_work_summary_replies.py b/erpnext/hr/report/daily_work_summary_replies/daily_work_summary_replies.py
index aa8eea5d74..d8691b4d02 100644
--- a/erpnext/hr/report/daily_work_summary_replies/daily_work_summary_replies.py
+++ b/erpnext/hr/report/daily_work_summary_replies/daily_work_summary_replies.py
@@ -54,4 +54,4 @@ def get_data(filters):
user_name = frappe.get_value('User', user, 'full_name')
count = len([d for d in replies if d.sender == user])
data.append([user_name, count, total])
- return data
\ No newline at end of file
+ return data
diff --git a/erpnext/hr/report/employee_advance_summary/employee_advance_summary.js b/erpnext/hr/report/employee_advance_summary/employee_advance_summary.js
index 528ae4cea6..8de4af5d4f 100644
--- a/erpnext/hr/report/employee_advance_summary/employee_advance_summary.js
+++ b/erpnext/hr/report/employee_advance_summary/employee_advance_summary.js
@@ -38,4 +38,3 @@ frappe.query_reports["Employee Advance Summary"] = {
}
]
};
-
diff --git a/erpnext/hr/report/employee_analytics/employee_analytics.py b/erpnext/hr/report/employee_analytics/employee_analytics.py
index 8f39388926..fe77b6abc9 100644
--- a/erpnext/hr/report/employee_analytics/employee_analytics.py
+++ b/erpnext/hr/report/employee_analytics/employee_analytics.py
@@ -81,4 +81,3 @@ def get_chart_data(parameters,employees, filters):
}
chart["type"] = "donut"
return chart
-
diff --git a/erpnext/hr/report/employee_birthday/employee_birthday.js b/erpnext/hr/report/employee_birthday/employee_birthday.js
index 60b69b409a..bbe4a8d179 100644
--- a/erpnext/hr/report/employee_birthday/employee_birthday.js
+++ b/erpnext/hr/report/employee_birthday/employee_birthday.js
@@ -8,7 +8,7 @@ frappe.query_reports["Employee Birthday"] = {
"label": __("Month"),
"fieldtype": "Select",
"options": "Jan\nFeb\nMar\nApr\nMay\nJun\nJul\nAug\nSep\nOct\nNov\nDec",
- "default": ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov",
+ "default": ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov",
"Dec"][frappe.datetime.str_to_obj(frappe.datetime.get_today()).getMonth()],
},
{
@@ -19,4 +19,4 @@ frappe.query_reports["Employee Birthday"] = {
"default": frappe.defaults.get_user_default("Company")
}
]
-}
\ No newline at end of file
+}
diff --git a/erpnext/hr/report/recruitment_analytics/recruitment_analytics.js b/erpnext/hr/report/recruitment_analytics/recruitment_analytics.js
index 9620f52000..51dc7ff85b 100644
--- a/erpnext/hr/report/recruitment_analytics/recruitment_analytics.js
+++ b/erpnext/hr/report/recruitment_analytics/recruitment_analytics.js
@@ -20,4 +20,4 @@ frappe.query_reports["Recruitment Analytics"] = {
"reqd": 1,
},
]
-};
\ No newline at end of file
+};
diff --git a/erpnext/hr/report/vehicle_expenses/vehicle_expenses.js b/erpnext/hr/report/vehicle_expenses/vehicle_expenses.js
index 879acd18ef..2d0aa0f36d 100644
--- a/erpnext/hr/report/vehicle_expenses/vehicle_expenses.js
+++ b/erpnext/hr/report/vehicle_expenses/vehicle_expenses.js
@@ -49,4 +49,3 @@ frappe.query_reports["Vehicle Expenses"] = {
}
]
};
-
diff --git a/erpnext/hr/utils.py b/erpnext/hr/utils.py
index 992b18d37a..a1026ce055 100644
--- a/erpnext/hr/utils.py
+++ b/erpnext/hr/utils.py
@@ -413,4 +413,4 @@ def share_doc_with_approver(doc, user):
def validate_active_employee(employee):
if frappe.db.get_value("Employee", employee, "status") == "Inactive":
frappe.throw(_("Transactions cannot be created for an Inactive Employee {0}.").format(
- get_link_to_form("Employee", employee)), InactiveEmployeeStatusError)
\ No newline at end of file
+ get_link_to_form("Employee", employee)), InactiveEmployeeStatusError)
diff --git a/erpnext/hr/web_form/job_application/job_application.js b/erpnext/hr/web_form/job_application/job_application.js
index 699703c579..ffc5e98425 100644
--- a/erpnext/hr/web_form/job_application/job_application.js
+++ b/erpnext/hr/web_form/job_application/job_application.js
@@ -1,3 +1,3 @@
frappe.ready(function() {
// bind events here
-})
\ No newline at end of file
+})
diff --git a/erpnext/loan_management/dashboard_chart_source/top_10_pledged_loan_securities/top_10_pledged_loan_securities.js b/erpnext/loan_management/dashboard_chart_source/top_10_pledged_loan_securities/top_10_pledged_loan_securities.js
index cf75cc8e41..58179416b1 100644
--- a/erpnext/loan_management/dashboard_chart_source/top_10_pledged_loan_securities/top_10_pledged_loan_securities.js
+++ b/erpnext/loan_management/dashboard_chart_source/top_10_pledged_loan_securities/top_10_pledged_loan_securities.js
@@ -11,4 +11,4 @@ frappe.dashboards.chart_sources["Top 10 Pledged Loan Securities"] = {
default: frappe.defaults.get_user_default("Company")
}
]
-};
\ No newline at end of file
+};
diff --git a/erpnext/loan_management/dashboard_chart_source/top_10_pledged_loan_securities/top_10_pledged_loan_securities.py b/erpnext/loan_management/dashboard_chart_source/top_10_pledged_loan_securities/top_10_pledged_loan_securities.py
index 6bb04401be..6ce2a54b19 100644
--- a/erpnext/loan_management/dashboard_chart_source/top_10_pledged_loan_securities/top_10_pledged_loan_securities.py
+++ b/erpnext/loan_management/dashboard_chart_source/top_10_pledged_loan_securities/top_10_pledged_loan_securities.py
@@ -73,4 +73,4 @@ def get_data(chart_name = None, chart = None, no_cache = None, filters = None, f
'chartType': 'bar',
'values': values
}]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/loan_management/doctype/loan/loan_dashboard.py b/erpnext/loan_management/doctype/loan/loan_dashboard.py
index 7a8190f745..711a7829ba 100644
--- a/erpnext/loan_management/doctype/loan/loan_dashboard.py
+++ b/erpnext/loan_management/doctype/loan/loan_dashboard.py
@@ -16,4 +16,4 @@ def get_data():
'items': ['Loan Repayment', 'Loan Interest Accrual', 'Loan Write Off', 'Loan Security Unpledge']
}
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/loan_management/doctype/loan/test_loan.py b/erpnext/loan_management/doctype/loan/test_loan.py
index 314f58dd15..122d723605 100644
--- a/erpnext/loan_management/doctype/loan/test_loan.py
+++ b/erpnext/loan_management/doctype/loan/test_loan.py
@@ -988,4 +988,4 @@ def create_demand_loan(applicant, loan_type, loan_application, posting_date=None
loan.save()
- return loan
\ No newline at end of file
+ return loan
diff --git a/erpnext/loan_management/doctype/loan_application/loan_application_dashboard.py b/erpnext/loan_management/doctype/loan_application/loan_application_dashboard.py
index bf3f58b83e..3975adf443 100644
--- a/erpnext/loan_management/doctype/loan_application/loan_application_dashboard.py
+++ b/erpnext/loan_management/doctype/loan_application/loan_application_dashboard.py
@@ -9,4 +9,4 @@ def get_data():
'items': ['Loan', 'Loan Security Pledge']
},
],
- }
\ No newline at end of file
+ }
diff --git a/erpnext/loan_management/doctype/loan_disbursement/loan_disbursement.py b/erpnext/loan_management/doctype/loan_disbursement/loan_disbursement.py
index f341e81065..f113c10ef7 100644
--- a/erpnext/loan_management/doctype/loan_disbursement/loan_disbursement.py
+++ b/erpnext/loan_management/doctype/loan_disbursement/loan_disbursement.py
@@ -203,5 +203,3 @@ def get_disbursal_amount(loan, on_current_security_price=0):
disbursal_amount = loan_details.loan_amount - loan_details.disbursed_amount
return disbursal_amount
-
-
diff --git a/erpnext/loan_management/doctype/loan_interest_accrual/loan_interest_accrual.py b/erpnext/loan_management/doctype/loan_interest_accrual/loan_interest_accrual.py
index 7978350adf..d75213ce78 100644
--- a/erpnext/loan_management/doctype/loan_interest_accrual/loan_interest_accrual.py
+++ b/erpnext/loan_management/doctype/loan_interest_accrual/loan_interest_accrual.py
@@ -247,4 +247,3 @@ def get_per_day_interest(principal_amount, rate_of_interest, posting_date=None):
posting_date = getdate()
return flt((principal_amount * rate_of_interest) / (days_in_year(get_datetime(posting_date).year) * 100))
-
diff --git a/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py b/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py
index b8b1a40b5f..57aec2e5c9 100644
--- a/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py
+++ b/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py
@@ -455,6 +455,3 @@ def calculate_amounts(against_loan, posting_date, payment_type=''):
amounts['payable_amount'] = amounts['payable_principal_amount'] + amounts['interest_amount']
return amounts
-
-
-
diff --git a/erpnext/loan_management/doctype/loan_security/loan_security_dashboard.py b/erpnext/loan_management/doctype/loan_security/loan_security_dashboard.py
index 878b3fd051..3eec5660ac 100644
--- a/erpnext/loan_management/doctype/loan_security/loan_security_dashboard.py
+++ b/erpnext/loan_management/doctype/loan_security/loan_security_dashboard.py
@@ -12,4 +12,4 @@ def get_data():
'items': ['Loan Security Pledge', 'Loan Security Unpledge']
}
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/loan_management/doctype/loan_security_pledge/loan_security_pledge.js b/erpnext/loan_management/doctype/loan_security_pledge/loan_security_pledge.js
index 11c932ff1c..48ca392edf 100644
--- a/erpnext/loan_management/doctype/loan_security_pledge/loan_security_pledge.js
+++ b/erpnext/loan_management/doctype/loan_security_pledge/loan_security_pledge.js
@@ -40,4 +40,4 @@ frappe.ui.form.on("Pledge", {
qty: function(frm, cdt, cdn) {
frm.events.calculate_amounts(frm, cdt, cdn);
},
-});
\ No newline at end of file
+});
diff --git a/erpnext/loan_management/doctype/loan_security_price/loan_security_price.py b/erpnext/loan_management/doctype/loan_security_price/loan_security_price.py
index 32d81afed5..9fc1fda53f 100644
--- a/erpnext/loan_management/doctype/loan_security_price/loan_security_price.py
+++ b/erpnext/loan_management/doctype/loan_security_price/loan_security_price.py
@@ -40,12 +40,3 @@ def get_loan_security_price(loan_security, valid_time=None):
frappe.throw(_("No valid Loan Security Price found for {0}").format(frappe.bold(loan_security)))
else:
return loan_security_price
-
-
-
-
-
-
-
-
-
diff --git a/erpnext/loan_management/doctype/loan_security_shortfall/loan_security_shortfall.py b/erpnext/loan_management/doctype/loan_security_shortfall/loan_security_shortfall.py
index 8233b7b297..cd7694b7b1 100644
--- a/erpnext/loan_management/doctype/loan_security_shortfall/loan_security_shortfall.py
+++ b/erpnext/loan_management/doctype/loan_security_shortfall/loan_security_shortfall.py
@@ -122,4 +122,3 @@ def update_pending_shortfall(shortfall):
"shortfall_amount": 0,
"shortfall_percentage": 0
})
-
diff --git a/erpnext/loan_management/doctype/loan_security_type/loan_security_type_dashboard.py b/erpnext/loan_management/doctype/loan_security_type/loan_security_type_dashboard.py
index ac33589b54..17de8c1da4 100644
--- a/erpnext/loan_management/doctype/loan_security_type/loan_security_type_dashboard.py
+++ b/erpnext/loan_management/doctype/loan_security_type/loan_security_type_dashboard.py
@@ -12,4 +12,4 @@ def get_data():
'items': ['Loan Security Pledge', 'Loan Security Unpledge']
}
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/loan_management/doctype/loan_security_unpledge/loan_security_unpledge.py b/erpnext/loan_management/doctype/loan_security_unpledge/loan_security_unpledge.py
index b24dc2f7c2..4f936dd7c1 100644
--- a/erpnext/loan_management/doctype/loan_security_unpledge/loan_security_unpledge.py
+++ b/erpnext/loan_management/doctype/loan_security_unpledge/loan_security_unpledge.py
@@ -147,8 +147,3 @@ def get_pledged_security_qty(loan):
current_pledges[security] -= unpledges.get(security, 0.0)
return current_pledges
-
-
-
-
-
diff --git a/erpnext/loan_management/doctype/loan_type/loan_type.py b/erpnext/loan_management/doctype/loan_type/loan_type.py
index 208cb19c88..50ef930dbb 100644
--- a/erpnext/loan_management/doctype/loan_type/loan_type.py
+++ b/erpnext/loan_management/doctype/loan_type/loan_type.py
@@ -21,4 +21,3 @@ class LoanType(Document):
if self.get('loan_account') == self.get('payment_account'):
frappe.throw(_('Loan Account and Payment Account cannot be same'))
-
diff --git a/erpnext/loan_management/doctype/loan_type/loan_type_dashboard.py b/erpnext/loan_management/doctype/loan_type/loan_type_dashboard.py
index 58c668948c..95d97fdf9b 100644
--- a/erpnext/loan_management/doctype/loan_type/loan_type_dashboard.py
+++ b/erpnext/loan_management/doctype/loan_type/loan_type_dashboard.py
@@ -12,4 +12,4 @@ def get_data():
'items': ['Loan Application']
}
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/loan_management/doctype/loan_write_off/loan_write_off.py b/erpnext/loan_management/doctype/loan_write_off/loan_write_off.py
index 54a3f2cbb1..676df701cc 100644
--- a/erpnext/loan_management/doctype/loan_write_off/loan_write_off.py
+++ b/erpnext/loan_management/doctype/loan_write_off/loan_write_off.py
@@ -84,5 +84,3 @@ class LoanWriteOff(AccountsController):
)
make_gl_entries(gl_entries, cancel=cancel, merge_entries=False)
-
-
diff --git a/erpnext/loan_management/doctype/process_loan_interest_accrual/process_loan_interest_accrual.py b/erpnext/loan_management/doctype/process_loan_interest_accrual/process_loan_interest_accrual.py
index 11333dc2aa..8c67c0affe 100644
--- a/erpnext/loan_management/doctype/process_loan_interest_accrual/process_loan_interest_accrual.py
+++ b/erpnext/loan_management/doctype/process_loan_interest_accrual/process_loan_interest_accrual.py
@@ -61,4 +61,3 @@ def term_loan_accrual_pending(date):
})
return pending_accrual
-
diff --git a/erpnext/loan_management/doctype/process_loan_interest_accrual/process_loan_interest_accrual_dashboard.py b/erpnext/loan_management/doctype/process_loan_interest_accrual/process_loan_interest_accrual_dashboard.py
index 243a7a3ba6..e104c6646b 100644
--- a/erpnext/loan_management/doctype/process_loan_interest_accrual/process_loan_interest_accrual_dashboard.py
+++ b/erpnext/loan_management/doctype/process_loan_interest_accrual/process_loan_interest_accrual_dashboard.py
@@ -9,4 +9,4 @@ def get_data():
'items': ['Loan Interest Accrual']
}
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/loan_management/doctype/process_loan_security_shortfall/process_loan_security_shortfall_dashboard.py b/erpnext/loan_management/doctype/process_loan_security_shortfall/process_loan_security_shortfall_dashboard.py
index dc9bd81a1d..e67e4d4738 100644
--- a/erpnext/loan_management/doctype/process_loan_security_shortfall/process_loan_security_shortfall_dashboard.py
+++ b/erpnext/loan_management/doctype/process_loan_security_shortfall/process_loan_security_shortfall_dashboard.py
@@ -9,4 +9,4 @@ def get_data():
'items': ['Loan Security Shortfall']
}
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/loan_management/loan_common.js b/erpnext/loan_management/loan_common.js
index 50b68da30e..43980ffef4 100644
--- a/erpnext/loan_management/loan_common.js
+++ b/erpnext/loan_management/loan_common.js
@@ -40,4 +40,4 @@ frappe.ui.form.on(cur_frm.doctype, {
frm.set_value("applicant_name", null);
}
}
-});
\ No newline at end of file
+});
diff --git a/erpnext/loan_management/report/applicant_wise_loan_security_exposure/applicant_wise_loan_security_exposure.py b/erpnext/loan_management/report/applicant_wise_loan_security_exposure/applicant_wise_loan_security_exposure.py
index 0ccd149e5f..f2cbbb469f 100644
--- a/erpnext/loan_management/report/applicant_wise_loan_security_exposure/applicant_wise_loan_security_exposure.py
+++ b/erpnext/loan_management/report/applicant_wise_loan_security_exposure/applicant_wise_loan_security_exposure.py
@@ -136,4 +136,4 @@ def get_applicant_wise_total_loan_security_qty(filters, loan_security_details):
total_value_map[security.applicant] += current_pledges.get((security.applicant, security.loan_security)) \
* loan_security_details.get(security.loan_security, {}).get('latest_price', 0)
- return current_pledges, total_value_map, applicant_type_map
\ No newline at end of file
+ return current_pledges, total_value_map, applicant_type_map
diff --git a/erpnext/loan_management/report/loan_interest_report/loan_interest_report.py b/erpnext/loan_management/report/loan_interest_report/loan_interest_report.py
index 2a74a1eb85..a505e72c4d 100644
--- a/erpnext/loan_management/report/loan_interest_report/loan_interest_report.py
+++ b/erpnext/loan_management/report/loan_interest_report/loan_interest_report.py
@@ -182,4 +182,4 @@ def get_loan_wise_security_value(filters, current_pledges):
loan_wise_security_value[key[0]] += \
flt(qty * loan_security_details.get(key[1], {}).get('latest_price', 0))
- return loan_wise_security_value
\ No newline at end of file
+ return loan_wise_security_value
diff --git a/erpnext/loan_management/report/loan_repayment_and_closure/loan_repayment_and_closure.py b/erpnext/loan_management/report/loan_repayment_and_closure/loan_repayment_and_closure.py
index c6f6b990cc..6591077088 100644
--- a/erpnext/loan_management/report/loan_repayment_and_closure/loan_repayment_and_closure.py
+++ b/erpnext/loan_management/report/loan_repayment_and_closure/loan_repayment_and_closure.py
@@ -126,4 +126,4 @@ def get_data(filters):
data.append(row)
- return data
\ No newline at end of file
+ return data
diff --git a/erpnext/loan_management/report/loan_security_exposure/loan_security_exposure.py b/erpnext/loan_management/report/loan_security_exposure/loan_security_exposure.py
index 887a86a46c..34bbe5a450 100644
--- a/erpnext/loan_management/report/loan_security_exposure/loan_security_exposure.py
+++ b/erpnext/loan_management/report/loan_security_exposure/loan_security_exposure.py
@@ -79,6 +79,3 @@ def get_company_wise_loan_security_details(filters, loan_security_details):
total_portfolio_value += flt(qty * loan_security_details.get(key[1], {}).get('latest_price', 0))
return security_wise_map, total_portfolio_value
-
-
-
diff --git a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js
index 546a68f268..d1a8c8de27 100644
--- a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js
+++ b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js
@@ -69,10 +69,10 @@ erpnext.maintenance.MaintenanceSchedule = class MaintenanceSchedule extends frap
if (flag) {
this.frm.add_custom_button(__('Maintenance Visit'), function () {
let options = "";
-
+
me.frm.call('get_pending_data', {data_type: "items"}).then(r => {
options = r.message;
-
+
let schedule_id = "";
let d = new frappe.ui.Dialog({
title: __("Enter Visit Details"),
@@ -86,7 +86,7 @@ erpnext.maintenance.MaintenanceSchedule = class MaintenanceSchedule extends frap
let field = d.get_field("scheduled_date");
me.frm.call('get_pending_data',
{
- item_name: this.value,
+ item_name: this.value,
data_type: "date"
}).then(r => {
field.df.options = r.message;
@@ -157,10 +157,9 @@ erpnext.maintenance.MaintenanceSchedule = class MaintenanceSchedule extends frap
let me = this;
if (item.start_date && item.periodicity) {
me.frm.call('validate_end_date_visits');
-
+
}
}
};
extend_cscript(cur_frm.cscript, new erpnext.maintenance.MaintenanceSchedule({frm: cur_frm}));
-
diff --git a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py
index d6e42f3ee1..97289032d7 100644
--- a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py
+++ b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py
@@ -52,15 +52,15 @@ class MaintenanceSchedule(TransactionBase):
item.end_date = add_days(item.start_date, item.no_of_visits * days_in_period[item.periodicity])
else:
item.end_date = add_days(item.start_date, days_in_period[item.periodicity])
-
+
diff = date_diff(item.end_date, item.start_date) + 1
no_of_visits = cint(diff / days_in_period[item.periodicity])
-
+
if not item.no_of_visits or item.no_of_visits == 0:
item.end_date = add_days(item.start_date, days_in_period[item.periodicity])
diff = date_diff(item.end_date, item.start_date) + 1
item.no_of_visits = cint(diff / days_in_period[item.periodicity])
-
+
elif item.no_of_visits > no_of_visits:
item.end_date = add_days(item.start_date, item.no_of_visits * days_in_period[item.periodicity])
@@ -207,7 +207,7 @@ class MaintenanceSchedule(TransactionBase):
def on_update(self):
frappe.db.set(self, 'status', 'Draft')
-
+
def update_amc_date(self, serial_nos, amc_expiry_date=None):
for serial_no in serial_nos:
serial_no_doc = frappe.get_doc("Serial No", serial_no)
@@ -300,7 +300,7 @@ class MaintenanceSchedule(TransactionBase):
for schedule in self.schedules:
if schedule.item_name == item_name and s_date == formatdate(schedule.scheduled_date, "dd-mm-yyyy"):
return schedule.name
-
+
@frappe.whitelist()
def update_serial_nos(s_id):
serial_nos = frappe.db.get_value('Maintenance Schedule Detail', s_id, 'serial_no')
@@ -318,12 +318,12 @@ def make_maintenance_visit(source_name, target_doc=None, item_name=None, s_id=No
target.maintenance_type = "Scheduled"
target.maintenance_schedule = source.name
target.maintenance_schedule_detail = s_id
-
+
def update_sales(source, target, parent):
sales_person = frappe.db.get_value('Maintenance Schedule Detail', s_id, 'sales_person')
target.service_person = sales_person
target.serial_no = ''
-
+
doclist = get_mapped_doc("Maintenance Schedule", source_name, {
"Maintenance Schedule": {
"doctype": "Maintenance Visit",
diff --git a/erpnext/maintenance/doctype/maintenance_schedule/test_maintenance_schedule.py b/erpnext/maintenance/doctype/maintenance_schedule/test_maintenance_schedule.py
index 09981bad05..c733dd0c92 100644
--- a/erpnext/maintenance/doctype/maintenance_schedule/test_maintenance_schedule.py
+++ b/erpnext/maintenance/doctype/maintenance_schedule/test_maintenance_schedule.py
@@ -22,7 +22,7 @@ class TestMaintenanceSchedule(unittest.TestCase):
ms.cancel()
events_after_cancel = get_events(ms)
self.assertTrue(len(events_after_cancel) == 0)
-
+
def test_make_schedule(self):
ms = make_maintenance_schedule()
ms.save()
@@ -72,7 +72,7 @@ class TestMaintenanceSchedule(unittest.TestCase):
#checks if visit status is back updated in schedule
self.assertTrue(ms.schedules[1].completion_status, "Partially Completed")
-
+
def get_events(ms):
return frappe.get_all("Event Participants", filters={
"reference_doctype": ms.doctype,
diff --git a/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.py b/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.py
index 7fffc942a0..d63c700387 100644
--- a/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.py
+++ b/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.py
@@ -28,11 +28,11 @@ class MaintenanceVisit(TransactionBase):
def validate(self):
self.validate_serial_no()
self.validate_maintenance_date()
-
+
def update_completion_status(self):
if self.maintenance_schedule_detail:
frappe.db.set_value('Maintenance Schedule Detail', self.maintenance_schedule_detail, 'completion_status', self.completion_status)
-
+
def update_actual_date(self):
if self.maintenance_schedule_detail:
frappe.db.set_value('Maintenance Schedule Detail', self.maintenance_schedule_detail, 'actual_date', self.mntc_date)
diff --git a/erpnext/manufacturing/doctype/blanket_order/blanket_order.js b/erpnext/manufacturing/doctype/blanket_order/blanket_order.js
index f19a1b0868..d3bb33e86e 100644
--- a/erpnext/manufacturing/doctype/blanket_order/blanket_order.js
+++ b/erpnext/manufacturing/doctype/blanket_order/blanket_order.js
@@ -85,5 +85,3 @@ frappe.ui.form.on('Blanket Order', {
frm.trigger('set_tc_name_filter');
}
});
-
-
diff --git a/erpnext/manufacturing/doctype/blanket_order/blanket_order.py b/erpnext/manufacturing/doctype/blanket_order/blanket_order.py
index d7556add80..1aedb1e590 100644
--- a/erpnext/manufacturing/doctype/blanket_order/blanket_order.py
+++ b/erpnext/manufacturing/doctype/blanket_order/blanket_order.py
@@ -76,4 +76,4 @@ def make_order(source_name):
"postprocess": update_item
}
})
- return target_doc
\ No newline at end of file
+ return target_doc
diff --git a/erpnext/manufacturing/doctype/blanket_order/test_blanket_order.py b/erpnext/manufacturing/doctype/blanket_order/test_blanket_order.py
index 3171defdae..9a0a72fb47 100644
--- a/erpnext/manufacturing/doctype/blanket_order/test_blanket_order.py
+++ b/erpnext/manufacturing/doctype/blanket_order/test_blanket_order.py
@@ -88,4 +88,4 @@ def make_blanket_order(**args):
bo.insert()
bo.submit()
- return bo
\ No newline at end of file
+ return bo
diff --git a/erpnext/manufacturing/doctype/bom/bom_item_preview.html b/erpnext/manufacturing/doctype/bom/bom_item_preview.html
index 6088e46265..e614a7ebaa 100644
--- a/erpnext/manufacturing/doctype/bom/bom_item_preview.html
+++ b/erpnext/manufacturing/doctype/bom/bom_item_preview.html
@@ -38,4 +38,4 @@
{{ __("Open Item {0}", [data.item_code.bold()]) }}
{% endif %}
-
\ No newline at end of file
+
diff --git a/erpnext/manufacturing/doctype/bom/bom_tree.js b/erpnext/manufacturing/doctype/bom/bom_tree.js
index 60fb377f47..6e2599e41b 100644
--- a/erpnext/manufacturing/doctype/bom/bom_tree.js
+++ b/erpnext/manufacturing/doctype/bom/bom_tree.js
@@ -70,4 +70,4 @@ frappe.treeview_settings["BOM"] = {
}
},
view_template: 'bom_item_preview'
-}
\ No newline at end of file
+}
diff --git a/erpnext/manufacturing/doctype/bom/test_bom.js b/erpnext/manufacturing/doctype/bom/test_bom.js
index 5044a28444..98a9198b79 100644
--- a/erpnext/manufacturing/doctype/bom/test_bom.js
+++ b/erpnext/manufacturing/doctype/bom/test_bom.js
@@ -60,4 +60,4 @@ QUnit.test("test: item", function (assert) {
() => done()
]);
-});
\ No newline at end of file
+});
diff --git a/erpnext/manufacturing/doctype/bom_explosion_item/bom_explosion_item.py b/erpnext/manufacturing/doctype/bom_explosion_item/bom_explosion_item.py
index cc5a3f8cb1..39ccbddbea 100644
--- a/erpnext/manufacturing/doctype/bom_explosion_item/bom_explosion_item.py
+++ b/erpnext/manufacturing/doctype/bom_explosion_item/bom_explosion_item.py
@@ -7,4 +7,4 @@ import frappe
from frappe.model.document import Document
class BOMExplosionItem(Document):
- pass
\ No newline at end of file
+ pass
diff --git a/erpnext/manufacturing/doctype/bom_item/bom_item.py b/erpnext/manufacturing/doctype/bom_item/bom_item.py
index e7cdea290b..220c73e149 100644
--- a/erpnext/manufacturing/doctype/bom_item/bom_item.py
+++ b/erpnext/manufacturing/doctype/bom_item/bom_item.py
@@ -7,4 +7,4 @@ import frappe
from frappe.model.document import Document
class BOMItem(Document):
- pass
\ No newline at end of file
+ pass
diff --git a/erpnext/manufacturing/doctype/bom_operation/bom_operation.py b/erpnext/manufacturing/doctype/bom_operation/bom_operation.py
index ee3f877da3..e3501eb9cf 100644
--- a/erpnext/manufacturing/doctype/bom_operation/bom_operation.py
+++ b/erpnext/manufacturing/doctype/bom_operation/bom_operation.py
@@ -7,4 +7,4 @@ import frappe
from frappe.model.document import Document
class BOMOperation(Document):
- pass
\ No newline at end of file
+ pass
diff --git a/erpnext/manufacturing/doctype/bom_update_tool/bom_update_tool.js b/erpnext/manufacturing/doctype/bom_update_tool/bom_update_tool.js
index e4b8a20288..bf5fe2e18d 100644
--- a/erpnext/manufacturing/doctype/bom_update_tool/bom_update_tool.js
+++ b/erpnext/manufacturing/doctype/bom_update_tool/bom_update_tool.js
@@ -46,4 +46,4 @@ frappe.ui.form.on('BOM Update Tool', {
}
});
}
-});
\ No newline at end of file
+});
diff --git a/erpnext/manufacturing/doctype/job_card/job_card.js b/erpnext/manufacturing/doctype/job_card/job_card.js
index 81860c9fbc..91eb4a0fa9 100644
--- a/erpnext/manufacturing/doctype/job_card/job_card.js
+++ b/erpnext/manufacturing/doctype/job_card/job_card.js
@@ -367,4 +367,4 @@ frappe.ui.form.on('Job Card Time Log', {
to_time: function(frm) {
frm.set_value('started_time', '');
}
-})
\ No newline at end of file
+})
diff --git a/erpnext/manufacturing/doctype/job_card/job_card_list.js b/erpnext/manufacturing/doctype/job_card/job_card_list.js
index ed851ebc83..8017209e7d 100644
--- a/erpnext/manufacturing/doctype/job_card/job_card_list.js
+++ b/erpnext/manufacturing/doctype/job_card/job_card_list.js
@@ -12,4 +12,4 @@ frappe.listview_settings['Job Card'] = {
return [__("Open"), "red", "status,=,Open"];
}
}
-};
\ No newline at end of file
+};
diff --git a/erpnext/manufacturing/doctype/job_card/test_job_card.py b/erpnext/manufacturing/doctype/job_card/test_job_card.py
index b6a6c33d37..8fa0b27fcb 100644
--- a/erpnext/manufacturing/doctype/job_card/test_job_card.py
+++ b/erpnext/manufacturing/doctype/job_card/test_job_card.py
@@ -72,4 +72,4 @@ class TestJobCard(unittest.TestCase):
doc.cancel()
for d in job_cards:
- frappe.delete_doc("Job Card", d.name)
\ No newline at end of file
+ frappe.delete_doc("Job Card", d.name)
diff --git a/erpnext/manufacturing/doctype/manufacturing_settings/manufacturing_settings.js b/erpnext/manufacturing/doctype/manufacturing_settings/manufacturing_settings.js
index 668e981d18..a0122a4738 100644
--- a/erpnext/manufacturing/doctype/manufacturing_settings/manufacturing_settings.js
+++ b/erpnext/manufacturing/doctype/manufacturing_settings/manufacturing_settings.js
@@ -30,4 +30,4 @@ frappe.tour["Manufacturing Settings"] = [
title: __("Update BOM Cost Automatically"),
description: __("If ticked, the BOM cost will be automatically updated based on Valuation Rate / Price List Rate / last purchase rate of raw materials.")
}
-];
\ No newline at end of file
+];
diff --git a/erpnext/manufacturing/doctype/manufacturing_settings/manufacturing_settings.py b/erpnext/manufacturing/doctype/manufacturing_settings/manufacturing_settings.py
index e88164f917..149fe3e22b 100644
--- a/erpnext/manufacturing/doctype/manufacturing_settings/manufacturing_settings.py
+++ b/erpnext/manufacturing/doctype/manufacturing_settings/manufacturing_settings.py
@@ -20,4 +20,4 @@ def is_material_consumption_enabled():
frappe.local.material_consumption = cint(frappe.db.get_single_value('Manufacturing Settings',
'material_consumption'))
- return frappe.local.material_consumption
\ No newline at end of file
+ return frappe.local.material_consumption
diff --git a/erpnext/manufacturing/doctype/operation/operation.js b/erpnext/manufacturing/doctype/operation/operation.js
index 102b6780e5..2936e33b11 100644
--- a/erpnext/manufacturing/doctype/operation/operation.js
+++ b/erpnext/manufacturing/doctype/operation/operation.js
@@ -11,4 +11,4 @@ frappe.ui.form.on('Operation', {
};
});
}
-});
\ No newline at end of file
+});
diff --git a/erpnext/manufacturing/doctype/operation/test_operation.py b/erpnext/manufacturing/doctype/operation/test_operation.py
index 0067231701..8e7e723726 100644
--- a/erpnext/manufacturing/doctype/operation/test_operation.py
+++ b/erpnext/manufacturing/doctype/operation/test_operation.py
@@ -28,4 +28,4 @@ def make_operation(*args, **kwargs):
return doc
except frappe.DuplicateEntryError:
- return frappe.get_doc("Operation", args.operation)
\ No newline at end of file
+ return frappe.get_doc("Operation", args.operation)
diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan_dashboard.py b/erpnext/manufacturing/doctype/production_plan/production_plan_dashboard.py
index ca597f6327..52a56af7bc 100644
--- a/erpnext/manufacturing/doctype/production_plan/production_plan_dashboard.py
+++ b/erpnext/manufacturing/doctype/production_plan/production_plan_dashboard.py
@@ -14,4 +14,4 @@ def get_data():
'items': ['Purchase Order']
},
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/manufacturing/doctype/production_plan_item/production_plan_item.py b/erpnext/manufacturing/doctype/production_plan_item/production_plan_item.py
index 8b570422dd..37cf5a49dc 100644
--- a/erpnext/manufacturing/doctype/production_plan_item/production_plan_item.py
+++ b/erpnext/manufacturing/doctype/production_plan_item/production_plan_item.py
@@ -7,4 +7,4 @@ import frappe
from frappe.model.document import Document
class ProductionPlanItem(Document):
- pass
\ No newline at end of file
+ pass
diff --git a/erpnext/manufacturing/doctype/production_plan_sales_order/production_plan_sales_order.py b/erpnext/manufacturing/doctype/production_plan_sales_order/production_plan_sales_order.py
index ef7f79e8d2..99c7273a64 100644
--- a/erpnext/manufacturing/doctype/production_plan_sales_order/production_plan_sales_order.py
+++ b/erpnext/manufacturing/doctype/production_plan_sales_order/production_plan_sales_order.py
@@ -7,4 +7,4 @@ import frappe
from frappe.model.document import Document
class ProductionPlanSalesOrder(Document):
- pass
\ No newline at end of file
+ pass
diff --git a/erpnext/manufacturing/doctype/routing/routing_dashboard.py b/erpnext/manufacturing/doctype/routing/routing_dashboard.py
index ab309cc9d5..50a3fe62da 100644
--- a/erpnext/manufacturing/doctype/routing/routing_dashboard.py
+++ b/erpnext/manufacturing/doctype/routing/routing_dashboard.py
@@ -9,4 +9,4 @@ def get_data():
'items': ['BOM']
}
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/manufacturing/doctype/work_order/work_order_dashboard.py b/erpnext/manufacturing/doctype/work_order/work_order_dashboard.py
index 9aa0715e7f..403d46d8d4 100644
--- a/erpnext/manufacturing/doctype/work_order/work_order_dashboard.py
+++ b/erpnext/manufacturing/doctype/work_order/work_order_dashboard.py
@@ -17,4 +17,4 @@ def get_data():
'items': ['Serial No', 'Batch']
}
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/manufacturing/doctype/work_order/work_order_preview.html b/erpnext/manufacturing/doctype/work_order/work_order_preview.html
index a4bf93edef..95bdd291ee 100644
--- a/erpnext/manufacturing/doctype/work_order/work_order_preview.html
+++ b/erpnext/manufacturing/doctype/work_order/work_order_preview.html
@@ -30,4 +30,4 @@
-
\ No newline at end of file
+
diff --git a/erpnext/manufacturing/doctype/work_order_item/work_order_item.py b/erpnext/manufacturing/doctype/work_order_item/work_order_item.py
index d18f028fc6..9aa53b5e3c 100644
--- a/erpnext/manufacturing/doctype/work_order_item/work_order_item.py
+++ b/erpnext/manufacturing/doctype/work_order_item/work_order_item.py
@@ -10,4 +10,4 @@ class WorkOrderItem(Document):
pass
def on_doctype_update():
- frappe.db.add_index("Work Order Item", ["item_code", "source_warehouse"])
\ No newline at end of file
+ frappe.db.add_index("Work Order Item", ["item_code", "source_warehouse"])
diff --git a/erpnext/manufacturing/doctype/workstation/workstation.js b/erpnext/manufacturing/doctype/workstation/workstation.js
index ba8e30cba0..d8d25fc6f8 100644
--- a/erpnext/manufacturing/doctype/workstation/workstation.js
+++ b/erpnext/manufacturing/doctype/workstation/workstation.js
@@ -16,4 +16,4 @@ frappe.ui.form.on("Workstation", {
})
}
}
-})
\ No newline at end of file
+})
diff --git a/erpnext/manufacturing/report/bom_operations_time/bom_operations_time.py b/erpnext/manufacturing/report/bom_operations_time/bom_operations_time.py
index e7d92658f7..8778d9ba55 100644
--- a/erpnext/manufacturing/report/bom_operations_time/bom_operations_time.py
+++ b/erpnext/manufacturing/report/bom_operations_time/bom_operations_time.py
@@ -108,5 +108,3 @@ def get_columns(filters):
"fieldtype": "Int",
"width": 180
}]
-
-
diff --git a/erpnext/manufacturing/report/bom_stock_report/bom_stock_report.html b/erpnext/manufacturing/report/bom_stock_report/bom_stock_report.html
index 119a4fc629..2ae8848cc0 100644
--- a/erpnext/manufacturing/report/bom_stock_report/bom_stock_report.html
+++ b/erpnext/manufacturing/report/bom_stock_report/bom_stock_report.html
@@ -24,4 +24,4 @@
{% } %}
-
\ No newline at end of file
+
diff --git a/erpnext/manufacturing/report/cost_of_poor_quality_report/cost_of_poor_quality_report.py b/erpnext/manufacturing/report/cost_of_poor_quality_report/cost_of_poor_quality_report.py
index 9f81e7d26a..b4db98c3d7 100644
--- a/erpnext/manufacturing/report/cost_of_poor_quality_report/cost_of_poor_quality_report.py
+++ b/erpnext/manufacturing/report/cost_of_poor_quality_report/cost_of_poor_quality_report.py
@@ -124,4 +124,4 @@ def get_columns(filters):
"fieldname": "total_time_in_mins",
"width": "100"
}
- ]
\ No newline at end of file
+ ]
diff --git a/erpnext/manufacturing/report/downtime_analysis/downtime_analysis.py b/erpnext/manufacturing/report/downtime_analysis/downtime_analysis.py
index 093309a005..74c794b5dd 100644
--- a/erpnext/manufacturing/report/downtime_analysis/downtime_analysis.py
+++ b/erpnext/manufacturing/report/downtime_analysis/downtime_analysis.py
@@ -110,4 +110,4 @@ def get_columns(filters):
"fieldtype": "Text",
"width": 100
}
- ]
\ No newline at end of file
+ ]
diff --git a/erpnext/manufacturing/report/exponential_smoothing_forecasting/exponential_smoothing_forecasting.py b/erpnext/manufacturing/report/exponential_smoothing_forecasting/exponential_smoothing_forecasting.py
index fc27d35598..9a6c764c60 100644
--- a/erpnext/manufacturing/report/exponential_smoothing_forecasting/exponential_smoothing_forecasting.py
+++ b/erpnext/manufacturing/report/exponential_smoothing_forecasting/exponential_smoothing_forecasting.py
@@ -239,4 +239,4 @@ class ForecastingReport(ExponentialSmoothingForecast):
"currency": self.company_currency,
"datatype": self.fieldtype
}
- ]
\ No newline at end of file
+ ]
diff --git a/erpnext/manufacturing/report/job_card_summary/job_card_summary.py b/erpnext/manufacturing/report/job_card_summary/job_card_summary.py
index b1bff3500c..a893905152 100644
--- a/erpnext/manufacturing/report/job_card_summary/job_card_summary.py
+++ b/erpnext/manufacturing/report/job_card_summary/job_card_summary.py
@@ -201,4 +201,4 @@ def get_columns(filters):
}
])
- return columns
\ No newline at end of file
+ return columns
diff --git a/erpnext/manufacturing/report/production_analytics/production_analytics.py b/erpnext/manufacturing/report/production_analytics/production_analytics.py
index 79af8a1e39..42c9d97cb5 100644
--- a/erpnext/manufacturing/report/production_analytics/production_analytics.py
+++ b/erpnext/manufacturing/report/production_analytics/production_analytics.py
@@ -139,7 +139,3 @@ def get_chart_data(periodic_data, columns):
chart["type"] = "line"
return chart
-
-
-
-
diff --git a/erpnext/manufacturing/report/quality_inspection_summary/quality_inspection_summary.py b/erpnext/manufacturing/report/quality_inspection_summary/quality_inspection_summary.py
index 6192632bda..a12ac7f9d9 100644
--- a/erpnext/manufacturing/report/quality_inspection_summary/quality_inspection_summary.py
+++ b/erpnext/manufacturing/report/quality_inspection_summary/quality_inspection_summary.py
@@ -129,4 +129,4 @@ def get_columns(filters):
}
])
- return columns
\ No newline at end of file
+ return columns
diff --git a/erpnext/manufacturing/report/work_order_stock_report/work_order_stock_report.py b/erpnext/manufacturing/report/work_order_stock_report/work_order_stock_report.py
index 97553e699d..599a738f6f 100644
--- a/erpnext/manufacturing/report/work_order_stock_report/work_order_stock_report.py
+++ b/erpnext/manufacturing/report/work_order_stock_report/work_order_stock_report.py
@@ -10,10 +10,10 @@ def execute(filters=None):
data = get_item_list(wo_list, filters)
columns = get_columns()
return columns, data
-
+
def get_item_list(wo_list, filters):
out = []
-
+
#Add a row for each item/qty
for wo_details in wo_list:
desc = frappe.db.get_value("BOM", wo_details.bom_no, "description")
@@ -70,13 +70,13 @@ def get_item_list(wo_list, filters):
out.append(row)
return out
-
+
def get_work_orders():
out = frappe.get_all("Work Order", filters={"docstatus": 1, "status": ( "!=","Completed")},
fields=["name","status", "bom_no", "qty", "produced_qty"], order_by='name')
return out
-
+
def get_columns():
columns = [{
"fieldname": "work_order",
diff --git a/erpnext/manufacturing/report/work_order_summary/work_order_summary.py b/erpnext/manufacturing/report/work_order_summary/work_order_summary.py
index 612dad0bf5..d0766f9abe 100644
--- a/erpnext/manufacturing/report/work_order_summary/work_order_summary.py
+++ b/erpnext/manufacturing/report/work_order_summary/work_order_summary.py
@@ -265,4 +265,4 @@ def get_columns(filters):
},
])
- return columns
\ No newline at end of file
+ return columns
diff --git a/erpnext/non_profit/doctype/chapter_member/chapter_member.py b/erpnext/non_profit/doctype/chapter_member/chapter_member.py
index c4b899913b..a1b25f2d4e 100644
--- a/erpnext/non_profit/doctype/chapter_member/chapter_member.py
+++ b/erpnext/non_profit/doctype/chapter_member/chapter_member.py
@@ -7,5 +7,3 @@ from frappe.model.document import Document
class ChapterMember(Document):
pass
-
-
diff --git a/erpnext/non_profit/doctype/donation/donation.py b/erpnext/non_profit/doctype/donation/donation.py
index 4fd1a30ab9..9aa7e13433 100644
--- a/erpnext/non_profit/doctype/donation/donation.py
+++ b/erpnext/non_profit/doctype/donation/donation.py
@@ -217,4 +217,3 @@ def notify_failure(log):
sendmail_to_system_managers(_('[Important] [ERPNext] Razorpay donation webhook failed, please check.'), content)
except Exception:
pass
-
diff --git a/erpnext/non_profit/doctype/donation/donation_dashboard.py b/erpnext/non_profit/doctype/donation/donation_dashboard.py
index 7e25c8d217..3da89423d3 100644
--- a/erpnext/non_profit/doctype/donation/donation_dashboard.py
+++ b/erpnext/non_profit/doctype/donation/donation_dashboard.py
@@ -13,4 +13,4 @@ def get_data():
'items': ['Payment Entry']
}
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/non_profit/doctype/donation/test_donation.py b/erpnext/non_profit/doctype/donation/test_donation.py
index bbe9bf5228..b206f54523 100644
--- a/erpnext/non_profit/doctype/donation/test_donation.py
+++ b/erpnext/non_profit/doctype/donation/test_donation.py
@@ -73,4 +73,4 @@ def create_mode_of_payment():
'company': '_Test Company',
'default_account': 'Cash - _TC'
}]
- }).insert()
\ No newline at end of file
+ }).insert()
diff --git a/erpnext/non_profit/doctype/donor/donor.py b/erpnext/non_profit/doctype/donor/donor.py
index fb70e59575..ab6a197ed5 100644
--- a/erpnext/non_profit/doctype/donor/donor.py
+++ b/erpnext/non_profit/doctype/donor/donor.py
@@ -15,4 +15,3 @@ class Donor(Document):
from frappe.utils import validate_email_address
if self.email:
validate_email_address(self.email.strip(), True)
-
diff --git a/erpnext/non_profit/doctype/grant_application/grant_application.py b/erpnext/non_profit/doctype/grant_application/grant_application.py
index f0123b2e49..b810fd027a 100644
--- a/erpnext/non_profit/doctype/grant_application/grant_application.py
+++ b/erpnext/non_profit/doctype/grant_application/grant_application.py
@@ -55,4 +55,4 @@ def send_grant_review_emails(grant_application):
grant.save()
frappe.db.commit()
- frappe.msgprint(_("Review Invitation Sent"))
\ No newline at end of file
+ frappe.msgprint(_("Review Invitation Sent"))
diff --git a/erpnext/non_profit/doctype/member/member.js b/erpnext/non_profit/doctype/member/member.js
index 6b8f1b1deb..e58ec0f5ee 100644
--- a/erpnext/non_profit/doctype/member/member.js
+++ b/erpnext/non_profit/doctype/member/member.js
@@ -61,4 +61,4 @@ frappe.ui.form.on('Member', {
}
});
}
-});
\ No newline at end of file
+});
diff --git a/erpnext/non_profit/doctype/membership/test_membership.py b/erpnext/non_profit/doctype/membership/test_membership.py
index 0f5a9bed82..5ad2088fc3 100644
--- a/erpnext/non_profit/doctype/membership/test_membership.py
+++ b/erpnext/non_profit/doctype/membership/test_membership.py
@@ -159,4 +159,4 @@ def get_subscription_payload():
}
}
}
- }
\ No newline at end of file
+ }
diff --git a/erpnext/non_profit/doctype/membership_type/membership_type.py b/erpnext/non_profit/doctype/membership_type/membership_type.py
index 022829bd3a..c712b99c3b 100644
--- a/erpnext/non_profit/doctype/membership_type/membership_type.py
+++ b/erpnext/non_profit/doctype/membership_type/membership_type.py
@@ -15,4 +15,4 @@ class MembershipType(Document):
frappe.throw(_("The Linked Item should be a service item"))
def get_membership_type(razorpay_id):
- return frappe.db.exists("Membership Type", {"razorpay_plan_id": razorpay_id})
\ No newline at end of file
+ return frappe.db.exists("Membership Type", {"razorpay_plan_id": razorpay_id})
diff --git a/erpnext/non_profit/doctype/non_profit_settings/non_profit_settings.py b/erpnext/non_profit/doctype/non_profit_settings/non_profit_settings.py
index a84cc2cdb5..50c93516ad 100644
--- a/erpnext/non_profit/doctype/non_profit_settings/non_profit_settings.py
+++ b/erpnext/non_profit/doctype/non_profit_settings/non_profit_settings.py
@@ -35,4 +35,4 @@ class NonProfitSettings(Document):
def get_plans_for_membership(*args, **kwargs):
controller = get_payment_gateway_controller("Razorpay")
plans = controller.get_plans()
- return [plan.get("item") for plan in plans.get("items")]
\ No newline at end of file
+ return [plan.get("item") for plan in plans.get("items")]
diff --git a/erpnext/non_profit/web_form/grant_application/grant_application.js b/erpnext/non_profit/web_form/grant_application/grant_application.js
index 7da3f1fb41..f09e540919 100644
--- a/erpnext/non_profit/web_form/grant_application/grant_application.js
+++ b/erpnext/non_profit/web_form/grant_application/grant_application.js
@@ -1,3 +1,3 @@
frappe.ready(function() {
// bind events here
-});
\ No newline at end of file
+});
diff --git a/erpnext/non_profit/web_form/grant_application/grant_application.py b/erpnext/non_profit/web_form/grant_application/grant_application.py
index 7666ef6b61..186722a8bf 100644
--- a/erpnext/non_profit/web_form/grant_application/grant_application.py
+++ b/erpnext/non_profit/web_form/grant_application/grant_application.py
@@ -4,5 +4,3 @@ def get_context(context):
context.no_cache = True
context.parents = [dict(label='View All ',
route='grant-application', title='View All')]
-
-
diff --git a/erpnext/patches/v10_0/migrate_daily_work_summary_settings_to_daily_work_summary_group.py b/erpnext/patches/v10_0/migrate_daily_work_summary_settings_to_daily_work_summary_group.py
index 102b6da875..daa258e882 100644
--- a/erpnext/patches/v10_0/migrate_daily_work_summary_settings_to_daily_work_summary_group.py
+++ b/erpnext/patches/v10_0/migrate_daily_work_summary_settings_to_daily_work_summary_group.py
@@ -48,4 +48,4 @@ def get_previous_setting():
return obj
def get_setting_companies():
- return frappe.db.sql("select * from `tabDaily Work Summary Settings Company`", as_dict=True)
\ No newline at end of file
+ return frappe.db.sql("select * from `tabDaily Work Summary Settings Company`", as_dict=True)
diff --git a/erpnext/patches/v10_0/rename_offer_letter_to_job_offer.py b/erpnext/patches/v10_0/rename_offer_letter_to_job_offer.py
index 2e3095153a..f832936b10 100644
--- a/erpnext/patches/v10_0/rename_offer_letter_to_job_offer.py
+++ b/erpnext/patches/v10_0/rename_offer_letter_to_job_offer.py
@@ -7,4 +7,4 @@ def execute():
frappe.rename_doc("DocType", "Offer Letter Term", "Job Offer Term", force=True)
frappe.reload_doc("hr", "doctype", "job_offer")
frappe.reload_doc("hr", "doctype", "job_offer_term")
- frappe.delete_doc("Print Format", "Offer Letter")
\ No newline at end of file
+ frappe.delete_doc("Print Format", "Offer Letter")
diff --git a/erpnext/patches/v10_0/rename_price_to_rate_in_pricing_rule.py b/erpnext/patches/v10_0/rename_price_to_rate_in_pricing_rule.py
index 48fa22204d..a9dd310310 100644
--- a/erpnext/patches/v10_0/rename_price_to_rate_in_pricing_rule.py
+++ b/erpnext/patches/v10_0/rename_price_to_rate_in_pricing_rule.py
@@ -11,4 +11,4 @@ def execute():
except Exception as e:
if e.args[0]!=1054:
- raise
\ No newline at end of file
+ raise
diff --git a/erpnext/patches/v11_0/add_default_email_template_for_leave.py b/erpnext/patches/v11_0/add_default_email_template_for_leave.py
index f722be26b4..0f1e496623 100644
--- a/erpnext/patches/v11_0/add_default_email_template_for_leave.py
+++ b/erpnext/patches/v11_0/add_default_email_template_for_leave.py
@@ -27,4 +27,3 @@ def execute():
'subject': _("Leave Status Notification"),
'owner': frappe.session.user,
}).insert(ignore_permissions=True)
-
diff --git a/erpnext/patches/v11_0/add_expense_claim_default_account.py b/erpnext/patches/v11_0/add_expense_claim_default_account.py
index eecf75568a..a613bd8849 100644
--- a/erpnext/patches/v11_0/add_expense_claim_default_account.py
+++ b/erpnext/patches/v11_0/add_expense_claim_default_account.py
@@ -8,4 +8,4 @@ def execute():
for company in companies:
if company.default_payable_account is not None:
- frappe.db.set_value("Company", company.name, "default_expense_claim_payable_account", company.default_payable_account)
\ No newline at end of file
+ frappe.db.set_value("Company", company.name, "default_expense_claim_payable_account", company.default_payable_account)
diff --git a/erpnext/patches/v11_0/add_healthcare_service_unit_tree_root.py b/erpnext/patches/v11_0/add_healthcare_service_unit_tree_root.py
index d956052f1a..a45f39d434 100644
--- a/erpnext/patches/v11_0/add_healthcare_service_unit_tree_root.py
+++ b/erpnext/patches/v11_0/add_healthcare_service_unit_tree_root.py
@@ -18,4 +18,3 @@ def execute():
'is_group': 1,
'company': company
}).insert(ignore_permissions=True)
-
diff --git a/erpnext/patches/v11_0/add_index_on_nestedset_doctypes.py b/erpnext/patches/v11_0/add_index_on_nestedset_doctypes.py
index 5a30c780f8..0243dfb38e 100644
--- a/erpnext/patches/v11_0/add_index_on_nestedset_doctypes.py
+++ b/erpnext/patches/v11_0/add_index_on_nestedset_doctypes.py
@@ -8,4 +8,4 @@ def execute():
frappe.reload_doc("assets", "doctype", "Location")
for dt in ("Account", "Cost Center", "File", "Employee", "Location", "Task", "Customer Group", "Sales Person", "Territory"):
frappe.reload_doctype(dt)
- frappe.get_doc("DocType", dt).run_module_method("on_doctype_update")
\ No newline at end of file
+ frappe.get_doc("DocType", dt).run_module_method("on_doctype_update")
diff --git a/erpnext/patches/v11_0/add_market_segments.py b/erpnext/patches/v11_0/add_market_segments.py
index ed47d4293f..a8841ef3a4 100644
--- a/erpnext/patches/v11_0/add_market_segments.py
+++ b/erpnext/patches/v11_0/add_market_segments.py
@@ -9,4 +9,4 @@ def execute():
frappe.local.lang = frappe.db.get_default("lang") or 'en'
- add_market_segments()
\ No newline at end of file
+ add_market_segments()
diff --git a/erpnext/patches/v11_0/add_sales_stages.py b/erpnext/patches/v11_0/add_sales_stages.py
index ac2ae1511a..d06c6889ff 100644
--- a/erpnext/patches/v11_0/add_sales_stages.py
+++ b/erpnext/patches/v11_0/add_sales_stages.py
@@ -8,4 +8,4 @@ def execute():
frappe.local.lang = frappe.db.get_default("lang") or 'en'
- add_sale_stages()
\ No newline at end of file
+ add_sale_stages()
diff --git a/erpnext/patches/v11_0/check_buying_selling_in_currency_exchange.py b/erpnext/patches/v11_0/check_buying_selling_in_currency_exchange.py
index 462f830c18..0a1a36007e 100644
--- a/erpnext/patches/v11_0/check_buying_selling_in_currency_exchange.py
+++ b/erpnext/patches/v11_0/check_buying_selling_in_currency_exchange.py
@@ -3,4 +3,4 @@ import frappe
def execute():
frappe.reload_doc('setup', 'doctype', 'currency_exchange')
- frappe.db.sql("""update `tabCurrency Exchange` set for_buying = 1, for_selling = 1""")
\ No newline at end of file
+ frappe.db.sql("""update `tabCurrency Exchange` set for_buying = 1, for_selling = 1""")
diff --git a/erpnext/patches/v11_0/create_salary_structure_assignments.py b/erpnext/patches/v11_0/create_salary_structure_assignments.py
index a908c16715..d3ea7a3c1c 100644
--- a/erpnext/patches/v11_0/create_salary_structure_assignments.py
+++ b/erpnext/patches/v11_0/create_salary_structure_assignments.py
@@ -69,4 +69,4 @@ def execute():
except DuplicateAssignment:
pass
- frappe.db.sql("update `tabSalary Structure` set docstatus=1")
\ No newline at end of file
+ frappe.db.sql("update `tabSalary Structure` set docstatus=1")
diff --git a/erpnext/patches/v11_0/drop_column_max_days_allowed.py b/erpnext/patches/v11_0/drop_column_max_days_allowed.py
index 591c521efb..029f75a225 100644
--- a/erpnext/patches/v11_0/drop_column_max_days_allowed.py
+++ b/erpnext/patches/v11_0/drop_column_max_days_allowed.py
@@ -4,4 +4,4 @@ import frappe
def execute():
if frappe.db.exists("DocType", "Leave Type"):
if 'max_days_allowed' in frappe.db.get_table_columns("Leave Type"):
- frappe.db.sql("alter table `tabLeave Type` drop column max_days_allowed")
\ No newline at end of file
+ frappe.db.sql("alter table `tabLeave Type` drop column max_days_allowed")
diff --git a/erpnext/patches/v11_0/ewaybill_fields_gst_india.py b/erpnext/patches/v11_0/ewaybill_fields_gst_india.py
index 9925b70a96..4247c788e3 100644
--- a/erpnext/patches/v11_0/ewaybill_fields_gst_india.py
+++ b/erpnext/patches/v11_0/ewaybill_fields_gst_india.py
@@ -7,4 +7,4 @@ def execute():
if not company:
return
- make_custom_fields()
\ No newline at end of file
+ make_custom_fields()
diff --git a/erpnext/patches/v11_0/hr_ux_cleanups.py b/erpnext/patches/v11_0/hr_ux_cleanups.py
index 80476c8a74..8d18796501 100644
--- a/erpnext/patches/v11_0/hr_ux_cleanups.py
+++ b/erpnext/patches/v11_0/hr_ux_cleanups.py
@@ -10,4 +10,3 @@ def execute():
for holiday_list in frappe.get_all('Holiday List'):
holiday_list = frappe.get_doc('Holiday List', holiday_list.name)
holiday_list.db_set('total_holidays', len(holiday_list.holidays), update_modified = False)
-
diff --git a/erpnext/patches/v11_0/make_asset_finance_book_against_old_entries.py b/erpnext/patches/v11_0/make_asset_finance_book_against_old_entries.py
index ee709ac2d4..dfcf5ab288 100644
--- a/erpnext/patches/v11_0/make_asset_finance_book_against_old_entries.py
+++ b/erpnext/patches/v11_0/make_asset_finance_book_against_old_entries.py
@@ -42,4 +42,4 @@ def execute():
'frequency_of_depreciation': asset_category_doc.frequency_of_depreciation
})
- row.db_update()
\ No newline at end of file
+ row.db_update()
diff --git a/erpnext/patches/v11_0/make_location_from_warehouse.py b/erpnext/patches/v11_0/make_location_from_warehouse.py
index a307e8c365..8c92b5180d 100644
--- a/erpnext/patches/v11_0/make_location_from_warehouse.py
+++ b/erpnext/patches/v11_0/make_location_from_warehouse.py
@@ -28,4 +28,3 @@ def execute():
def get_parent_warehouse_name(warehouse):
return frappe.db.get_value('Warehouse', warehouse, 'warehouse_name')
-
\ No newline at end of file
diff --git a/erpnext/patches/v11_0/move_item_defaults_to_child_table_for_multicompany.py b/erpnext/patches/v11_0/move_item_defaults_to_child_table_for_multicompany.py
index c7c7635540..6da70b4ce3 100644
--- a/erpnext/patches/v11_0/move_item_defaults_to_child_table_for_multicompany.py
+++ b/erpnext/patches/v11_0/move_item_defaults_to_child_table_for_multicompany.py
@@ -93,4 +93,4 @@ def execute():
`expense_account`, `income_account`, `buying_cost_center`, `selling_cost_center`
)
VALUES {}
- '''.format(', '.join(['%s'] * len(to_insert_data))), tuple(to_insert_data))
\ No newline at end of file
+ '''.format(', '.join(['%s'] * len(to_insert_data))), tuple(to_insert_data))
diff --git a/erpnext/patches/v11_0/move_leave_approvers_from_employee.py b/erpnext/patches/v11_0/move_leave_approvers_from_employee.py
index edab34cc58..ef703d0ea7 100644
--- a/erpnext/patches/v11_0/move_leave_approvers_from_employee.py
+++ b/erpnext/patches/v11_0/move_leave_approvers_from_employee.py
@@ -31,4 +31,4 @@ def execute():
if not len(department.leave_approvers):
department.append("leave_approvers",{
"approver": record.leave_approver
- }).db_insert()
\ No newline at end of file
+ }).db_insert()
diff --git a/erpnext/patches/v11_0/refactor_autoname_naming.py b/erpnext/patches/v11_0/refactor_autoname_naming.py
index b997ba2db2..dd5cb639b1 100644
--- a/erpnext/patches/v11_0/refactor_autoname_naming.py
+++ b/erpnext/patches/v11_0/refactor_autoname_naming.py
@@ -117,4 +117,4 @@ def get_series():
def get_series_to_preserve(doctype):
series_to_preserve = frappe.db.get_value('DocType', doctype, 'autoname')
- return series_to_preserve
\ No newline at end of file
+ return series_to_preserve
diff --git a/erpnext/patches/v11_0/refactor_naming_series.py b/erpnext/patches/v11_0/refactor_naming_series.py
index b85ab66f14..9f231edea7 100644
--- a/erpnext/patches/v11_0/refactor_naming_series.py
+++ b/erpnext/patches/v11_0/refactor_naming_series.py
@@ -132,4 +132,4 @@ def get_series_to_preserve(doctype):
def get_default_series(doctype):
field = frappe.get_meta(doctype).get_field("naming_series")
default_series = field.get('default', '') if field else ''
- return default_series
\ No newline at end of file
+ return default_series
diff --git a/erpnext/patches/v11_0/rename_asset_adjustment_doctype.py b/erpnext/patches/v11_0/rename_asset_adjustment_doctype.py
index fad0cf7a45..923b23048d 100644
--- a/erpnext/patches/v11_0/rename_asset_adjustment_doctype.py
+++ b/erpnext/patches/v11_0/rename_asset_adjustment_doctype.py
@@ -8,4 +8,4 @@ import frappe
def execute():
if frappe.db.table_exists("Asset Adjustment") and not frappe.db.table_exists("Asset Value Adjustment"):
frappe.rename_doc('DocType', 'Asset Adjustment', 'Asset Value Adjustment', force=True)
- frappe.reload_doc('assets', 'doctype', 'asset_value_adjustment')
\ No newline at end of file
+ frappe.reload_doc('assets', 'doctype', 'asset_value_adjustment')
diff --git a/erpnext/patches/v11_0/rename_bom_wo_fields.py b/erpnext/patches/v11_0/rename_bom_wo_fields.py
index 882ec84e64..0e6036b074 100644
--- a/erpnext/patches/v11_0/rename_bom_wo_fields.py
+++ b/erpnext/patches/v11_0/rename_bom_wo_fields.py
@@ -30,4 +30,4 @@ def execute():
else:
frappe.db.sql(""" UPDATE `tab%s`
SET transfer_material_against = 'Work Order'
- WHERE docstatus < 2""" % (doctype))
\ No newline at end of file
+ WHERE docstatus < 2""" % (doctype))
diff --git a/erpnext/patches/v11_0/rename_health_insurance.py b/erpnext/patches/v11_0/rename_health_insurance.py
index e605071a29..06fc615167 100644
--- a/erpnext/patches/v11_0/rename_health_insurance.py
+++ b/erpnext/patches/v11_0/rename_health_insurance.py
@@ -6,4 +6,4 @@ import frappe
def execute():
frappe.rename_doc('DocType', 'Health Insurance', 'Employee Health Insurance', force=True)
- frappe.reload_doc('hr', 'doctype', 'employee_health_insurance')
\ No newline at end of file
+ frappe.reload_doc('hr', 'doctype', 'employee_health_insurance')
diff --git a/erpnext/patches/v11_0/rename_overproduction_percent_field.py b/erpnext/patches/v11_0/rename_overproduction_percent_field.py
index 077829f481..fbf925d955 100644
--- a/erpnext/patches/v11_0/rename_overproduction_percent_field.py
+++ b/erpnext/patches/v11_0/rename_overproduction_percent_field.py
@@ -7,4 +7,4 @@ import frappe
def execute():
frappe.reload_doc('manufacturing', 'doctype', 'manufacturing_settings')
- rename_field('Manufacturing Settings', 'over_production_allowance_percentage', 'overproduction_percentage_for_sales_order')
\ No newline at end of file
+ rename_field('Manufacturing Settings', 'over_production_allowance_percentage', 'overproduction_percentage_for_sales_order')
diff --git a/erpnext/patches/v11_0/renamed_from_to_fields_in_project.py b/erpnext/patches/v11_0/renamed_from_to_fields_in_project.py
index 4f68440002..d5ca4cc574 100644
--- a/erpnext/patches/v11_0/renamed_from_to_fields_in_project.py
+++ b/erpnext/patches/v11_0/renamed_from_to_fields_in_project.py
@@ -10,4 +10,4 @@ def execute():
if frappe.db.has_column('Project', 'from'):
rename_field('Project', 'from', 'from_time')
- rename_field('Project', 'to', 'to_time')
\ No newline at end of file
+ rename_field('Project', 'to', 'to_time')
diff --git a/erpnext/patches/v11_0/set_missing_gst_hsn_code.py b/erpnext/patches/v11_0/set_missing_gst_hsn_code.py
index 4353ef80e2..8f8a545c41 100644
--- a/erpnext/patches/v11_0/set_missing_gst_hsn_code.py
+++ b/erpnext/patches/v11_0/set_missing_gst_hsn_code.py
@@ -41,4 +41,4 @@ def execute():
for t in list(parent):
trans_doc = frappe.get_doc(dt, t)
hsnwise_tax = get_itemised_tax_breakup_html(trans_doc)
- frappe.db.set_value(dt, t, "other_charges_calculation", hsnwise_tax, update_modified=False)
\ No newline at end of file
+ frappe.db.set_value(dt, t, "other_charges_calculation", hsnwise_tax, update_modified=False)
diff --git a/erpnext/patches/v11_0/set_salary_component_properties.py b/erpnext/patches/v11_0/set_salary_component_properties.py
index 2498888273..d8ce31f307 100644
--- a/erpnext/patches/v11_0/set_salary_component_properties.py
+++ b/erpnext/patches/v11_0/set_salary_component_properties.py
@@ -13,4 +13,4 @@ def execute():
frappe.db.sql("""update `tabSalary Detail` set is_tax_applicable=1
where parentfield='earnings' and statistical_component=0""")
frappe.db.sql("""update `tabSalary Detail` set variable_based_on_taxable_salary=1
- where parentfield='deductions' and salary_component in ('TDS', 'Tax Deducted at Source')""")
\ No newline at end of file
+ where parentfield='deductions' and salary_component in ('TDS', 'Tax Deducted at Source')""")
diff --git a/erpnext/patches/v11_0/set_user_permissions_for_department.py b/erpnext/patches/v11_0/set_user_permissions_for_department.py
index 7bd8577f9c..2f90f14db3 100644
--- a/erpnext/patches/v11_0/set_user_permissions_for_department.py
+++ b/erpnext/patches/v11_0/set_user_permissions_for_department.py
@@ -6,7 +6,7 @@ def execute():
where allow='Department'""", as_dict=1)
for d in user_permissions:
user_permission = frappe.get_doc("User Permission", d.name)
- for new_dept in frappe.db.sql("""select name from tabDepartment
+ for new_dept in frappe.db.sql("""select name from tabDepartment
where ifnull(company, '') != '' and department_name=%s""", d.for_value):
try:
new_user_permission = frappe.copy_doc(user_permission)
@@ -16,4 +16,4 @@ def execute():
pass
frappe.reload_doc("hr", "doctype", "department")
- frappe.db.sql("update tabDepartment set disabled=1 where ifnull(company, '') = ''")
\ No newline at end of file
+ frappe.db.sql("update tabDepartment set disabled=1 where ifnull(company, '') = ''")
diff --git a/erpnext/patches/v11_0/skip_user_permission_check_for_department.py b/erpnext/patches/v11_0/skip_user_permission_check_for_department.py
index 0f7fad7e49..4e72917547 100644
--- a/erpnext/patches/v11_0/skip_user_permission_check_for_department.py
+++ b/erpnext/patches/v11_0/skip_user_permission_check_for_department.py
@@ -58,4 +58,4 @@ def execute():
if user_permissions_to_delete:
frappe.db.sql('DELETE FROM `tabUser Permission` WHERE `name` IN ({})'.format( # nosec
','.join(['%s'] * len(user_permissions_to_delete))
- ), tuple(user_permissions_to_delete))
\ No newline at end of file
+ ), tuple(user_permissions_to_delete))
diff --git a/erpnext/patches/v11_0/update_account_type_in_party_type.py b/erpnext/patches/v11_0/update_account_type_in_party_type.py
index efa04fd2ce..dabaeffc94 100644
--- a/erpnext/patches/v11_0/update_account_type_in_party_type.py
+++ b/erpnext/patches/v11_0/update_account_type_in_party_type.py
@@ -10,4 +10,4 @@ def execute():
'Employee': 'Payable', 'Member': 'Receivable', 'Shareholder': 'Payable', 'Student': 'Receivable'}
for party_type, account_type in party_types.items():
- frappe.db.set_value('Party Type', party_type, 'account_type', account_type)
\ No newline at end of file
+ frappe.db.set_value('Party Type', party_type, 'account_type', account_type)
diff --git a/erpnext/patches/v11_0/update_allow_transfer_for_manufacture.py b/erpnext/patches/v11_0/update_allow_transfer_for_manufacture.py
index 1b58c97ea4..799e91a3e2 100644
--- a/erpnext/patches/v11_0/update_allow_transfer_for_manufacture.py
+++ b/erpnext/patches/v11_0/update_allow_transfer_for_manufacture.py
@@ -17,4 +17,4 @@ def execute():
child.include_item_in_manufacturing = 1
where
child.item_code = item.name and ifnull(item.is_stock_item, 0) = 1
- """.format(doctype))
\ No newline at end of file
+ """.format(doctype))
diff --git a/erpnext/patches/v11_0/update_backflush_subcontract_rm_based_on_bom.py b/erpnext/patches/v11_0/update_backflush_subcontract_rm_based_on_bom.py
index f2eeadac60..37a616c702 100644
--- a/erpnext/patches/v11_0/update_backflush_subcontract_rm_based_on_bom.py
+++ b/erpnext/patches/v11_0/update_backflush_subcontract_rm_based_on_bom.py
@@ -16,4 +16,4 @@ def execute():
where
se.purpose = 'Send to Subcontractor' and sed.parent = se.name
and pois.rm_item_code = sed.item_code and se.docstatus = 1
- and pois.parenttype = 'Purchase Order'""")
\ No newline at end of file
+ and pois.parenttype = 'Purchase Order'""")
diff --git a/erpnext/patches/v11_0/update_brand_in_item_price.py b/erpnext/patches/v11_0/update_brand_in_item_price.py
index a8d3fab481..977d84fefe 100644
--- a/erpnext/patches/v11_0/update_brand_in_item_price.py
+++ b/erpnext/patches/v11_0/update_brand_in_item_price.py
@@ -12,4 +12,4 @@ def execute():
`tabItem Price`.brand = `tabItem`.brand
where
`tabItem Price`.item_code = `tabItem`.name
- and `tabItem`.brand is not null and `tabItem`.brand != ''""")
\ No newline at end of file
+ and `tabItem`.brand is not null and `tabItem`.brand != ''""")
diff --git a/erpnext/patches/v11_0/update_department_lft_rgt.py b/erpnext/patches/v11_0/update_department_lft_rgt.py
index b2f407b18e..2b38203710 100644
--- a/erpnext/patches/v11_0/update_department_lft_rgt.py
+++ b/erpnext/patches/v11_0/update_department_lft_rgt.py
@@ -17,4 +17,4 @@ def execute():
frappe.db.sql("""update `tabDepartment` set parent_department = '{0}'
where is_group = 0""".format(_('All Departments')))
- rebuild_tree("Department", "parent_department")
\ No newline at end of file
+ rebuild_tree("Department", "parent_department")
diff --git a/erpnext/patches/v11_1/delete_bom_browser.py b/erpnext/patches/v11_1/delete_bom_browser.py
index 457f511667..2892674d37 100644
--- a/erpnext/patches/v11_1/delete_bom_browser.py
+++ b/erpnext/patches/v11_1/delete_bom_browser.py
@@ -5,4 +5,4 @@ from __future__ import unicode_literals
import frappe
def execute():
- frappe.delete_doc_if_exists('Page', 'bom-browser')
\ No newline at end of file
+ frappe.delete_doc_if_exists('Page', 'bom-browser')
diff --git a/erpnext/patches/v11_1/make_job_card_time_logs.py b/erpnext/patches/v11_1/make_job_card_time_logs.py
index 6e708df48d..b706e5c1ff 100644
--- a/erpnext/patches/v11_1/make_job_card_time_logs.py
+++ b/erpnext/patches/v11_1/make_job_card_time_logs.py
@@ -26,4 +26,4 @@ def execute():
frappe.reload_doc('manufacturing', 'doctype', 'job_card')
frappe.db.sql(""" update `tabJob Card` set total_completed_qty = for_quantity,
- total_time_in_mins = time_in_mins where docstatus < 2 """)
\ No newline at end of file
+ total_time_in_mins = time_in_mins where docstatus < 2 """)
diff --git a/erpnext/patches/v11_1/move_customer_lead_to_dynamic_column.py b/erpnext/patches/v11_1/move_customer_lead_to_dynamic_column.py
index 5b1251c31c..fc3ec74083 100644
--- a/erpnext/patches/v11_1/move_customer_lead_to_dynamic_column.py
+++ b/erpnext/patches/v11_1/move_customer_lead_to_dynamic_column.py
@@ -11,4 +11,4 @@ def execute():
frappe.reload_doctype("Opportunity")
frappe.db.sql(""" UPDATE `tabOpportunity` set party_name = lead WHERE opportunity_from = 'Lead' """)
- frappe.db.sql(""" UPDATE `tabOpportunity` set party_name = customer WHERE opportunity_from = 'Customer' """)
\ No newline at end of file
+ frappe.db.sql(""" UPDATE `tabOpportunity` set party_name = customer WHERE opportunity_from = 'Customer' """)
diff --git a/erpnext/patches/v11_1/rename_depends_on_lwp.py b/erpnext/patches/v11_1/rename_depends_on_lwp.py
index a0f2536f7d..4c4b14fd4e 100644
--- a/erpnext/patches/v11_1/rename_depends_on_lwp.py
+++ b/erpnext/patches/v11_1/rename_depends_on_lwp.py
@@ -10,4 +10,4 @@ def execute():
for doctype in ("Salary Component", "Salary Detail"):
if "depends_on_lwp" in frappe.db.get_table_columns(doctype):
frappe.reload_doc("Payroll", "doctype", scrub(doctype))
- rename_field(doctype, "depends_on_lwp", "depends_on_payment_days")
\ No newline at end of file
+ rename_field(doctype, "depends_on_lwp", "depends_on_payment_days")
diff --git a/erpnext/patches/v11_1/renamed_delayed_item_report.py b/erpnext/patches/v11_1/renamed_delayed_item_report.py
index 222b9a0b17..8e8725c8af 100644
--- a/erpnext/patches/v11_1/renamed_delayed_item_report.py
+++ b/erpnext/patches/v11_1/renamed_delayed_item_report.py
@@ -7,4 +7,4 @@ import frappe
def execute():
for report in ["Delayed Order Item Summary", "Delayed Order Summary"]:
if frappe.db.exists("Report", report):
- frappe.delete_doc("Report", report)
\ No newline at end of file
+ frappe.delete_doc("Report", report)
diff --git a/erpnext/patches/v11_1/set_status_for_material_request_type_manufacture.py b/erpnext/patches/v11_1/set_status_for_material_request_type_manufacture.py
index d41cff523d..ec01fbb642 100644
--- a/erpnext/patches/v11_1/set_status_for_material_request_type_manufacture.py
+++ b/erpnext/patches/v11_1/set_status_for_material_request_type_manufacture.py
@@ -6,4 +6,4 @@ def execute():
update `tabMaterial Request`
set status='Manufactured'
where docstatus=1 and material_request_type='Manufacture' and per_ordered=100 and status != 'Stopped'
- """)
\ No newline at end of file
+ """)
diff --git a/erpnext/patches/v11_1/set_variant_based_on.py b/erpnext/patches/v11_1/set_variant_based_on.py
index 019eefd68f..49a9a17724 100644
--- a/erpnext/patches/v11_1/set_variant_based_on.py
+++ b/erpnext/patches/v11_1/set_variant_based_on.py
@@ -8,4 +8,4 @@ def execute():
frappe.db.sql("""update tabItem set variant_based_on = 'Item Attribute'
where ifnull(variant_based_on, '') = ''
and (has_variants=1 or ifnull(variant_of, '') != '')
- """)
\ No newline at end of file
+ """)
diff --git a/erpnext/patches/v11_1/update_bank_transaction_status.py b/erpnext/patches/v11_1/update_bank_transaction_status.py
index 544bc5e691..354e636c9b 100644
--- a/erpnext/patches/v11_1/update_bank_transaction_status.py
+++ b/erpnext/patches/v11_1/update_bank_transaction_status.py
@@ -23,4 +23,4 @@ def execute():
WHERE
status = 'Settled' and (deposit = allocated_amount or withdrawal = allocated_amount)
and ifnull(allocated_amount, 0) > 0
- """)
\ No newline at end of file
+ """)
diff --git a/erpnext/patches/v11_1/update_default_supplier_in_item_defaults.py b/erpnext/patches/v11_1/update_default_supplier_in_item_defaults.py
index 347dec1f74..8c360ad935 100644
--- a/erpnext/patches/v11_1/update_default_supplier_in_item_defaults.py
+++ b/erpnext/patches/v11_1/update_default_supplier_in_item_defaults.py
@@ -22,4 +22,4 @@ def execute():
SET `tabItem Default`.default_supplier = `tabItem`.default_supplier
WHERE
`tabItem Default`.parent = `tabItem`.name and `tabItem Default`.default_supplier is null
- and `tabItem`.default_supplier is not null and `tabItem`.default_supplier != '' """)
\ No newline at end of file
+ and `tabItem`.default_supplier is not null and `tabItem`.default_supplier != '' """)
diff --git a/erpnext/patches/v11_1/woocommerce_set_creation_user.py b/erpnext/patches/v11_1/woocommerce_set_creation_user.py
index 5ccdec6d26..074b904002 100644
--- a/erpnext/patches/v11_1/woocommerce_set_creation_user.py
+++ b/erpnext/patches/v11_1/woocommerce_set_creation_user.py
@@ -8,4 +8,4 @@ def execute():
if cint(doc.enable_sync):
doc.creation_user = doc.modified_by
- doc.save(ignore_permissions=True)
\ No newline at end of file
+ doc.save(ignore_permissions=True)
diff --git a/erpnext/patches/v12_0/add_company_link_to_einvoice_settings.py b/erpnext/patches/v12_0/add_company_link_to_einvoice_settings.py
index b6bd5fa311..c2ed6c288f 100644
--- a/erpnext/patches/v12_0/add_company_link_to_einvoice_settings.py
+++ b/erpnext/patches/v12_0/add_company_link_to_einvoice_settings.py
@@ -13,4 +13,4 @@ def execute():
where a.gstin = %s and dl.parent = a.name and dl.link_doctype = 'Company'
""", (creds.get('gstin')))
if company_name and len(company_name) > 0:
- frappe.db.set_value('E Invoice User', creds.get('name'), 'company', company_name[0][0])
\ No newline at end of file
+ frappe.db.set_value('E Invoice User', creds.get('name'), 'company', company_name[0][0])
diff --git a/erpnext/patches/v12_0/add_default_buying_selling_terms_in_company.py b/erpnext/patches/v12_0/add_default_buying_selling_terms_in_company.py
index 484f81a7ac..855d21dd99 100644
--- a/erpnext/patches/v12_0/add_default_buying_selling_terms_in_company.py
+++ b/erpnext/patches/v12_0/add_default_buying_selling_terms_in_company.py
@@ -14,6 +14,6 @@ def execute():
for company in frappe.get_all("Company", ["name", "default_selling_terms", "default_buying_terms"]):
if company.default_selling_terms and not company.default_buying_terms:
frappe.db.set_value("Company", company.name, "default_buying_terms", company.default_selling_terms)
-
+
frappe.reload_doc("setup", "doctype", "terms_and_conditions")
frappe.db.sql("update `tabTerms and Conditions` set selling=1, buying=1, hr=1")
diff --git a/erpnext/patches/v12_0/add_document_type_field_for_italy_einvoicing.py b/erpnext/patches/v12_0/add_document_type_field_for_italy_einvoicing.py
index 4d649dd0f0..6fe578dbd9 100644
--- a/erpnext/patches/v12_0/add_document_type_field_for_italy_einvoicing.py
+++ b/erpnext/patches/v12_0/add_document_type_field_for_italy_einvoicing.py
@@ -15,4 +15,4 @@ def execute():
]
}
- create_custom_fields(custom_fields, update=True)
\ No newline at end of file
+ create_custom_fields(custom_fields, update=True)
diff --git a/erpnext/patches/v12_0/add_einvoice_status_field.py b/erpnext/patches/v12_0/add_einvoice_status_field.py
index 387e88588d..2dfd30714c 100644
--- a/erpnext/patches/v12_0/add_einvoice_status_field.py
+++ b/erpnext/patches/v12_0/add_einvoice_status_field.py
@@ -13,13 +13,13 @@ def execute():
'Sales Invoice': [
dict(fieldname='einvoice_section', label='E-Invoice Fields', fieldtype='Section Break', insert_after='gst_vehicle_type',
print_hide=1, hidden=1),
-
+
dict(fieldname='ack_no', label='Ack. No.', fieldtype='Data', read_only=1, hidden=1, insert_after='einvoice_section',
no_copy=1, print_hide=1),
-
+
dict(fieldname='ack_date', label='Ack. Date', fieldtype='Data', read_only=1, hidden=1, insert_after='ack_no', no_copy=1, print_hide=1),
- dict(fieldname='irn_cancel_date', label='Cancel Date', fieldtype='Data', read_only=1, hidden=1, insert_after='ack_date',
+ dict(fieldname='irn_cancel_date', label='Cancel Date', fieldtype='Data', read_only=1, hidden=1, insert_after='ack_date',
no_copy=1, print_hide=1),
dict(fieldname='signed_einvoice', label='Signed E-Invoice', fieldtype='Code', options='JSON', hidden=1, insert_after='irn_cancel_date',
@@ -66,4 +66,4 @@ def execute():
if signed_einvoice:
signed_einvoice = json.loads(signed_einvoice)
frappe.db.set_value('Sales Invoice', inv.get('name'), 'ack_no', signed_einvoice.get('AckNo'), update_modified=False)
- frappe.db.set_value('Sales Invoice', inv.get('name'), 'ack_date', signed_einvoice.get('AckDt'), update_modified=False)
\ No newline at end of file
+ frappe.db.set_value('Sales Invoice', inv.get('name'), 'ack_date', signed_einvoice.get('AckDt'), update_modified=False)
diff --git a/erpnext/patches/v12_0/add_einvoice_summary_report_permissions.py b/erpnext/patches/v12_0/add_einvoice_summary_report_permissions.py
index bf8f566d32..c1c11e2600 100644
--- a/erpnext/patches/v12_0/add_einvoice_summary_report_permissions.py
+++ b/erpnext/patches/v12_0/add_einvoice_summary_report_permissions.py
@@ -15,4 +15,4 @@ def execute():
dict(role='Accounts User'),
dict(role='Accounts Manager')
]
- )).insert()
\ No newline at end of file
+ )).insert()
diff --git a/erpnext/patches/v12_0/add_eway_bill_in_delivery_note.py b/erpnext/patches/v12_0/add_eway_bill_in_delivery_note.py
index bb4b0380f8..cf1ed3676b 100644
--- a/erpnext/patches/v12_0/add_eway_bill_in_delivery_note.py
+++ b/erpnext/patches/v12_0/add_eway_bill_in_delivery_note.py
@@ -16,4 +16,4 @@ def execute():
'insert_after': 'customer_name_in_arabic',
'translatable': 0,
'owner': 'Administrator'
- })
\ No newline at end of file
+ })
diff --git a/erpnext/patches/v12_0/add_ewaybill_validity_field.py b/erpnext/patches/v12_0/add_ewaybill_validity_field.py
index 87d98f1a56..f29b71437e 100644
--- a/erpnext/patches/v12_0/add_ewaybill_validity_field.py
+++ b/erpnext/patches/v12_0/add_ewaybill_validity_field.py
@@ -13,4 +13,4 @@ def execute():
depends_on='ewaybill', read_only=1, allow_on_submit=1, insert_after='ewaybill')
]
}
- create_custom_fields(custom_fields, update=True)
\ No newline at end of file
+ create_custom_fields(custom_fields, update=True)
diff --git a/erpnext/patches/v12_0/add_export_type_field_in_party_master.py b/erpnext/patches/v12_0/add_export_type_field_in_party_master.py
index 5bb6e3fb33..a0b1f87d61 100644
--- a/erpnext/patches/v12_0/add_export_type_field_in_party_master.py
+++ b/erpnext/patches/v12_0/add_export_type_field_in_party_master.py
@@ -38,5 +38,3 @@ def execute():
WHERE fieldname = 'is_inter_state'
AND dt IN ('Sales Taxes and Charges Template', 'Purchase Taxes and Charges Template')
""")
-
-
diff --git a/erpnext/patches/v12_0/add_gst_category_in_delivery_note.py b/erpnext/patches/v12_0/add_gst_category_in_delivery_note.py
index 1208222504..c90819238c 100644
--- a/erpnext/patches/v12_0/add_gst_category_in_delivery_note.py
+++ b/erpnext/patches/v12_0/add_gst_category_in_delivery_note.py
@@ -16,4 +16,4 @@ def execute():
]
}
- create_custom_fields(custom_fields, update=True)
\ No newline at end of file
+ create_custom_fields(custom_fields, update=True)
diff --git a/erpnext/patches/v12_0/add_item_name_in_work_orders.py b/erpnext/patches/v12_0/add_item_name_in_work_orders.py
index 485dd314a1..d765b93d21 100644
--- a/erpnext/patches/v12_0/add_item_name_in_work_orders.py
+++ b/erpnext/patches/v12_0/add_item_name_in_work_orders.py
@@ -11,4 +11,4 @@ def execute():
SET
wo.item_name = item.item_name
""")
- frappe.db.commit()
\ No newline at end of file
+ frappe.db.commit()
diff --git a/erpnext/patches/v12_0/add_permission_in_lower_deduction.py b/erpnext/patches/v12_0/add_permission_in_lower_deduction.py
index af9bf74f30..2e42368b15 100644
--- a/erpnext/patches/v12_0/add_permission_in_lower_deduction.py
+++ b/erpnext/patches/v12_0/add_permission_in_lower_deduction.py
@@ -10,4 +10,4 @@ def execute():
add_permission('Lower Deduction Certificate', 'Accounts Manager', 0)
update_permission_property('Lower Deduction Certificate', 'Accounts Manager', 0, 'write', 1)
- update_permission_property('Lower Deduction Certificate', 'Accounts Manager', 0, 'create', 1)
\ No newline at end of file
+ update_permission_property('Lower Deduction Certificate', 'Accounts Manager', 0, 'create', 1)
diff --git a/erpnext/patches/v12_0/create_accounting_dimensions_in_missing_doctypes.py b/erpnext/patches/v12_0/create_accounting_dimensions_in_missing_doctypes.py
index 657decfed2..f171542df1 100644
--- a/erpnext/patches/v12_0/create_accounting_dimensions_in_missing_doctypes.py
+++ b/erpnext/patches/v12_0/create_accounting_dimensions_in_missing_doctypes.py
@@ -39,4 +39,4 @@ def execute():
create_custom_field(doctype, df)
frappe.clear_cache(doctype=doctype)
- count += 1
\ No newline at end of file
+ count += 1
diff --git a/erpnext/patches/v12_0/create_default_energy_point_rules.py b/erpnext/patches/v12_0/create_default_energy_point_rules.py
index 88233b4cf7..93d2576bb6 100644
--- a/erpnext/patches/v12_0/create_default_energy_point_rules.py
+++ b/erpnext/patches/v12_0/create_default_energy_point_rules.py
@@ -3,4 +3,4 @@ from erpnext.setup.install import create_default_energy_point_rules
def execute():
frappe.reload_doc('social', 'doctype', 'energy_point_rule')
- create_default_energy_point_rules()
\ No newline at end of file
+ create_default_energy_point_rules()
diff --git a/erpnext/patches/v12_0/create_irs_1099_field_united_states.py b/erpnext/patches/v12_0/create_irs_1099_field_united_states.py
index 7feaffdf40..23a8f24d78 100644
--- a/erpnext/patches/v12_0/create_irs_1099_field_united_states.py
+++ b/erpnext/patches/v12_0/create_irs_1099_field_united_states.py
@@ -13,4 +13,4 @@ def execute():
if not company:
return
- make_custom_fields()
\ No newline at end of file
+ make_custom_fields()
diff --git a/erpnext/patches/v12_0/create_itc_reversal_custom_fields.py b/erpnext/patches/v12_0/create_itc_reversal_custom_fields.py
index 0078a53cd6..a6230f4277 100644
--- a/erpnext/patches/v12_0/create_itc_reversal_custom_fields.py
+++ b/erpnext/patches/v12_0/create_itc_reversal_custom_fields.py
@@ -112,4 +112,4 @@ def execute():
'itc_central_tax': values.get('itc_central_tax'),
'itc_state_tax': values['itc_state_tax'],
'itc_cess_amount': values['itc_cess_amount'],
- })
\ No newline at end of file
+ })
diff --git a/erpnext/patches/v12_0/create_taxable_value_field.py b/erpnext/patches/v12_0/create_taxable_value_field.py
index a0c9fcf4cb..b9ee81df50 100644
--- a/erpnext/patches/v12_0/create_taxable_value_field.py
+++ b/erpnext/patches/v12_0/create_taxable_value_field.py
@@ -15,4 +15,4 @@ def execute():
]
}
- create_custom_fields(custom_fields, update=True)
\ No newline at end of file
+ create_custom_fields(custom_fields, update=True)
diff --git a/erpnext/patches/v12_0/delete_priority_property_setter.py b/erpnext/patches/v12_0/delete_priority_property_setter.py
index 5927267543..163855729d 100644
--- a/erpnext/patches/v12_0/delete_priority_property_setter.py
+++ b/erpnext/patches/v12_0/delete_priority_property_setter.py
@@ -6,4 +6,4 @@ def execute():
WHERE `tabProperty Setter`.doc_type='Issue'
AND `tabProperty Setter`.field_name='priority'
AND `tabProperty Setter`.property='options'
- """)
\ No newline at end of file
+ """)
diff --git a/erpnext/patches/v12_0/fix_quotation_expired_status.py b/erpnext/patches/v12_0/fix_quotation_expired_status.py
index c8708d8013..ac7e82d2d0 100644
--- a/erpnext/patches/v12_0/fix_quotation_expired_status.py
+++ b/erpnext/patches/v12_0/fix_quotation_expired_status.py
@@ -6,23 +6,23 @@ def execute():
# filter out submitted expired quotations which has sales order created
cond = "qo.docstatus = 1 and qo.status = 'Expired'"
invalid_so_against_quo = """
- SELECT
+ SELECT
so.name FROM `tabSales Order` so, `tabSales Order Item` so_item
- WHERE
+ WHERE
so_item.docstatus = 1 and so.docstatus = 1
and so_item.parent = so.name
and so_item.prevdoc_docname = qo.name
and qo.valid_till < so.transaction_date""" # check if SO was created after quotation expired
-
+
frappe.db.sql(
"""UPDATE `tabQuotation` qo SET qo.status = 'Expired' WHERE {cond} and exists({invalid_so_against_quo})"""
.format(cond=cond, invalid_so_against_quo=invalid_so_against_quo)
)
-
+
valid_so_against_quo = """
- SELECT
+ SELECT
so.name FROM `tabSales Order` so, `tabSales Order Item` so_item
- WHERE
+ WHERE
so_item.docstatus = 1 and so.docstatus = 1
and so_item.parent = so.name
and so_item.prevdoc_docname = qo.name
diff --git a/erpnext/patches/v12_0/move_target_distribution_from_parent_to_child.py b/erpnext/patches/v12_0/move_target_distribution_from_parent_to_child.py
index 548c1a4717..97badf355d 100644
--- a/erpnext/patches/v12_0/move_target_distribution_from_parent_to_child.py
+++ b/erpnext/patches/v12_0/move_target_distribution_from_parent_to_child.py
@@ -19,4 +19,4 @@ def execute():
frappe.delete_doc("Report", "Sales Partner-wise Transaction Summary")
frappe.delete_doc("Report", "Sales Person Target Variance Item Group-Wise")
- frappe.delete_doc("Report", "Territory Target Variance Item Group-Wise")
\ No newline at end of file
+ frappe.delete_doc("Report", "Territory Target Variance Item Group-Wise")
diff --git a/erpnext/patches/v12_0/recalculate_requested_qty_in_bin.py b/erpnext/patches/v12_0/recalculate_requested_qty_in_bin.py
index 8267df95e1..46794bebe7 100644
--- a/erpnext/patches/v12_0/recalculate_requested_qty_in_bin.py
+++ b/erpnext/patches/v12_0/recalculate_requested_qty_in_bin.py
@@ -10,4 +10,4 @@ def execute():
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/patches/v12_0/remove_bank_remittance_custom_fields.py b/erpnext/patches/v12_0/remove_bank_remittance_custom_fields.py
index d1446b3227..be884f94d1 100644
--- a/erpnext/patches/v12_0/remove_bank_remittance_custom_fields.py
+++ b/erpnext/patches/v12_0/remove_bank_remittance_custom_fields.py
@@ -11,4 +11,4 @@ def execute():
if frappe.db.exists("Custom Field", "Company-bank_remittance_section"):
deprecated_fields = ['bank_remittance_section', 'client_code', 'remittance_column_break', 'product_code']
for i in range(len(deprecated_fields)):
- frappe.delete_doc("Custom Field", 'Company-'+deprecated_fields[i])
\ No newline at end of file
+ frappe.delete_doc("Custom Field", 'Company-'+deprecated_fields[i])
diff --git a/erpnext/patches/v12_0/remove_denied_leaves_from_leave_ledger.py b/erpnext/patches/v12_0/remove_denied_leaves_from_leave_ledger.py
index 7859606e5c..4fcffb702a 100644
--- a/erpnext/patches/v12_0/remove_denied_leaves_from_leave_ledger.py
+++ b/erpnext/patches/v12_0/remove_denied_leaves_from_leave_ledger.py
@@ -25,4 +25,4 @@ def delete_denied_leaves_from_leave_ledger_entry(leave_application_list):
WHERE
transaction_type = 'Leave Application'
AND transaction_name in (%s) ''' % (', '.join(['%s'] * len(leave_application_list))), #nosec
- tuple(leave_application_list))
\ No newline at end of file
+ tuple(leave_application_list))
diff --git a/erpnext/patches/v12_0/remove_duplicate_leave_ledger_entries.py b/erpnext/patches/v12_0/remove_duplicate_leave_ledger_entries.py
index 24286dcebf..6b1b601db1 100644
--- a/erpnext/patches/v12_0/remove_duplicate_leave_ledger_entries.py
+++ b/erpnext/patches/v12_0/remove_duplicate_leave_ledger_entries.py
@@ -43,4 +43,4 @@ def delete_duplicate_ledger_entries(duplicate_records_list):
AND is_carry_forward = %s
AND from_date = %s
AND to_date = %s
- ''', tuple(d))
\ No newline at end of file
+ ''', tuple(d))
diff --git a/erpnext/patches/v12_0/rename_account_type_doctype.py b/erpnext/patches/v12_0/rename_account_type_doctype.py
index ffb4e937b1..9a08ad4521 100644
--- a/erpnext/patches/v12_0/rename_account_type_doctype.py
+++ b/erpnext/patches/v12_0/rename_account_type_doctype.py
@@ -4,4 +4,4 @@ import frappe
def execute():
frappe.rename_doc('DocType', 'Account Type', 'Bank Account Type', force=True)
frappe.rename_doc('DocType', 'Account Subtype', 'Bank Account Subtype', force=True)
- frappe.reload_doc('accounts', 'doctype', 'bank_account')
\ No newline at end of file
+ frappe.reload_doc('accounts', 'doctype', 'bank_account')
diff --git a/erpnext/patches/v12_0/rename_bank_account_field_in_journal_entry_account.py b/erpnext/patches/v12_0/rename_bank_account_field_in_journal_entry_account.py
index 4230cb88f4..7489ea30a0 100644
--- a/erpnext/patches/v12_0/rename_bank_account_field_in_journal_entry_account.py
+++ b/erpnext/patches/v12_0/rename_bank_account_field_in_journal_entry_account.py
@@ -14,4 +14,4 @@ def execute():
def update_journal_entry_account_fieldname():
''' maps data from old field to the new field '''
if frappe.db.has_column('Journal Entry Account', 'bank_account_no'):
- rename_field("Journal Entry Account", "bank_account_no", "bank_account")
\ No newline at end of file
+ rename_field("Journal Entry Account", "bank_account_no", "bank_account")
diff --git a/erpnext/patches/v12_0/rename_lost_reason_detail.py b/erpnext/patches/v12_0/rename_lost_reason_detail.py
index d0dc356bd0..c71b91c925 100644
--- a/erpnext/patches/v12_0/rename_lost_reason_detail.py
+++ b/erpnext/patches/v12_0/rename_lost_reason_detail.py
@@ -15,4 +15,4 @@ def execute():
SELECT o.`name`, o.`creation`, o.`modified`, o.`modified_by`, o.`owner`, o.`docstatus`, o.`parent`, o.`parentfield`, o.`parenttype`, o.`idx`, o.`_comments`, o.`_assign`, o.`_user_tags`, o.`_liked_by`, o.`lost_reason`
FROM `tabOpportunity Lost Reason` o LEFT JOIN `tabQuotation Lost Reason` q ON q.name = o.name WHERE q.name IS NULL""")
- frappe.delete_doc("DocType", "Lost Reason Detail")
\ No newline at end of file
+ frappe.delete_doc("DocType", "Lost Reason Detail")
diff --git a/erpnext/patches/v12_0/rename_pos_closing_doctype.py b/erpnext/patches/v12_0/rename_pos_closing_doctype.py
index 0577f81234..9d8626b852 100644
--- a/erpnext/patches/v12_0/rename_pos_closing_doctype.py
+++ b/erpnext/patches/v12_0/rename_pos_closing_doctype.py
@@ -7,10 +7,10 @@ def execute():
if frappe.db.table_exists("POS Closing Voucher"):
if not frappe.db.exists("DocType", "POS Closing Entry"):
frappe.rename_doc('DocType', 'POS Closing Voucher', 'POS Closing Entry', force=True)
-
+
if not frappe.db.exists('DocType', 'POS Closing Entry Taxes'):
frappe.rename_doc('DocType', 'POS Closing Voucher Taxes', 'POS Closing Entry Taxes', force=True)
-
+
if not frappe.db.exists('DocType', 'POS Closing Voucher Details'):
frappe.rename_doc('DocType', 'POS Closing Voucher Details', 'POS Closing Entry Detail', force=True)
@@ -22,4 +22,4 @@ def execute():
frappe.delete_doc("DocType", "POS Closing Voucher")
frappe.delete_doc("DocType", "POS Closing Voucher Taxes")
frappe.delete_doc("DocType", "POS Closing Voucher Details")
- frappe.delete_doc("DocType", "POS Closing Voucher Invoices")
\ No newline at end of file
+ frappe.delete_doc("DocType", "POS Closing Voucher Invoices")
diff --git a/erpnext/patches/v12_0/rename_tolerance_fields.py b/erpnext/patches/v12_0/rename_tolerance_fields.py
index aa2fff4ca7..20b096331e 100644
--- a/erpnext/patches/v12_0/rename_tolerance_fields.py
+++ b/erpnext/patches/v12_0/rename_tolerance_fields.py
@@ -12,4 +12,4 @@ def execute():
qty_allowance = frappe.db.get_single_value("Stock Settings", "over_delivery_receipt_allowance")
frappe.db.set_value("Accounts Settings", None, "over_delivery_receipt_allowance", qty_allowance)
- frappe.db.sql("update tabItem set over_billing_allowance=over_delivery_receipt_allowance")
\ No newline at end of file
+ frappe.db.sql("update tabItem set over_billing_allowance=over_delivery_receipt_allowance")
diff --git a/erpnext/patches/v12_0/replace_accounting_with_accounts_in_home_settings.py b/erpnext/patches/v12_0/replace_accounting_with_accounts_in_home_settings.py
index 09fc4c1b04..f88a22f6c9 100644
--- a/erpnext/patches/v12_0/replace_accounting_with_accounts_in_home_settings.py
+++ b/erpnext/patches/v12_0/replace_accounting_with_accounts_in_home_settings.py
@@ -2,4 +2,4 @@ import frappe
def execute():
frappe.db.sql("""UPDATE `tabUser` SET `home_settings` = REPLACE(`home_settings`, 'Accounting', 'Accounts')""")
- frappe.cache().delete_key('home_settings')
\ No newline at end of file
+ frappe.cache().delete_key('home_settings')
diff --git a/erpnext/patches/v12_0/repost_stock_ledger_entries_for_target_warehouse.py b/erpnext/patches/v12_0/repost_stock_ledger_entries_for_target_warehouse.py
index 13e935b2d3..c52f380d8c 100644
--- a/erpnext/patches/v12_0/repost_stock_ledger_entries_for_target_warehouse.py
+++ b/erpnext/patches/v12_0/repost_stock_ledger_entries_for_target_warehouse.py
@@ -66,6 +66,3 @@ def execute():
frappe.db.sql(""" UPDATE `tabPacked Item` set target_warehouse = null
WHERE creation > '2020-04-16' and docstatus < 2 and parenttype = 'Sales Order' """)
-
-
-
diff --git a/erpnext/patches/v12_0/set_automatically_process_deferred_accounting_in_accounts_settings.py b/erpnext/patches/v12_0/set_automatically_process_deferred_accounting_in_accounts_settings.py
index 5ee75be499..b5d7e3dcb9 100644
--- a/erpnext/patches/v12_0/set_automatically_process_deferred_accounting_in_accounts_settings.py
+++ b/erpnext/patches/v12_0/set_automatically_process_deferred_accounting_in_accounts_settings.py
@@ -4,4 +4,4 @@ import frappe
def execute():
frappe.reload_doc("accounts", "doctype", "accounts_settings")
- frappe.db.set_value("Accounts Settings", None, "automatically_process_deferred_accounting_entry", 1)
\ No newline at end of file
+ frappe.db.set_value("Accounts Settings", None, "automatically_process_deferred_accounting_entry", 1)
diff --git a/erpnext/patches/v12_0/set_cost_center_in_child_table_of_expense_claim.py b/erpnext/patches/v12_0/set_cost_center_in_child_table_of_expense_claim.py
index 8ba0d79a83..4415cfeaba 100644
--- a/erpnext/patches/v12_0/set_cost_center_in_child_table_of_expense_claim.py
+++ b/erpnext/patches/v12_0/set_cost_center_in_child_table_of_expense_claim.py
@@ -5,4 +5,4 @@ def execute():
UPDATE `tabExpense Claim Detail` child, `tabExpense Claim` par
SET child.cost_center = par.cost_center
WHERE child.parent = par.name
- """)
\ No newline at end of file
+ """)
diff --git a/erpnext/patches/v12_0/set_cwip_and_delete_asset_settings.py b/erpnext/patches/v12_0/set_cwip_and_delete_asset_settings.py
index 4d4fc7c462..13110dfe03 100644
--- a/erpnext/patches/v12_0/set_cwip_and_delete_asset_settings.py
+++ b/erpnext/patches/v12_0/set_cwip_and_delete_asset_settings.py
@@ -10,8 +10,8 @@ def execute():
if frappe.db.exists("DocType", "Asset Settings"):
frappe.reload_doctype("Asset Category")
cwip_value = frappe.db.get_single_value("Asset Settings", "disable_cwip_accounting")
-
+
frappe.db.sql("""UPDATE `tabAsset Category` SET enable_cwip_accounting = %s""", cint(cwip_value))
frappe.db.sql("""DELETE FROM `tabSingles` where doctype = 'Asset Settings'""")
- frappe.delete_doc_if_exists("DocType", "Asset Settings")
\ No newline at end of file
+ frappe.delete_doc_if_exists("DocType", "Asset Settings")
diff --git a/erpnext/patches/v12_0/set_default_homepage_type.py b/erpnext/patches/v12_0/set_default_homepage_type.py
index 241e4b9b5e..a290e31cf2 100644
--- a/erpnext/patches/v12_0/set_default_homepage_type.py
+++ b/erpnext/patches/v12_0/set_default_homepage_type.py
@@ -1,4 +1,4 @@
import frappe
def execute():
- frappe.db.set_value('Homepage', 'Homepage', 'hero_section_based_on', 'Default')
\ No newline at end of file
+ frappe.db.set_value('Homepage', 'Homepage', 'hero_section_based_on', 'Default')
diff --git a/erpnext/patches/v12_0/set_default_payroll_based_on.py b/erpnext/patches/v12_0/set_default_payroll_based_on.py
index 04b54a6cf6..038bd6d21a 100644
--- a/erpnext/patches/v12_0/set_default_payroll_based_on.py
+++ b/erpnext/patches/v12_0/set_default_payroll_based_on.py
@@ -3,4 +3,4 @@ import frappe
def execute():
frappe.reload_doc("hr", "doctype", "hr_settings")
- frappe.db.set_value("HR Settings", None, "payroll_based_on", "Leave")
\ No newline at end of file
+ frappe.db.set_value("HR Settings", None, "payroll_based_on", "Leave")
diff --git a/erpnext/patches/v12_0/set_expense_account_in_landed_cost_voucher_taxes.py b/erpnext/patches/v12_0/set_expense_account_in_landed_cost_voucher_taxes.py
index a996a69b3d..a27c7b24a8 100644
--- a/erpnext/patches/v12_0/set_expense_account_in_landed_cost_voucher_taxes.py
+++ b/erpnext/patches/v12_0/set_expense_account_in_landed_cost_voucher_taxes.py
@@ -30,4 +30,4 @@ def execute():
s.docstatus = 1
AND s.company = %s
AND t.parent = s.name
- """, (account, company))
\ No newline at end of file
+ """, (account, company))
diff --git a/erpnext/patches/v12_0/set_gst_category.py b/erpnext/patches/v12_0/set_gst_category.py
index 55bbdee7ed..cc093953bf 100644
--- a/erpnext/patches/v12_0/set_gst_category.py
+++ b/erpnext/patches/v12_0/set_gst_category.py
@@ -48,5 +48,3 @@ def execute():
frappe.db.sql(""" UPDATE `tab{doctype}` t1, `tabAddress` t2, `tabDynamic Link` t3 SET t1.gst_category = "Overseas"
where t3.link_name = t1.name and t3.parent = t2.name and t2.country != 'India' """.format(doctype=doctype)) #nosec
-
-
diff --git a/erpnext/patches/v12_0/set_italian_import_supplier_invoice_permissions.py b/erpnext/patches/v12_0/set_italian_import_supplier_invoice_permissions.py
index a6011c4dac..8fdc73b8ff 100644
--- a/erpnext/patches/v12_0/set_italian_import_supplier_invoice_permissions.py
+++ b/erpnext/patches/v12_0/set_italian_import_supplier_invoice_permissions.py
@@ -9,4 +9,4 @@ def execute():
countries = frappe.get_all("Company", fields="country")
countries = [country["country"] for country in countries]
if "Italy" in countries:
- add_permissions()
\ No newline at end of file
+ add_permissions()
diff --git a/erpnext/patches/v12_0/set_multi_uom_in_rfq.py b/erpnext/patches/v12_0/set_multi_uom_in_rfq.py
index 70ca6b222e..a5c8f7524a 100644
--- a/erpnext/patches/v12_0/set_multi_uom_in_rfq.py
+++ b/erpnext/patches/v12_0/set_multi_uom_in_rfq.py
@@ -13,4 +13,4 @@ def execute():
SET
stock_uom = uom,
conversion_factor = 1,
- stock_qty = qty""")
\ No newline at end of file
+ stock_qty = qty""")
diff --git a/erpnext/patches/v12_0/set_payment_entry_status.py b/erpnext/patches/v12_0/set_payment_entry_status.py
index fafbec6a9a..84645a3863 100644
--- a/erpnext/patches/v12_0/set_payment_entry_status.py
+++ b/erpnext/patches/v12_0/set_payment_entry_status.py
@@ -6,4 +6,4 @@ def execute():
WHEN docstatus = 1 THEN 'Submitted'
WHEN docstatus = 2 THEN 'Cancelled'
ELSE 'Draft'
- END;""")
\ No newline at end of file
+ END;""")
diff --git a/erpnext/patches/v12_0/set_priority_for_support.py b/erpnext/patches/v12_0/set_priority_for_support.py
index a5490ef20d..66696bee54 100644
--- a/erpnext/patches/v12_0/set_priority_for_support.py
+++ b/erpnext/patches/v12_0/set_priority_for_support.py
@@ -81,4 +81,4 @@ def set_priorities_service_level_agreement():
doc.flags.ignore_validate = True
doc.save(ignore_permissions=True)
except frappe.db.TableMissingError:
- frappe.reload_doc("support", "doctype", "service_level_agreement")
\ No newline at end of file
+ frappe.reload_doc("support", "doctype", "service_level_agreement")
diff --git a/erpnext/patches/v12_0/set_produced_qty_field_in_sales_order_for_work_order.py b/erpnext/patches/v12_0/set_produced_qty_field_in_sales_order_for_work_order.py
index 07026732fd..6c11cb415f 100644
--- a/erpnext/patches/v12_0/set_produced_qty_field_in_sales_order_for_work_order.py
+++ b/erpnext/patches/v12_0/set_produced_qty_field_in_sales_order_for_work_order.py
@@ -11,4 +11,4 @@ def execute():
filters={'sales_order': ('!=', ''), 'sales_order_item': ('!=', '')}):
# update produced qty in sales order
- update_produced_qty_in_so_item(d.sales_order, d.sales_order_item)
\ No newline at end of file
+ update_produced_qty_in_so_item(d.sales_order, d.sales_order_item)
diff --git a/erpnext/patches/v12_0/set_production_capacity_in_workstation.py b/erpnext/patches/v12_0/set_production_capacity_in_workstation.py
index bae1e28deb..babaebeaef 100644
--- a/erpnext/patches/v12_0/set_production_capacity_in_workstation.py
+++ b/erpnext/patches/v12_0/set_production_capacity_in_workstation.py
@@ -5,4 +5,4 @@ def execute():
frappe.reload_doc("manufacturing", "doctype", "workstation")
frappe.db.sql(""" UPDATE `tabWorkstation`
- SET production_capacity = 1 """)
\ No newline at end of file
+ SET production_capacity = 1 """)
diff --git a/erpnext/patches/v12_0/set_quotation_status.py b/erpnext/patches/v12_0/set_quotation_status.py
index 64a9080a8f..87643a2354 100644
--- a/erpnext/patches/v12_0/set_quotation_status.py
+++ b/erpnext/patches/v12_0/set_quotation_status.py
@@ -4,4 +4,4 @@ import frappe
def execute():
frappe.db.sql(""" UPDATE `tabQuotation` set status = 'Open'
- where docstatus = 1 and status = 'Submitted' """)
\ No newline at end of file
+ where docstatus = 1 and status = 'Submitted' """)
diff --git a/erpnext/patches/v12_0/set_updated_purpose_in_pick_list.py b/erpnext/patches/v12_0/set_updated_purpose_in_pick_list.py
index 63ca540a8e..1cc37caba4 100644
--- a/erpnext/patches/v12_0/set_updated_purpose_in_pick_list.py
+++ b/erpnext/patches/v12_0/set_updated_purpose_in_pick_list.py
@@ -8,4 +8,4 @@ import frappe
def execute():
frappe.reload_doc("stock", "doctype", "pick_list")
frappe.db.sql("""UPDATE `tabPick List` set purpose = 'Delivery'
- WHERE docstatus = 1 and purpose = 'Delivery against Sales Order' """)
\ No newline at end of file
+ WHERE docstatus = 1 and purpose = 'Delivery against Sales Order' """)
diff --git a/erpnext/patches/v12_0/setup_einvoice_fields.py b/erpnext/patches/v12_0/setup_einvoice_fields.py
index 2474bc3b82..82b14fc9d6 100644
--- a/erpnext/patches/v12_0/setup_einvoice_fields.py
+++ b/erpnext/patches/v12_0/setup_einvoice_fields.py
@@ -14,9 +14,9 @@ def execute():
'Sales Invoice': [
dict(fieldname='irn', label='IRN', fieldtype='Data', read_only=1, insert_after='customer', no_copy=1, print_hide=1,
depends_on='eval:in_list(["Registered Regular", "SEZ", "Overseas", "Deemed Export"], doc.gst_category) && doc.irn_cancelled === 0'),
-
+
dict(fieldname='ack_no', label='Ack. No.', fieldtype='Data', read_only=1, hidden=1, insert_after='irn', no_copy=1, print_hide=1),
-
+
dict(fieldname='ack_date', label='Ack. Date', fieldtype='Data', read_only=1, hidden=1, insert_after='ack_no', no_copy=1, print_hide=1),
dict(fieldname='irn_cancelled', label='IRN Cancelled', fieldtype='Check', no_copy=1, print_hide=1,
diff --git a/erpnext/patches/v12_0/stock_entry_enhancements.py b/erpnext/patches/v12_0/stock_entry_enhancements.py
index 847d92894b..17fdcd9395 100644
--- a/erpnext/patches/v12_0/stock_entry_enhancements.py
+++ b/erpnext/patches/v12_0/stock_entry_enhancements.py
@@ -49,4 +49,4 @@ def add_gst_hsn_code_field():
`tabStock Entry Detail`.gst_hsn_code = `tabItem`.gst_hsn_code
Where
`tabItem`.name = `tabStock Entry Detail`.item_code and `tabItem`.gst_hsn_code is not null
- """)
\ No newline at end of file
+ """)
diff --git a/erpnext/patches/v12_0/unhide_cost_center_field.py b/erpnext/patches/v12_0/unhide_cost_center_field.py
index 6005ab7072..3474a34af4 100644
--- a/erpnext/patches/v12_0/unhide_cost_center_field.py
+++ b/erpnext/patches/v12_0/unhide_cost_center_field.py
@@ -10,4 +10,4 @@ def execute():
WHERE doc_type in ('Sales Invoice', 'Purchase Invoice', 'Payment Entry')
AND field_name = 'cost_center'
AND property = 'hidden'
- """)
\ No newline at end of file
+ """)
diff --git a/erpnext/patches/v12_0/update_appointment_reminder_scheduler_entry.py b/erpnext/patches/v12_0/update_appointment_reminder_scheduler_entry.py
index 91931eeb3b..f451664961 100644
--- a/erpnext/patches/v12_0/update_appointment_reminder_scheduler_entry.py
+++ b/erpnext/patches/v12_0/update_appointment_reminder_scheduler_entry.py
@@ -4,4 +4,4 @@ def execute():
job = frappe.db.exists('Scheduled Job Type', 'patient_appointment.send_appointment_reminder')
if job:
method = 'erpnext.healthcare.doctype.patient_appointment.patient_appointment.send_appointment_reminder'
- frappe.db.set_value('Scheduled Job Type', job, 'method', method)
\ No newline at end of file
+ frappe.db.set_value('Scheduled Job Type', job, 'method', method)
diff --git a/erpnext/patches/v12_0/update_bom_in_so_mr.py b/erpnext/patches/v12_0/update_bom_in_so_mr.py
index 309ae4c2ab..8a87171813 100644
--- a/erpnext/patches/v12_0/update_bom_in_so_mr.py
+++ b/erpnext/patches/v12_0/update_bom_in_so_mr.py
@@ -16,4 +16,4 @@ def execute():
WHERE
child_doc.item_code = item.name and child_doc.docstatus < 2
and item.default_bom is not null and item.default_bom != '' {cond}
- """.format(doc = doctype, cond = condition))
\ No newline at end of file
+ """.format(doc = doctype, cond = condition))
diff --git a/erpnext/patches/v12_0/update_end_date_and_status_in_email_campaign.py b/erpnext/patches/v12_0/update_end_date_and_status_in_email_campaign.py
index db71a735de..c45f6221f9 100644
--- a/erpnext/patches/v12_0/update_end_date_and_status_in_email_campaign.py
+++ b/erpnext/patches/v12_0/update_end_date_and_status_in_email_campaign.py
@@ -21,4 +21,4 @@ def execute():
elif end_date >= today_date:
doc.db_set("status", "In Progress")
elif end_date < today_date:
- doc.db_set("status", "Completed")
\ No newline at end of file
+ doc.db_set("status", "Completed")
diff --git a/erpnext/patches/v12_0/update_ewaybill_field_position.py b/erpnext/patches/v12_0/update_ewaybill_field_position.py
index c0230c4395..9e5f599d2c 100644
--- a/erpnext/patches/v12_0/update_ewaybill_field_position.py
+++ b/erpnext/patches/v12_0/update_ewaybill_field_position.py
@@ -25,4 +25,4 @@ def execute():
'translatable': 0
})
- ewaybill_field.save()
\ No newline at end of file
+ ewaybill_field.save()
diff --git a/erpnext/patches/v12_0/update_gst_category.py b/erpnext/patches/v12_0/update_gst_category.py
index 963edad150..1a54216b88 100644
--- a/erpnext/patches/v12_0/update_gst_category.py
+++ b/erpnext/patches/v12_0/update_gst_category.py
@@ -16,4 +16,4 @@ def execute():
frappe.db.sql(""" UPDATE `tabPurchase Invoice` set gst_category = 'Unregistered'
where gst_category = 'Registered Regular'
and ifnull(supplier_gstin, '')=''
- """)
\ No newline at end of file
+ """)
diff --git a/erpnext/patches/v12_0/update_healthcare_refactored_changes.py b/erpnext/patches/v12_0/update_healthcare_refactored_changes.py
index d06c5713d2..d0b0443397 100644
--- a/erpnext/patches/v12_0/update_healthcare_refactored_changes.py
+++ b/erpnext/patches/v12_0/update_healthcare_refactored_changes.py
@@ -134,4 +134,4 @@ def execute():
status = (CASE WHEN visited >= max_visits THEN 'Completed'
ELSE 'Pending'
END)
- """)
\ No newline at end of file
+ """)
diff --git a/erpnext/patches/v12_0/update_is_cancelled_field.py b/erpnext/patches/v12_0/update_is_cancelled_field.py
index 0b2e82750b..4bbec44aa4 100644
--- a/erpnext/patches/v12_0/update_is_cancelled_field.py
+++ b/erpnext/patches/v12_0/update_is_cancelled_field.py
@@ -12,4 +12,4 @@ def execute():
frappe.reload_doc("stock", "doctype", "stock_ledger_entry")
frappe.reload_doc("stock", "doctype", "serial_no")
except:
- pass
\ No newline at end of file
+ pass
diff --git a/erpnext/patches/v12_0/update_item_tax_template_company.py b/erpnext/patches/v12_0/update_item_tax_template_company.py
index f7496999b3..e15894df89 100644
--- a/erpnext/patches/v12_0/update_item_tax_template_company.py
+++ b/erpnext/patches/v12_0/update_item_tax_template_company.py
@@ -10,4 +10,4 @@ def execute():
for tax in doc.taxes:
doc.company = frappe.get_value('Account', tax.tax_type, 'company')
break
- doc.save()
\ No newline at end of file
+ doc.save()
diff --git a/erpnext/patches/v12_0/update_owner_fields_in_acc_dimension_custom_fields.py b/erpnext/patches/v12_0/update_owner_fields_in_acc_dimension_custom_fields.py
index e4dcecd9bd..6ebaf48e0e 100644
--- a/erpnext/patches/v12_0/update_owner_fields_in_acc_dimension_custom_fields.py
+++ b/erpnext/patches/v12_0/update_owner_fields_in_acc_dimension_custom_fields.py
@@ -14,4 +14,4 @@ def execute():
SET owner = 'Administrator'
WHERE fieldname = %s
AND dt IN (%s)""" % #nosec
- ('%s', ', '.join(['%s']* len(doclist))), tuple([dimension.fieldname] + doclist))
\ No newline at end of file
+ ('%s', ', '.join(['%s']* len(doclist))), tuple([dimension.fieldname] + doclist))
diff --git a/erpnext/patches/v12_0/update_price_list_currency_in_bom.py b/erpnext/patches/v12_0/update_price_list_currency_in_bom.py
index f5e7b947c2..09f0707429 100644
--- a/erpnext/patches/v12_0/update_price_list_currency_in_bom.py
+++ b/erpnext/patches/v12_0/update_price_list_currency_in_bom.py
@@ -28,4 +28,4 @@ def execute():
plc_conversion_rate = get_exchange_rate(d.currency,
d.company_currency, getdate(d.creation), "for_buying")
- frappe.db.set_value("BOM", d.name, "plc_conversion_rate", plc_conversion_rate)
\ No newline at end of file
+ frappe.db.set_value("BOM", d.name, "plc_conversion_rate", plc_conversion_rate)
diff --git a/erpnext/patches/v12_0/update_state_code_for_daman_and_diu.py b/erpnext/patches/v12_0/update_state_code_for_daman_and_diu.py
index 7450e9cd8c..8dbfa1866d 100644
--- a/erpnext/patches/v12_0/update_state_code_for_daman_and_diu.py
+++ b/erpnext/patches/v12_0/update_state_code_for_daman_and_diu.py
@@ -19,4 +19,4 @@ def execute():
gst_state = 'Dadra and Nagar Haveli and Daman and Diu',
gst_state_number = 26
WHERE gst_state = 'Daman and Diu'
- """)
\ No newline at end of file
+ """)
diff --git a/erpnext/patches/v12_0/update_uom_conversion_factor.py b/erpnext/patches/v12_0/update_uom_conversion_factor.py
index b5a20aa6fd..24914fd13b 100644
--- a/erpnext/patches/v12_0/update_uom_conversion_factor.py
+++ b/erpnext/patches/v12_0/update_uom_conversion_factor.py
@@ -8,4 +8,4 @@ def execute():
frappe.reload_doc("setup", "doctype", "UOM")
frappe.reload_doc("stock", "doctype", "UOM Category")
- add_uom_data()
\ No newline at end of file
+ add_uom_data()
diff --git a/erpnext/patches/v13_0/add_doctype_to_sla.py b/erpnext/patches/v13_0/add_doctype_to_sla.py
index e2c7fd268a..cdc5a1eabb 100644
--- a/erpnext/patches/v13_0/add_doctype_to_sla.py
+++ b/erpnext/patches/v13_0/add_doctype_to_sla.py
@@ -18,4 +18,4 @@ def execute():
agreement.apply_sla_for_resolution = 1
agreement.append('sla_fulfilled_on', {'status': 'Resolved'})
agreement.append('sla_fulfilled_on', {'status': 'Closed'})
- agreement.save()
\ No newline at end of file
+ agreement.save()
diff --git a/erpnext/patches/v13_0/add_naming_series_to_old_projects.py b/erpnext/patches/v13_0/add_naming_series_to_old_projects.py
index 5ed9040f1e..a7b66f0d2b 100644
--- a/erpnext/patches/v13_0/add_naming_series_to_old_projects.py
+++ b/erpnext/patches/v13_0/add_naming_series_to_old_projects.py
@@ -10,4 +10,3 @@ def execute():
naming_series = 'PROJ-.####'
WHERE
naming_series is NULL""")
-
diff --git a/erpnext/patches/v13_0/change_default_pos_print_format.py b/erpnext/patches/v13_0/change_default_pos_print_format.py
index 605a29e477..1e4f383dda 100644
--- a/erpnext/patches/v13_0/change_default_pos_print_format.py
+++ b/erpnext/patches/v13_0/change_default_pos_print_format.py
@@ -5,4 +5,4 @@ def execute():
frappe.db.sql(
"""UPDATE `tabPOS Profile` profile
SET profile.`print_format` = 'POS Invoice'
- WHERE profile.`print_format` = 'Point of Sale'""")
\ No newline at end of file
+ WHERE profile.`print_format` = 'Point of Sale'""")
diff --git a/erpnext/patches/v13_0/check_is_income_tax_component.py b/erpnext/patches/v13_0/check_is_income_tax_component.py
index c92d52dcec..ebae3ad715 100644
--- a/erpnext/patches/v13_0/check_is_income_tax_component.py
+++ b/erpnext/patches/v13_0/check_is_income_tax_component.py
@@ -43,4 +43,4 @@ def execute():
if frappe.db.exists("Salary Component", "Provident Fund"):
frappe.db.set_value("Salary Component", "Provident Fund", "component_type", "Provident Fund")
if frappe.db.exists("Salary Component", "Professional Tax"):
- frappe.db.set_value("Salary Component", "Professional Tax", "component_type", "Professional Tax")
\ No newline at end of file
+ frappe.db.set_value("Salary Component", "Professional Tax", "component_type", "Professional Tax")
diff --git a/erpnext/patches/v13_0/convert_qi_parameter_to_link_field.py b/erpnext/patches/v13_0/convert_qi_parameter_to_link_field.py
index 289b6a761e..341955aa35 100644
--- a/erpnext/patches/v13_0/convert_qi_parameter_to_link_field.py
+++ b/erpnext/patches/v13_0/convert_qi_parameter_to_link_field.py
@@ -20,4 +20,4 @@ def execute():
"doctype": "Quality Inspection Parameter",
"parameter": parameter,
"description": parameter
- }).insert(ignore_permissions=True)
\ No newline at end of file
+ }).insert(ignore_permissions=True)
diff --git a/erpnext/patches/v13_0/create_healthcare_custom_fields_in_stock_entry_detail.py b/erpnext/patches/v13_0/create_healthcare_custom_fields_in_stock_entry_detail.py
index 585e540626..08d4876c0d 100644
--- a/erpnext/patches/v13_0/create_healthcare_custom_fields_in_stock_entry_detail.py
+++ b/erpnext/patches/v13_0/create_healthcare_custom_fields_in_stock_entry_detail.py
@@ -7,4 +7,4 @@ def execute():
return
if data['custom_fields']:
- create_custom_fields(data['custom_fields'])
\ No newline at end of file
+ create_custom_fields(data['custom_fields'])
diff --git a/erpnext/patches/v13_0/create_leave_policy_assignment_based_on_employee_current_leave_policy.py b/erpnext/patches/v13_0/create_leave_policy_assignment_based_on_employee_current_leave_policy.py
index 90dc0e2e18..9a354537f7 100644
--- a/erpnext/patches/v13_0/create_leave_policy_assignment_based_on_employee_current_leave_policy.py
+++ b/erpnext/patches/v13_0/create_leave_policy_assignment_based_on_employee_current_leave_policy.py
@@ -74,6 +74,3 @@ def create_assignment(employee, leave_policy, leave_period=None, allocation_exis
def get_employee_with_grade(grade):
return frappe.get_list("Employee", filters = {"grade": grade})
-
-
-
diff --git a/erpnext/patches/v13_0/create_uae_pos_invoice_fields.py b/erpnext/patches/v13_0/create_uae_pos_invoice_fields.py
index 59b2e49b26..6ad3402ba0 100644
--- a/erpnext/patches/v13_0/create_uae_pos_invoice_fields.py
+++ b/erpnext/patches/v13_0/create_uae_pos_invoice_fields.py
@@ -15,4 +15,4 @@ def execute():
frappe.reload_doc('accounts', 'doctype', 'pos_invoice')
frappe.reload_doc('accounts', 'doctype', 'pos_invoice_item')
- make_custom_fields()
\ No newline at end of file
+ make_custom_fields()
diff --git a/erpnext/patches/v13_0/delete_old_purchase_reports.py b/erpnext/patches/v13_0/delete_old_purchase_reports.py
index 8bdc07ee5b..c17aad06c7 100644
--- a/erpnext/patches/v13_0/delete_old_purchase_reports.py
+++ b/erpnext/patches/v13_0/delete_old_purchase_reports.py
@@ -20,4 +20,4 @@ def delete_auto_email_reports(report):
""" Check for one or multiple Auto Email Reports and delete """
auto_email_reports = frappe.db.get_values("Auto Email Report", {"report": report}, ["name"])
for auto_email_report in auto_email_reports:
- frappe.delete_doc("Auto Email Report", auto_email_report[0])
\ No newline at end of file
+ frappe.delete_doc("Auto Email Report", auto_email_report[0])
diff --git a/erpnext/patches/v13_0/delete_old_sales_reports.py b/erpnext/patches/v13_0/delete_old_sales_reports.py
index 0f44865808..671c012c8a 100644
--- a/erpnext/patches/v13_0/delete_old_sales_reports.py
+++ b/erpnext/patches/v13_0/delete_old_sales_reports.py
@@ -18,4 +18,4 @@ def delete_auto_email_reports(report):
""" Check for one or multiple Auto Email Reports and delete """
auto_email_reports = frappe.db.get_values("Auto Email Report", {"report": report}, ["name"])
for auto_email_report in auto_email_reports:
- frappe.delete_doc("Auto Email Report", auto_email_report[0])
\ No newline at end of file
+ frappe.delete_doc("Auto Email Report", auto_email_report[0])
diff --git a/erpnext/patches/v13_0/delete_orphaned_tables.py b/erpnext/patches/v13_0/delete_orphaned_tables.py
index 1d6eebe039..50a4a0efcb 100644
--- a/erpnext/patches/v13_0/delete_orphaned_tables.py
+++ b/erpnext/patches/v13_0/delete_orphaned_tables.py
@@ -28,9 +28,9 @@ def has_deleted_company_transactions():
def get_child_doctypes_whose_parent_doctypes_were_affected():
parent_doctypes = get_affected_doctypes()
child_doctypes = frappe.get_all(
- 'DocField',
+ 'DocField',
filters={
- 'fieldtype': 'Table',
+ 'fieldtype': 'Table',
'parent':['in', parent_doctypes]
}, pluck='options')
@@ -39,7 +39,7 @@ def get_child_doctypes_whose_parent_doctypes_were_affected():
def get_affected_doctypes():
affected_doctypes = []
tdr_docs = frappe.get_all('Transaction Deletion Record', pluck="name")
-
+
for tdr in tdr_docs:
tdr_doc = frappe.get_doc("Transaction Deletion Record", tdr)
@@ -66,4 +66,4 @@ def check_for_new_doc_with_same_name_as_deleted_parent(doc):
parent_creation_time = frappe.db.get_value(doc['parenttype'], doc['parent'], 'creation')
child_creation_time = doc['creation']
- return getdate(parent_creation_time) > getdate(child_creation_time)
\ No newline at end of file
+ return getdate(parent_creation_time) > getdate(child_creation_time)
diff --git a/erpnext/patches/v13_0/delete_report_requested_items_to_order.py b/erpnext/patches/v13_0/delete_report_requested_items_to_order.py
index 94a9fa85a8..8d6340d44e 100644
--- a/erpnext/patches/v13_0/delete_report_requested_items_to_order.py
+++ b/erpnext/patches/v13_0/delete_report_requested_items_to_order.py
@@ -9,4 +9,4 @@ def execute():
frappe.db.sql("""
DELETE FROM `tabReport`
WHERE name = 'Requested Items to Order'
- """)
\ No newline at end of file
+ """)
diff --git a/erpnext/patches/v13_0/drop_razorpay_payload_column.py b/erpnext/patches/v13_0/drop_razorpay_payload_column.py
index 8980fd0039..76b8041cd9 100644
--- a/erpnext/patches/v13_0/drop_razorpay_payload_column.py
+++ b/erpnext/patches/v13_0/drop_razorpay_payload_column.py
@@ -4,4 +4,4 @@ import frappe
def execute():
if frappe.db.exists("DocType", "Membership"):
if 'webhook_payload' in frappe.db.get_table_columns("Membership"):
- frappe.db.sql("alter table `tabMembership` drop column webhook_payload")
\ No newline at end of file
+ frappe.db.sql("alter table `tabMembership` drop column webhook_payload")
diff --git a/erpnext/patches/v13_0/fix_non_unique_represents_company.py b/erpnext/patches/v13_0/fix_non_unique_represents_company.py
index 61dc824dd4..f20c73ae10 100644
--- a/erpnext/patches/v13_0/fix_non_unique_represents_company.py
+++ b/erpnext/patches/v13_0/fix_non_unique_represents_company.py
@@ -5,4 +5,4 @@ def execute():
update tabCustomer
set represents_company = NULL
where represents_company = ''
- """)
\ No newline at end of file
+ """)
diff --git a/erpnext/patches/v13_0/germany_fill_debtor_creditor_number.py b/erpnext/patches/v13_0/germany_fill_debtor_creditor_number.py
index 11e1e9b3b9..dca43b4193 100644
--- a/erpnext/patches/v13_0/germany_fill_debtor_creditor_number.py
+++ b/erpnext/patches/v13_0/germany_fill_debtor_creditor_number.py
@@ -12,7 +12,7 @@ def execute():
German companies used to use a dedicated payable/receivable account for
every party to mimick party accounts in the external accounting software
"DATEV". This is no longer necessary. The reference ID for DATEV will be
- stored in a new custom field "debtor_creditor_number".
+ stored in a new custom field "debtor_creditor_number".
"""
company_list = frappe.get_all('Company', filters={'country': 'Germany'})
diff --git a/erpnext/patches/v13_0/item_reposting_for_incorrect_sl_and_gl.py b/erpnext/patches/v13_0/item_reposting_for_incorrect_sl_and_gl.py
index 021bb72cae..c4ad1b7ff4 100644
--- a/erpnext/patches/v13_0/item_reposting_for_incorrect_sl_and_gl.py
+++ b/erpnext/patches/v13_0/item_reposting_for_incorrect_sl_and_gl.py
@@ -67,4 +67,4 @@ def execute():
def get_creation_time():
return frappe.db.sql(''' SELECT create_time FROM
- INFORMATION_SCHEMA.TABLES where TABLE_NAME = "tabRepost Item Valuation" ''', as_list=1)[0][0]
\ No newline at end of file
+ INFORMATION_SCHEMA.TABLES where TABLE_NAME = "tabRepost Item Valuation" ''', as_list=1)[0][0]
diff --git a/erpnext/patches/v13_0/loyalty_points_entry_for_pos_invoice.py b/erpnext/patches/v13_0/loyalty_points_entry_for_pos_invoice.py
index ee7734053c..d2228c3bf3 100644
--- a/erpnext/patches/v13_0/loyalty_points_entry_for_pos_invoice.py
+++ b/erpnext/patches/v13_0/loyalty_points_entry_for_pos_invoice.py
@@ -9,7 +9,7 @@ def execute():
'''`sales_invoice` field from loyalty point entry is splitted into `invoice_type` & `invoice` fields'''
frappe.reload_doc("Accounts", "doctype", "loyalty_point_entry")
-
+
if not frappe.db.has_column('Loyalty Point Entry', 'sales_invoice'):
return
@@ -17,4 +17,4 @@ def execute():
"""UPDATE `tabLoyalty Point Entry` lpe
SET lpe.`invoice_type` = 'Sales Invoice', lpe.`invoice` = lpe.`sales_invoice`
WHERE lpe.`sales_invoice` IS NOT NULL
- AND (lpe.`invoice` IS NULL OR lpe.`invoice` = '')""")
\ No newline at end of file
+ AND (lpe.`invoice` IS NULL OR lpe.`invoice` = '')""")
diff --git a/erpnext/patches/v13_0/make_non_standard_user_type.py b/erpnext/patches/v13_0/make_non_standard_user_type.py
index a9d7883d40..73361f0026 100644
--- a/erpnext/patches/v13_0/make_non_standard_user_type.py
+++ b/erpnext/patches/v13_0/make_non_standard_user_type.py
@@ -21,4 +21,4 @@ def execute():
frappe.flags.ignore_select_perm = True
frappe.flags.update_select_perm_after_migrate = True
- add_non_standard_user_types()
\ No newline at end of file
+ add_non_standard_user_types()
diff --git a/erpnext/patches/v13_0/move_branch_code_to_bank_account.py b/erpnext/patches/v13_0/move_branch_code_to_bank_account.py
index 833ae2a48f..24d9196d29 100644
--- a/erpnext/patches/v13_0/move_branch_code_to_bank_account.py
+++ b/erpnext/patches/v13_0/move_branch_code_to_bank_account.py
@@ -14,4 +14,4 @@ def execute():
frappe.db.sql("""UPDATE `tabBank` b, `tabBank Account` ba
SET ba.branch_code = b.branch_code
WHERE ba.bank = b.name AND
- ifnull(b.branch_code, '') != '' AND ifnull(ba.branch_code, '') = ''""")
\ No newline at end of file
+ ifnull(b.branch_code, '') != '' AND ifnull(ba.branch_code, '') = ''""")
diff --git a/erpnext/patches/v13_0/patch_to_fix_reverse_linking_in_additional_salary_encashment_and_incentive.py b/erpnext/patches/v13_0/patch_to_fix_reverse_linking_in_additional_salary_encashment_and_incentive.py
index fde8f86470..15aeb76e53 100644
--- a/erpnext/patches/v13_0/patch_to_fix_reverse_linking_in_additional_salary_encashment_and_incentive.py
+++ b/erpnext/patches/v13_0/patch_to_fix_reverse_linking_in_additional_salary_encashment_and_incentive.py
@@ -51,4 +51,3 @@ def execute():
and parent = %s
and salary_component = %s
""", (salary["name"], comp_type, salary["salary_slip"], salary["salary_component"]))
-
diff --git a/erpnext/patches/v13_0/rename_issue_status_hold_to_on_hold.py b/erpnext/patches/v13_0/rename_issue_status_hold_to_on_hold.py
index 48325fc2d4..4ef04ad9b1 100644
--- a/erpnext/patches/v13_0/rename_issue_status_hold_to_on_hold.py
+++ b/erpnext/patches/v13_0/rename_issue_status_hold_to_on_hold.py
@@ -17,4 +17,4 @@ def rename_status():
status = 'On Hold'
WHERE
status = 'Hold'
- """)
\ No newline at end of file
+ """)
diff --git a/erpnext/patches/v13_0/rename_membership_settings_to_non_profit_settings.py b/erpnext/patches/v13_0/rename_membership_settings_to_non_profit_settings.py
index 3fa09a7baa..f60567b6b2 100644
--- a/erpnext/patches/v13_0/rename_membership_settings_to_non_profit_settings.py
+++ b/erpnext/patches/v13_0/rename_membership_settings_to_non_profit_settings.py
@@ -19,4 +19,4 @@ def execute():
}
for old_name, new_name in rename_fields_map.items():
- rename_field("Non Profit Settings", old_name, new_name)
\ No newline at end of file
+ rename_field("Non Profit Settings", old_name, new_name)
diff --git a/erpnext/patches/v13_0/replace_pos_page_with_point_of_sale_page.py b/erpnext/patches/v13_0/replace_pos_page_with_point_of_sale_page.py
index 390e217cad..d8bcd7f077 100644
--- a/erpnext/patches/v13_0/replace_pos_page_with_point_of_sale_page.py
+++ b/erpnext/patches/v13_0/replace_pos_page_with_point_of_sale_page.py
@@ -3,4 +3,4 @@ import frappe
def execute():
if frappe.db.exists("Page", "point-of-sale"):
- frappe.rename_doc("Page", "pos", "point-of-sale", 1, 1)
\ No newline at end of file
+ frappe.rename_doc("Page", "pos", "point-of-sale", 1, 1)
diff --git a/erpnext/patches/v13_0/replace_pos_payment_mode_table.py b/erpnext/patches/v13_0/replace_pos_payment_mode_table.py
index 7cb264830a..bc1fc98e4d 100644
--- a/erpnext/patches/v13_0/replace_pos_payment_mode_table.py
+++ b/erpnext/patches/v13_0/replace_pos_payment_mode_table.py
@@ -23,5 +23,5 @@ def execute():
pos_payment_method.parentfield = payment_mode.parentfield
pos_payment_method.parenttype = payment_mode.parenttype
pos_payment_method.db_insert()
-
+
frappe.db.sql("""delete from `tabSales Invoice Payment` where parent=%s""", pos_profile.name)
diff --git a/erpnext/patches/v13_0/set_company_in_leave_ledger_entry.py b/erpnext/patches/v13_0/set_company_in_leave_ledger_entry.py
index 66857c4e65..13ec41ec55 100644
--- a/erpnext/patches/v13_0/set_company_in_leave_ledger_entry.py
+++ b/erpnext/patches/v13_0/set_company_in_leave_ledger_entry.py
@@ -4,4 +4,4 @@ def execute():
frappe.reload_doc('HR', 'doctype', 'Leave Allocation')
frappe.reload_doc('HR', 'doctype', 'Leave Ledger Entry')
frappe.db.sql("""update `tabLeave Ledger Entry` as lle set company = (select company from `tabEmployee` where employee = lle.employee)""")
- frappe.db.sql("""update `tabLeave Allocation` as la set company = (select company from `tabEmployee` where employee = la.employee)""")
\ No newline at end of file
+ frappe.db.sql("""update `tabLeave Allocation` as la set company = (select company from `tabEmployee` where employee = la.employee)""")
diff --git a/erpnext/patches/v13_0/set_payment_channel_in_payment_gateway_account.py b/erpnext/patches/v13_0/set_payment_channel_in_payment_gateway_account.py
index edca238393..7f75946af9 100644
--- a/erpnext/patches/v13_0/set_payment_channel_in_payment_gateway_account.py
+++ b/erpnext/patches/v13_0/set_payment_channel_in_payment_gateway_account.py
@@ -14,4 +14,4 @@ def set_payment_channel_as_email():
frappe.db.sql("""
UPDATE `tabPayment Gateway Account`
SET `payment_channel` = "Email"
- """)
\ No newline at end of file
+ """)
diff --git a/erpnext/patches/v13_0/set_pos_closing_as_failed.py b/erpnext/patches/v13_0/set_pos_closing_as_failed.py
index 1c576db1c7..7968e74f50 100644
--- a/erpnext/patches/v13_0/set_pos_closing_as_failed.py
+++ b/erpnext/patches/v13_0/set_pos_closing_as_failed.py
@@ -4,4 +4,4 @@ import frappe
def execute():
frappe.reload_doc('accounts', 'doctype', 'pos_closing_entry')
- frappe.db.sql("update `tabPOS Closing Entry` set `status` = 'Failed' where `status` = 'Queued'")
\ No newline at end of file
+ frappe.db.sql("update `tabPOS Closing Entry` set `status` = 'Failed' where `status` = 'Queued'")
diff --git a/erpnext/patches/v13_0/set_training_event_attendance.py b/erpnext/patches/v13_0/set_training_event_attendance.py
index 18cad8d86c..3db183fb2a 100644
--- a/erpnext/patches/v13_0/set_training_event_attendance.py
+++ b/erpnext/patches/v13_0/set_training_event_attendance.py
@@ -6,4 +6,4 @@ def execute():
frappe.reload_doc('hr', 'doctype', 'training_event_employee')
frappe.db.sql("update `tabTraining Event Employee` set `attendance` = 'Present'")
- frappe.db.sql("update `tabTraining Event Employee` set `is_mandatory` = 1 where `attendance` = 'Mandatory'")
\ No newline at end of file
+ frappe.db.sql("update `tabTraining Event Employee` set `is_mandatory` = 1 where `attendance` = 'Mandatory'")
diff --git a/erpnext/patches/v13_0/set_youtube_video_id.py b/erpnext/patches/v13_0/set_youtube_video_id.py
index c3b49eb4fe..f6104d1579 100644
--- a/erpnext/patches/v13_0/set_youtube_video_id.py
+++ b/erpnext/patches/v13_0/set_youtube_video_id.py
@@ -7,4 +7,4 @@ def execute():
for video in frappe.get_all("Video", fields=["name", "url", "youtube_video_id"]):
if video.url and not video.youtube_video_id:
- frappe.db.set_value("Video", video.name, "youtube_video_id", get_id_from_url(video.url))
\ No newline at end of file
+ frappe.db.set_value("Video", video.name, "youtube_video_id", get_id_from_url(video.url))
diff --git a/erpnext/patches/v13_0/setting_custom_roles_for_some_regional_reports.py b/erpnext/patches/v13_0/setting_custom_roles_for_some_regional_reports.py
index ecc7822e1d..c8c160fae7 100644
--- a/erpnext/patches/v13_0/setting_custom_roles_for_some_regional_reports.py
+++ b/erpnext/patches/v13_0/setting_custom_roles_for_some_regional_reports.py
@@ -7,4 +7,4 @@ def execute():
if not company:
return
- add_custom_roles_for_reports()
\ No newline at end of file
+ add_custom_roles_for_reports()
diff --git a/erpnext/patches/v13_0/setup_patient_history_settings_for_standard_doctypes.py b/erpnext/patches/v13_0/setup_patient_history_settings_for_standard_doctypes.py
index d927524a3c..83581dd414 100644
--- a/erpnext/patches/v13_0/setup_patient_history_settings_for_standard_doctypes.py
+++ b/erpnext/patches/v13_0/setup_patient_history_settings_for_standard_doctypes.py
@@ -13,4 +13,4 @@ def execute():
frappe.reload_doc("healthcare", "doctype", "Patient History Standard Document Type")
frappe.reload_doc("healthcare", "doctype", "Patient History Custom Document Type")
- setup_patient_history_settings()
\ No newline at end of file
+ setup_patient_history_settings()
diff --git a/erpnext/patches/v13_0/stock_entry_enhancements.py b/erpnext/patches/v13_0/stock_entry_enhancements.py
index 0bdcc9c0e8..7b93ce3576 100644
--- a/erpnext/patches/v13_0/stock_entry_enhancements.py
+++ b/erpnext/patches/v13_0/stock_entry_enhancements.py
@@ -8,18 +8,18 @@ def execute():
frappe.reload_doc("stock", "doctype", "stock_entry")
if frappe.db.has_column("Stock Entry", "add_to_transit"):
frappe.db.sql("""
- UPDATE `tabStock Entry` SET
+ UPDATE `tabStock Entry` SET
stock_entry_type = 'Material Transfer',
purpose = 'Material Transfer',
add_to_transit = 1 WHERE stock_entry_type = 'Send to Warehouse'
""")
- frappe.db.sql("""UPDATE `tabStock Entry` SET
+ frappe.db.sql("""UPDATE `tabStock Entry` SET
stock_entry_type = 'Material Transfer',
purpose = 'Material Transfer'
WHERE stock_entry_type = 'Receive at Warehouse'
""")
-
+
frappe.reload_doc("stock", "doctype", "warehouse_type")
if not frappe.db.exists('Warehouse Type', 'Transit'):
doc = frappe.new_doc('Warehouse Type')
@@ -28,4 +28,4 @@ def execute():
frappe.reload_doc("stock", "doctype", "stock_entry_type")
frappe.delete_doc_if_exists("Stock Entry Type", "Send to Warehouse")
- frappe.delete_doc_if_exists("Stock Entry Type", "Receive at Warehouse")
\ No newline at end of file
+ frappe.delete_doc_if_exists("Stock Entry Type", "Receive at Warehouse")
diff --git a/erpnext/patches/v13_0/update_actual_start_and_end_date_in_wo.py b/erpnext/patches/v13_0/update_actual_start_and_end_date_in_wo.py
index adfa20e368..50f233deef 100644
--- a/erpnext/patches/v13_0/update_actual_start_and_end_date_in_wo.py
+++ b/erpnext/patches/v13_0/update_actual_start_and_end_date_in_wo.py
@@ -38,4 +38,4 @@ def execute():
jc.production_item = wo.production_item, jc.item_name = wo.item_name
WHERE
jc.work_order = wo.name and IFNULL(jc.production_item, "") = ""
- """)
\ No newline at end of file
+ """)
diff --git a/erpnext/patches/v13_0/update_amt_in_work_order_required_items.py b/erpnext/patches/v13_0/update_amt_in_work_order_required_items.py
index eae5ff60b9..dc9ed18ead 100644
--- a/erpnext/patches/v13_0/update_amt_in_work_order_required_items.py
+++ b/erpnext/patches/v13_0/update_amt_in_work_order_required_items.py
@@ -7,4 +7,3 @@ def execute():
frappe.reload_doc("manufacturing", "doctype", "work_order_item")
frappe.db.sql("""UPDATE `tabWork Order Item` SET amount = rate * required_qty""")
-
diff --git a/erpnext/patches/v13_0/update_deferred_settings.py b/erpnext/patches/v13_0/update_deferred_settings.py
index a7d82077b7..bcc09527a2 100644
--- a/erpnext/patches/v13_0/update_deferred_settings.py
+++ b/erpnext/patches/v13_0/update_deferred_settings.py
@@ -8,4 +8,4 @@ def execute():
accounts_settings.book_deferred_entries_based_on = 'Days'
accounts_settings.book_deferred_entries_via_journal_entry = 0
accounts_settings.submit_journal_entries = 0
- accounts_settings.save()
\ No newline at end of file
+ accounts_settings.save()
diff --git a/erpnext/patches/v13_0/update_export_type_for_gst.py b/erpnext/patches/v13_0/update_export_type_for_gst.py
index 3e20212af6..ef70b55d94 100644
--- a/erpnext/patches/v13_0/update_export_type_for_gst.py
+++ b/erpnext/patches/v13_0/update_export_type_for_gst.py
@@ -8,7 +8,7 @@ def execute():
# Update custom fields
fieldname = frappe.db.get_value('Custom Field', {'dt': 'Customer', 'fieldname': 'export_type'})
if fieldname:
- frappe.db.set_value('Custom Field', fieldname,
+ frappe.db.set_value('Custom Field', fieldname,
{
'default': '',
'mandatory_depends_on': 'eval:in_list(["SEZ", "Overseas", "Deemed Export"], doc.gst_category)'
@@ -16,7 +16,7 @@ def execute():
fieldname = frappe.db.get_value('Custom Field', {'dt': 'Supplier', 'fieldname': 'export_type'})
if fieldname:
- frappe.db.set_value('Custom Field', fieldname,
+ frappe.db.set_value('Custom Field', fieldname,
{
'default': '',
'mandatory_depends_on': 'eval:in_list(["SEZ", "Overseas"], doc.gst_category)'
@@ -29,4 +29,4 @@ def execute():
frappe.db.sql("""
UPDATE `tabSupplier` set export_type = '' WHERE gst_category NOT IN ('SEZ', 'Overseas')
- """)
\ No newline at end of file
+ """)
diff --git a/erpnext/patches/v13_0/update_job_card_details.py b/erpnext/patches/v13_0/update_job_card_details.py
index d4e65c6f2f..733b3a960c 100644
--- a/erpnext/patches/v13_0/update_job_card_details.py
+++ b/erpnext/patches/v13_0/update_job_card_details.py
@@ -13,4 +13,4 @@ def execute():
SET jc.hour_rate = wo.hour_rate
WHERE
jc.operation_id = wo.name and jc.docstatus < 2 and wo.hour_rate > 0
- """)
\ No newline at end of file
+ """)
diff --git a/erpnext/patches/v13_0/update_project_template_tasks.py b/erpnext/patches/v13_0/update_project_template_tasks.py
index 8cc27d217f..b41b74205c 100644
--- a/erpnext/patches/v13_0/update_project_template_tasks.py
+++ b/erpnext/patches/v13_0/update_project_template_tasks.py
@@ -44,4 +44,4 @@ def execute():
"task": tsk.name,
"subject": tsk.subject
})
- template.save()
\ No newline at end of file
+ template.save()
diff --git a/erpnext/patches/v13_0/update_reason_for_resignation_in_employee.py b/erpnext/patches/v13_0/update_reason_for_resignation_in_employee.py
index 792118fbee..ccdc334f30 100644
--- a/erpnext/patches/v13_0/update_reason_for_resignation_in_employee.py
+++ b/erpnext/patches/v13_0/update_reason_for_resignation_in_employee.py
@@ -12,4 +12,3 @@ def execute():
SET reason_for_leaving = reason_for_resignation
WHERE status = 'Left' and reason_for_leaving is null and reason_for_resignation is not null
""")
-
diff --git a/erpnext/patches/v13_0/update_returned_qty_in_pr_dn.py b/erpnext/patches/v13_0/update_returned_qty_in_pr_dn.py
index 409f4da859..e642547ef8 100644
--- a/erpnext/patches/v13_0/update_returned_qty_in_pr_dn.py
+++ b/erpnext/patches/v13_0/update_returned_qty_in_pr_dn.py
@@ -29,4 +29,4 @@ def execute():
where docstatus = 1 """)
for doctype in ('Purchase Receipt', 'Delivery Note'):
- update_from_return_docs(doctype)
\ No newline at end of file
+ update_from_return_docs(doctype)
diff --git a/erpnext/patches/v13_0/update_subscription.py b/erpnext/patches/v13_0/update_subscription.py
index 871ebf17c4..d25e9c805b 100644
--- a/erpnext/patches/v13_0/update_subscription.py
+++ b/erpnext/patches/v13_0/update_subscription.py
@@ -38,4 +38,4 @@ def execute():
UPDATE `tabSubscription Plan`
SET price_determination = %s
WHERE price_determination = %s
- """, (value, key))
\ No newline at end of file
+ """, (value, key))
diff --git a/erpnext/patches/v13_0/update_subscription_status_in_memberships.py b/erpnext/patches/v13_0/update_subscription_status_in_memberships.py
index 28e650e9ce..d9c3e453d4 100644
--- a/erpnext/patches/v13_0/update_subscription_status_in_memberships.py
+++ b/erpnext/patches/v13_0/update_subscription_status_in_memberships.py
@@ -6,4 +6,4 @@ def execute():
if frappe.db.has_column('Member', 'subscription_activated'):
frappe.db.sql('UPDATE `tabMember` SET subscription_status = "Active" WHERE subscription_activated = 1')
- frappe.db.sql_ddl('ALTER table `tabMember` DROP COLUMN subscription_activated')
\ No newline at end of file
+ frappe.db.sql_ddl('ALTER table `tabMember` DROP COLUMN subscription_activated')
diff --git a/erpnext/patches/v13_0/update_tds_check_field.py b/erpnext/patches/v13_0/update_tds_check_field.py
index 3d149586a0..341b0e8e2e 100644
--- a/erpnext/patches/v13_0/update_tds_check_field.py
+++ b/erpnext/patches/v13_0/update_tds_check_field.py
@@ -6,4 +6,4 @@ def execute():
frappe.db.sql("""
UPDATE `tabTax Withholding Category` set round_off_tax_amount = 0
WHERE round_off_tax_amount IS NULL
- """)
\ No newline at end of file
+ """)
diff --git a/erpnext/patches/v13_0/update_timesheet_changes.py b/erpnext/patches/v13_0/update_timesheet_changes.py
index 93b7f8e59a..a36c84ea6e 100644
--- a/erpnext/patches/v13_0/update_timesheet_changes.py
+++ b/erpnext/patches/v13_0/update_timesheet_changes.py
@@ -22,4 +22,4 @@ def execute():
exchange_rate = 1.0,
base_total_billable_amount = total_billable_amount,
base_total_billed_amount = total_billed_amount,
- base_total_costing_amount = total_costing_amount""".format(base_currency))
\ No newline at end of file
+ base_total_costing_amount = total_costing_amount""".format(base_currency))
diff --git a/erpnext/patches/v13_0/updates_for_multi_currency_payroll.py b/erpnext/patches/v13_0/updates_for_multi_currency_payroll.py
index 340bf4947b..7d344f9cd7 100644
--- a/erpnext/patches/v13_0/updates_for_multi_currency_payroll.py
+++ b/erpnext/patches/v13_0/updates_for_multi_currency_payroll.py
@@ -96,8 +96,8 @@ def execute():
# update currency in following doctypes based on company currency
doctypes_for_currency = ['Employee Advance', 'Leave Encashment', 'Employee Benefit Application',
- 'Employee Benefit Claim', 'Employee Incentive', 'Additional Salary',
- 'Employee Tax Exemption Declaration', 'Employee Tax Exemption Proof Submission',
+ 'Employee Benefit Claim', 'Employee Incentive', 'Additional Salary',
+ 'Employee Tax Exemption Declaration', 'Employee Tax Exemption Proof Submission',
'Income Tax Slab', 'Retention Bonus', 'Salary Structure']
for dt in doctypes_for_currency:
diff --git a/erpnext/patches/v8_1/removed_roles_from_gst_report_non_indian_account.py b/erpnext/patches/v8_1/removed_roles_from_gst_report_non_indian_account.py
index ccb2e0ec74..55f5f8201f 100644
--- a/erpnext/patches/v8_1/removed_roles_from_gst_report_non_indian_account.py
+++ b/erpnext/patches/v8_1/removed_roles_from_gst_report_non_indian_account.py
@@ -15,4 +15,4 @@ def execute():
where
parenttype = 'Report' and parent in('GST Sales Register',
'GST Purchase Register', 'GST Itemised Sales Register',
- 'GST Itemised Purchase Register', 'Eway Bill')""")
\ No newline at end of file
+ 'GST Itemised Purchase Register', 'Eway Bill')""")
diff --git a/erpnext/patches/v8_1/setup_gst_india.py b/erpnext/patches/v8_1/setup_gst_india.py
index e8b017d864..c214990693 100644
--- a/erpnext/patches/v8_1/setup_gst_india.py
+++ b/erpnext/patches/v8_1/setup_gst_india.py
@@ -50,4 +50,4 @@ ERPNext Team.
try:
sendmail_to_system_managers("[Important] ERPNext GST updates", message)
except Exception as e:
- pass
\ No newline at end of file
+ pass
diff --git a/erpnext/payroll/doctype/additional_salary/test_additional_salary.py b/erpnext/payroll/doctype/additional_salary/test_additional_salary.py
index 4d47f25fcf..2a9c56179e 100644
--- a/erpnext/payroll/doctype/additional_salary/test_additional_salary.py
+++ b/erpnext/payroll/doctype/additional_salary/test_additional_salary.py
@@ -27,7 +27,7 @@ class TestAdditionalSalary(unittest.TestCase):
frappe.db.set_value("Employee", emp_id, "relieving_date", add_days(nowdate(), 1800))
salary_structure = make_salary_structure("Test Salary Structure Additional Salary", "Monthly", employee=emp_id)
add_sal = get_additional_salary(emp_id)
-
+
ss = make_employee_salary_slip("test_additional@salary.com", "Monthly", salary_structure=salary_structure.name)
for earning in ss.earnings:
if earning.salary_component == "Recurring Salary Component":
diff --git a/erpnext/payroll/doctype/employee_benefit_application/employee_benefit_application.py b/erpnext/payroll/doctype/employee_benefit_application/employee_benefit_application.py
index 5ebe514ac0..c7fbb06b10 100644
--- a/erpnext/payroll/doctype/employee_benefit_application/employee_benefit_application.py
+++ b/erpnext/payroll/doctype/employee_benefit_application/employee_benefit_application.py
@@ -253,4 +253,4 @@ def get_earning_components_max_benefits(employee, date, earning_component):
order by name
""", salary_structure, earning_component)
- return amount if amount else 0
\ No newline at end of file
+ return amount if amount else 0
diff --git a/erpnext/payroll/doctype/employee_tax_exemption_sub_category/employee_tax_exemption_sub_category.py b/erpnext/payroll/doctype/employee_tax_exemption_sub_category/employee_tax_exemption_sub_category.py
index a8dd7e4d6d..d3f24c9378 100644
--- a/erpnext/payroll/doctype/employee_tax_exemption_sub_category/employee_tax_exemption_sub_category.py
+++ b/erpnext/payroll/doctype/employee_tax_exemption_sub_category/employee_tax_exemption_sub_category.py
@@ -13,4 +13,4 @@ class EmployeeTaxExemptionSubCategory(Document):
category_max_amount = frappe.db.get_value("Employee Tax Exemption Category", self.exemption_category, "max_amount")
if flt(self.max_amount) > flt(category_max_amount):
frappe.throw(_("Max Exemption Amount cannot be greater than maximum exemption amount {0} of Tax Exemption Category {1}")
- .format(category_max_amount, self.exemption_category))
\ No newline at end of file
+ .format(category_max_amount, self.exemption_category))
diff --git a/erpnext/payroll/doctype/gratuity/gratuity.js b/erpnext/payroll/doctype/gratuity/gratuity.js
index 565d2c49f9..377f3c6491 100644
--- a/erpnext/payroll/doctype/gratuity/gratuity.js
+++ b/erpnext/payroll/doctype/gratuity/gratuity.js
@@ -69,4 +69,4 @@ frappe.ui.form.on('Gratuity', {
}
}
-});
\ No newline at end of file
+});
diff --git a/erpnext/payroll/doctype/gratuity/gratuity.py b/erpnext/payroll/doctype/gratuity/gratuity.py
index 1acd6e342f..8cb804db6f 100644
--- a/erpnext/payroll/doctype/gratuity/gratuity.py
+++ b/erpnext/payroll/doctype/gratuity/gratuity.py
@@ -246,4 +246,3 @@ def get_last_salary_slip(employee):
"employee": employee, 'docstatus': 1
},
order_by = "start_date desc")[0].name
-
diff --git a/erpnext/payroll/doctype/gratuity/gratuity_dashboard.py b/erpnext/payroll/doctype/gratuity/gratuity_dashboard.py
index 5b2489f22c..483e346a32 100644
--- a/erpnext/payroll/doctype/gratuity/gratuity_dashboard.py
+++ b/erpnext/payroll/doctype/gratuity/gratuity_dashboard.py
@@ -17,4 +17,4 @@ def get_data():
'items': ['Additional Salary']
}
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/payroll/doctype/gratuity_rule/gratuity_rule.js b/erpnext/payroll/doctype/gratuity_rule/gratuity_rule.js
index ee6c5df737..014a121c96 100644
--- a/erpnext/payroll/doctype/gratuity_rule/gratuity_rule.js
+++ b/erpnext/payroll/doctype/gratuity_rule/gratuity_rule.js
@@ -37,4 +37,4 @@ frappe.ui.form.on('Gratuity Rule Slab', {
frappe.throw(__("To(Year) year can not be less than From(year) "));
}
}
-});
\ No newline at end of file
+});
diff --git a/erpnext/payroll/doctype/gratuity_rule/gratuity_rule_dashboard.py b/erpnext/payroll/doctype/gratuity_rule/gratuity_rule_dashboard.py
index 0d70163495..0f27315cfb 100644
--- a/erpnext/payroll/doctype/gratuity_rule/gratuity_rule_dashboard.py
+++ b/erpnext/payroll/doctype/gratuity_rule/gratuity_rule_dashboard.py
@@ -10,4 +10,4 @@ def get_data():
'items': ['Gratuity']
}
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/payroll/doctype/payroll_entry/payroll_entry_dashboard.py b/erpnext/payroll/doctype/payroll_entry/payroll_entry_dashboard.py
index 7af507d119..0346a7cc59 100644
--- a/erpnext/payroll/doctype/payroll_entry/payroll_entry_dashboard.py
+++ b/erpnext/payroll/doctype/payroll_entry/payroll_entry_dashboard.py
@@ -13,4 +13,4 @@ def get_data():
'items': ['Salary Slip', 'Journal Entry']
}
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/payroll/doctype/payroll_period/payroll_period_dashboard.py b/erpnext/payroll/doctype/payroll_period/payroll_period_dashboard.py
index 4e9c7c9e7c..e33299559c 100644
--- a/erpnext/payroll/doctype/payroll_period/payroll_period_dashboard.py
+++ b/erpnext/payroll/doctype/payroll_period/payroll_period_dashboard.py
@@ -9,4 +9,4 @@ def get_data():
'items': ['Employee Tax Exemption Proof Submission', 'Employee Tax Exemption Declaration']
},
],
- }
\ No newline at end of file
+ }
diff --git a/erpnext/payroll/doctype/salary_slip/test_salary_slip.js b/erpnext/payroll/doctype/salary_slip/test_salary_slip.js
index 06a1c7d72d..a47eba1887 100644
--- a/erpnext/payroll/doctype/salary_slip/test_salary_slip.js
+++ b/erpnext/payroll/doctype/salary_slip/test_salary_slip.js
@@ -52,4 +52,4 @@ QUnit.test("test salary slip", function(assert) {
() => frappe.click_button('Yes'),
() => done()
]);
-});
\ No newline at end of file
+});
diff --git a/erpnext/payroll/doctype/salary_structure/condition_and_formula_help.html b/erpnext/payroll/doctype/salary_structure/condition_and_formula_help.html
index d07a1ab551..0f6cc37851 100644
--- a/erpnext/payroll/doctype/salary_structure/condition_and_formula_help.html
+++ b/erpnext/payroll/doctype/salary_structure/condition_and_formula_help.html
@@ -44,4 +44,4 @@
Condition: annual_taxable_earning > 20000000
Formula: annual_taxable_earning * 0.10
-
\ No newline at end of file
+
diff --git a/erpnext/payroll/doctype/salary_structure/salary_structure.py b/erpnext/payroll/doctype/salary_structure/salary_structure.py
index 58c445f8a9..6dfb3a57d5 100644
--- a/erpnext/payroll/doctype/salary_structure/salary_structure.py
+++ b/erpnext/payroll/doctype/salary_structure/salary_structure.py
@@ -206,4 +206,3 @@ def get_employees(salary_structure):
salary_structure, salary_structure))
return list(set([d.employee for d in employees]))
-
diff --git a/erpnext/payroll/doctype/salary_structure/salary_structure_dashboard.py b/erpnext/payroll/doctype/salary_structure/salary_structure_dashboard.py
index 547f2b81be..0159e3530f 100644
--- a/erpnext/payroll/doctype/salary_structure/salary_structure_dashboard.py
+++ b/erpnext/payroll/doctype/salary_structure/salary_structure_dashboard.py
@@ -15,4 +15,4 @@ def get_data():
'items': ['Employee Grade']
},
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/payroll/doctype/salary_structure_assignment/salary_structure_assignment.py b/erpnext/payroll/doctype/salary_structure_assignment/salary_structure_assignment.py
index a0c3013061..5fb3ce2a98 100644
--- a/erpnext/payroll/doctype/salary_structure_assignment/salary_structure_assignment.py
+++ b/erpnext/payroll/doctype/salary_structure_assignment/salary_structure_assignment.py
@@ -36,7 +36,7 @@ class SalaryStructureAssignment(Document):
def validate_income_tax_slab(self):
if not self.income_tax_slab:
return
-
+
income_tax_slab_currency = frappe.db.get_value('Income Tax Slab', self.income_tax_slab, 'currency')
if self.currency != income_tax_slab_currency:
frappe.throw(_("Currency of selected Income Tax Slab should be {0} instead of {1}").format(self.currency, income_tax_slab_currency))
@@ -69,4 +69,4 @@ def get_employee_currency(employee):
employee_currency = frappe.db.get_value('Salary Structure Assignment', {'employee': employee}, 'currency')
if not employee_currency:
frappe.throw(_("There is no Salary Structure assigned to {0}. First assign a Salary Stucture.").format(employee))
- return employee_currency
\ No newline at end of file
+ return employee_currency
diff --git a/erpnext/payroll/notification/as b/erpnext/payroll/notification/as
index 7a39557261..05c2c1bec2 100644
--- a/erpnext/payroll/notification/as
+++ b/erpnext/payroll/notification/as
@@ -1 +1 @@
-update from `tabNotification` set module='Payroll' where name = "Retention Bonus"
\ No newline at end of file
+update from `tabNotification` set module='Payroll' where name = "Retention Bonus"
diff --git a/erpnext/payroll/report/bank_remittance/bank_remittance.js b/erpnext/payroll/report/bank_remittance/bank_remittance.js
index 6482ed3451..8b75b4face 100644
--- a/erpnext/payroll/report/bank_remittance/bank_remittance.js
+++ b/erpnext/payroll/report/bank_remittance/bank_remittance.js
@@ -25,4 +25,3 @@ frappe.query_reports["Bank Remittance"] = {
]
}
-
diff --git a/erpnext/payroll/report/income_tax_deductions/income_tax_deductions.js b/erpnext/payroll/report/income_tax_deductions/income_tax_deductions.js
index 4bbb7f6a1b..6ecf2b1960 100644
--- a/erpnext/payroll/report/income_tax_deductions/income_tax_deductions.js
+++ b/erpnext/payroll/report/income_tax_deductions/income_tax_deductions.js
@@ -4,4 +4,4 @@
frappe.require("assets/erpnext/js/salary_slip_deductions_report_filters.js", function() {
frappe.query_reports["Income Tax Deductions"] = erpnext.salary_slip_deductions_report_filters;
-});
\ No newline at end of file
+});
diff --git a/erpnext/payroll/report/salary_payments_based_on_payment_mode/salary_payments_based_on_payment_mode.js b/erpnext/payroll/report/salary_payments_based_on_payment_mode/salary_payments_based_on_payment_mode.js
index 166d982c9c..9b82954169 100644
--- a/erpnext/payroll/report/salary_payments_based_on_payment_mode/salary_payments_based_on_payment_mode.js
+++ b/erpnext/payroll/report/salary_payments_based_on_payment_mode/salary_payments_based_on_payment_mode.js
@@ -4,4 +4,4 @@
frappe.require("assets/erpnext/js/salary_slip_deductions_report_filters.js", function() {
frappe.query_reports["Salary Payments Based On Payment Mode"] = erpnext.salary_slip_deductions_report_filters;
-});
\ No newline at end of file
+});
diff --git a/erpnext/portal/doctype/homepage/homepage.py b/erpnext/portal/doctype/homepage/homepage.py
index 4e4d4774ab..54ea7c62df 100644
--- a/erpnext/portal/doctype/homepage/homepage.py
+++ b/erpnext/portal/doctype/homepage/homepage.py
@@ -23,4 +23,3 @@ class Homepage(Document):
doc.save()
self.append('products', dict(item_code=d.name,
item_name=d.item_name, description=d.description, image=d.image))
-
diff --git a/erpnext/portal/product_configurator/test_product_configurator.py b/erpnext/portal/product_configurator/test_product_configurator.py
index 8aa073402a..ec7c83aa39 100644
--- a/erpnext/portal/product_configurator/test_product_configurator.py
+++ b/erpnext/portal/product_configurator/test_product_configurator.py
@@ -139,4 +139,4 @@ class TestProductConfigurator(unittest.TestCase):
# teardown
doc.delete()
- item_group_doc.delete()
\ No newline at end of file
+ item_group_doc.delete()
diff --git a/erpnext/projects/doctype/activity_cost/activity_cost.js b/erpnext/projects/doctype/activity_cost/activity_cost.js
index ba10153e5c..2d22caad8e 100644
--- a/erpnext/projects/doctype/activity_cost/activity_cost.js
+++ b/erpnext/projects/doctype/activity_cost/activity_cost.js
@@ -1 +1 @@
-cur_frm.add_fetch('employee', 'employee_name', 'employee_name');
\ No newline at end of file
+cur_frm.add_fetch('employee', 'employee_name', 'employee_name');
diff --git a/erpnext/projects/doctype/activity_cost/activity_cost.py b/erpnext/projects/doctype/activity_cost/activity_cost.py
index 862a70717a..99226ea581 100644
--- a/erpnext/projects/doctype/activity_cost/activity_cost.py
+++ b/erpnext/projects/doctype/activity_cost/activity_cost.py
@@ -13,7 +13,7 @@ class ActivityCost(Document):
def validate(self):
self.set_title()
self.check_unique()
-
+
def set_title(self):
if self.employee:
if not self.employee_name:
diff --git a/erpnext/projects/doctype/activity_cost/test_activity_cost.py b/erpnext/projects/doctype/activity_cost/test_activity_cost.py
index 67d76eb1ee..5f35f299b3 100644
--- a/erpnext/projects/doctype/activity_cost/test_activity_cost.py
+++ b/erpnext/projects/doctype/activity_cost/test_activity_cost.py
@@ -22,4 +22,4 @@ class TestActivityCost(unittest.TestCase):
activity_cost1.insert()
activity_cost2 = frappe.copy_doc(activity_cost1)
self.assertRaises(DuplicationError, activity_cost2.insert )
- frappe.db.sql("delete from `tabActivity Cost`")
\ No newline at end of file
+ frappe.db.sql("delete from `tabActivity Cost`")
diff --git a/erpnext/projects/doctype/activity_type/activity_type.py b/erpnext/projects/doctype/activity_type/activity_type.py
index 8b610c2956..50e18ef4de 100644
--- a/erpnext/projects/doctype/activity_type/activity_type.py
+++ b/erpnext/projects/doctype/activity_type/activity_type.py
@@ -5,4 +5,4 @@ from __future__ import unicode_literals
from frappe.model.document import Document
class ActivityType(Document):
- pass
\ No newline at end of file
+ pass
diff --git a/erpnext/projects/doctype/activity_type/test_activity_type.py b/erpnext/projects/doctype/activity_type/test_activity_type.py
index 3ea28dfbe2..dcb01018de 100644
--- a/erpnext/projects/doctype/activity_type/test_activity_type.py
+++ b/erpnext/projects/doctype/activity_type/test_activity_type.py
@@ -4,4 +4,4 @@ from __future__ import unicode_literals
import frappe
-test_records = frappe.get_test_records('Activity Type')
\ No newline at end of file
+test_records = frappe.get_test_records('Activity Type')
diff --git a/erpnext/projects/doctype/project/project_dashboard.html b/erpnext/projects/doctype/project/project_dashboard.html
index f5bfbb7ca1..1f299e3083 100644
--- a/erpnext/projects/doctype/project/project_dashboard.html
+++ b/erpnext/projects/doctype/project/project_dashboard.html
@@ -23,4 +23,4 @@
-{% endfor %}
\ No newline at end of file
+{% endfor %}
diff --git a/erpnext/projects/doctype/project_template/project_template.py b/erpnext/projects/doctype/project_template/project_template.py
index aace40240c..2426fd2af8 100644
--- a/erpnext/projects/doctype/project_template/project_template.py
+++ b/erpnext/projects/doctype/project_template/project_template.py
@@ -22,7 +22,7 @@ class ProjectTemplate(Document):
task_details_format = get_link_to_form("Task",task_details.name)
dependency_task_format = get_link_to_form("Task", dependency_task.task)
frappe.throw(_("Task {0} depends on Task {1}. Please add Task {1} to the Tasks list.").format(frappe.bold(task_details_format), frappe.bold(dependency_task_format)))
-
+
def check_dependent_task_presence(self, task):
for task_details in self.tasks:
if task_details.task == task:
diff --git a/erpnext/projects/doctype/project_template/test_project_template.py b/erpnext/projects/doctype/project_template/test_project_template.py
index 95663cdcbb..d546fd09a3 100644
--- a/erpnext/projects/doctype/project_template/test_project_template.py
+++ b/erpnext/projects/doctype/project_template/test_project_template.py
@@ -26,4 +26,4 @@ def make_project_template(project_template_name, project_tasks=[]):
})
doc.insert()
- return frappe.get_doc('Project Template', project_template_name)
\ No newline at end of file
+ return frappe.get_doc('Project Template', project_template_name)
diff --git a/erpnext/projects/doctype/project_type/project_type.js b/erpnext/projects/doctype/project_type/project_type.js
index a1f941fe14..e3dda5eccc 100644
--- a/erpnext/projects/doctype/project_type/project_type.js
+++ b/erpnext/projects/doctype/project_type/project_type.js
@@ -3,4 +3,4 @@
frappe.ui.form.on('Project Type', {
-});
\ No newline at end of file
+});
diff --git a/erpnext/projects/doctype/project_type/project_type.py b/erpnext/projects/doctype/project_type/project_type.py
index f46876eda2..36137ca018 100644
--- a/erpnext/projects/doctype/project_type/project_type.py
+++ b/erpnext/projects/doctype/project_type/project_type.py
@@ -10,4 +10,4 @@ from frappe import _
class ProjectType(Document):
def on_trash(self):
if self.name == "External":
- frappe.throw(_("You cannot delete Project Type 'External'"))
\ No newline at end of file
+ frappe.throw(_("You cannot delete Project Type 'External'"))
diff --git a/erpnext/projects/doctype/project_update/project_update.py b/erpnext/projects/doctype/project_update/project_update.py
index faa4bf1f9b..2e1ec746ed 100644
--- a/erpnext/projects/doctype/project_update/project_update.py
+++ b/erpnext/projects/doctype/project_update/project_update.py
@@ -39,4 +39,4 @@ def email_sending(project_name,frequency,date_start,date_end,progress,number_of_
for emails in email:
frappe.sendmail(recipients=emails,subject=frappe._(project_name + ' ' + 'Summary'),message = msg)
else:
- pass
\ No newline at end of file
+ pass
diff --git a/erpnext/projects/doctype/project_update/test_project_update.py b/erpnext/projects/doctype/project_update/test_project_update.py
index d5d0919444..2edd2f85a3 100644
--- a/erpnext/projects/doctype/project_update/test_project_update.py
+++ b/erpnext/projects/doctype/project_update/test_project_update.py
@@ -10,4 +10,4 @@ class TestProjectUpdate(unittest.TestCase):
pass
test_records = frappe.get_test_records('Project Update')
-test_ignore = ["Sales Order"]
\ No newline at end of file
+test_ignore = ["Sales Order"]
diff --git a/erpnext/projects/doctype/task/task_tree.js b/erpnext/projects/doctype/task/task_tree.js
index d1d872f28a..9ebfcdd180 100644
--- a/erpnext/projects/doctype/task/task_tree.js
+++ b/erpnext/projects/doctype/task/task_tree.js
@@ -81,4 +81,4 @@ frappe.treeview_settings['Task'] = {
}
],
extend_toolbar: true
-};
\ No newline at end of file
+};
diff --git a/erpnext/projects/doctype/timesheet/timesheet.css b/erpnext/projects/doctype/timesheet/timesheet.css
index 3a38415e6c..1e055629ba 100644
--- a/erpnext/projects/doctype/timesheet/timesheet.css
+++ b/erpnext/projects/doctype/timesheet/timesheet.css
@@ -20,4 +20,4 @@
.playpause {
border-right: 1px dashed #fff;
border-bottom: 1px dashed #fff;
-}
\ No newline at end of file
+}
diff --git a/erpnext/projects/doctype/timesheet/timesheet.js b/erpnext/projects/doctype/timesheet/timesheet.js
index 84c7b8118b..1655b76b98 100644
--- a/erpnext/projects/doctype/timesheet/timesheet.js
+++ b/erpnext/projects/doctype/timesheet/timesheet.js
@@ -399,4 +399,4 @@ function set_project_in_timelog(frm) {
frappe.model.set_value(item.doctype, item.name, "project", frm.doc.parent_project);
});
}
-}
\ No newline at end of file
+}
diff --git a/erpnext/projects/doctype/timesheet/timesheet.py b/erpnext/projects/doctype/timesheet/timesheet.py
index a0042eb7d1..5f569d6bcd 100644
--- a/erpnext/projects/doctype/timesheet/timesheet.py
+++ b/erpnext/projects/doctype/timesheet/timesheet.py
@@ -238,9 +238,9 @@ def get_projectwise_timesheet_data(project=None, parent=None, from_time=None, to
@frappe.whitelist()
def get_timesheet_detail_rate(timelog, currency):
- timelog_detail = frappe.db.sql("""SELECT tsd.billing_amount as billing_amount,
- ts.currency as currency FROM `tabTimesheet Detail` tsd
- INNER JOIN `tabTimesheet` ts ON ts.name=tsd.parent
+ timelog_detail = frappe.db.sql("""SELECT tsd.billing_amount as billing_amount,
+ ts.currency as currency FROM `tabTimesheet Detail` tsd
+ INNER JOIN `tabTimesheet` ts ON ts.name=tsd.parent
WHERE tsd.name = '{0}'""".format(timelog), as_dict = 1)[0]
if timelog_detail.currency:
diff --git a/erpnext/projects/doctype/timesheet/timesheet_calendar.js b/erpnext/projects/doctype/timesheet/timesheet_calendar.js
index 14f016a765..80967ede1c 100644
--- a/erpnext/projects/doctype/timesheet/timesheet_calendar.js
+++ b/erpnext/projects/doctype/timesheet/timesheet_calendar.js
@@ -9,8 +9,8 @@ frappe.views.calendar["Timesheet"] = {
"title": "title"
},
style_map: {
- "0": "info",
- "1": "standard",
+ "0": "info",
+ "1": "standard",
"2": "danger"
},
gantt: true,
diff --git a/erpnext/projects/doctype/timesheet/timesheet_dashboard.py b/erpnext/projects/doctype/timesheet/timesheet_dashboard.py
index acff97a226..088d98c4d5 100644
--- a/erpnext/projects/doctype/timesheet/timesheet_dashboard.py
+++ b/erpnext/projects/doctype/timesheet/timesheet_dashboard.py
@@ -10,4 +10,4 @@ def get_data():
'items': ['Sales Invoice', 'Salary Slip']
}
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/projects/doctype/timesheet/timesheet_list.js b/erpnext/projects/doctype/timesheet/timesheet_list.js
index 1b200f855d..b59fdc96fe 100644
--- a/erpnext/projects/doctype/timesheet/timesheet_list.js
+++ b/erpnext/projects/doctype/timesheet/timesheet_list.js
@@ -4,13 +4,13 @@ frappe.listview_settings['Timesheet'] = {
if (doc.status== "Billed") {
return [__("Billed"), "green", "status,=," + "Billed"]
}
-
+
if (doc.status== "Payslip") {
return [__("Payslip"), "green", "status,=," + "Payslip"]
}
-
+
if (doc.status== "Completed") {
return [__("Completed"), "green", "status,=," + "Completed"]
}
}
-};
\ No newline at end of file
+};
diff --git a/erpnext/projects/report/billing_summary.py b/erpnext/projects/report/billing_summary.py
index 5efde41b5b..a22ed7b833 100644
--- a/erpnext/projects/report/billing_summary.py
+++ b/erpnext/projects/report/billing_summary.py
@@ -144,4 +144,4 @@ def get_billable_and_total_duration(activity, start_time, end_time):
if activity_duration != activity.billing_hours:
billing_duration = activity_duration * activity.billing_hours / activity.hours
- return flt(activity_duration, precision), flt(billing_duration, precision)
\ No newline at end of file
+ return flt(activity_duration, precision), flt(billing_duration, precision)
diff --git a/erpnext/projects/report/daily_timesheet_summary/daily_timesheet_summary.py b/erpnext/projects/report/daily_timesheet_summary/daily_timesheet_summary.py
index 682fb2e09d..3dcae5b1b5 100644
--- a/erpnext/projects/report/daily_timesheet_summary/daily_timesheet_summary.py
+++ b/erpnext/projects/report/daily_timesheet_summary/daily_timesheet_summary.py
@@ -20,8 +20,8 @@ def execute(filters=None):
return columns, data
def get_column():
- return [_("Timesheet") + ":Link/Timesheet:120", _("Employee") + "::150", _("Employee Name") + "::150",
- _("From Datetime") + "::140", _("To Datetime") + "::140", _("Hours") + "::70",
+ return [_("Timesheet") + ":Link/Timesheet:120", _("Employee") + "::150", _("Employee Name") + "::150",
+ _("From Datetime") + "::140", _("To Datetime") + "::140", _("Hours") + "::70",
_("Activity Type") + "::120", _("Task") + ":Link/Task:150",
_("Project") + ":Link/Project:120", _("Status") + "::70"]
@@ -45,4 +45,4 @@ def get_conditions(filters):
if match_conditions:
conditions += " and %s" % match_conditions
- return conditions
\ No newline at end of file
+ return conditions
diff --git a/erpnext/projects/report/delayed_tasks_summary/test_delayed_tasks_summary.py b/erpnext/projects/report/delayed_tasks_summary/test_delayed_tasks_summary.py
index dbeedb4be9..78291b2d78 100644
--- a/erpnext/projects/report/delayed_tasks_summary/test_delayed_tasks_summary.py
+++ b/erpnext/projects/report/delayed_tasks_summary/test_delayed_tasks_summary.py
@@ -10,7 +10,7 @@ class TestDelayedTasksSummary(unittest.TestCase):
def setUp(self):
task1 = create_task("_Test Task 98", add_days(nowdate(), -10), nowdate())
create_task("_Test Task 99", add_days(nowdate(), -10), add_days(nowdate(), -1))
-
+
task1.status = "Completed"
task1.completed_on = add_days(nowdate(), -1)
task1.save()
@@ -38,7 +38,7 @@ class TestDelayedTasksSummary(unittest.TestCase):
]
report = execute(filters)
data = list(filter(lambda x: x.subject == "_Test Task 99", report[1]))[0]
-
+
for key in ["subject", "status", "priority", "delay"]:
self.assertEqual(expected_data[0].get(key), data.get(key))
@@ -51,4 +51,4 @@ class TestDelayedTasksSummary(unittest.TestCase):
def tearDown(self):
for task in ["_Test Task 98", "_Test Task 99"]:
- frappe.get_doc("Task", {"subject": task}).delete()
\ No newline at end of file
+ frappe.get_doc("Task", {"subject": task}).delete()
diff --git a/erpnext/projects/report/employee_billing_summary/employee_billing_summary.py b/erpnext/projects/report/employee_billing_summary/employee_billing_summary.py
index cd5ad7803a..17c92c234d 100644
--- a/erpnext/projects/report/employee_billing_summary/employee_billing_summary.py
+++ b/erpnext/projects/report/employee_billing_summary/employee_billing_summary.py
@@ -11,4 +11,4 @@ def execute(filters=None):
columns = get_columns()
data = get_data(filters)
- return columns, data
\ No newline at end of file
+ return columns, data
diff --git a/erpnext/projects/report/employee_hours_utilization_based_on_timesheet/test_employee_util.py b/erpnext/projects/report/employee_hours_utilization_based_on_timesheet/test_employee_util.py
index 0e5a59756e..969fc556e8 100644
--- a/erpnext/projects/report/employee_hours_utilization_based_on_timesheet/test_employee_util.py
+++ b/erpnext/projects/report/employee_hours_utilization_based_on_timesheet/test_employee_util.py
@@ -195,4 +195,4 @@ class TestEmployeeUtilization(unittest.TestCase):
'per_util': 27.78,
'per_util_billed_only': 27.78
}
- ]
\ No newline at end of file
+ ]
diff --git a/erpnext/projects/report/project_billing_summary/project_billing_summary.py b/erpnext/projects/report/project_billing_summary/project_billing_summary.py
index cd5ad7803a..17c92c234d 100644
--- a/erpnext/projects/report/project_billing_summary/project_billing_summary.py
+++ b/erpnext/projects/report/project_billing_summary/project_billing_summary.py
@@ -11,4 +11,4 @@ def execute(filters=None):
columns = get_columns()
data = get_data(filters)
- return columns, data
\ No newline at end of file
+ return columns, data
diff --git a/erpnext/projects/report/project_profitability/project_profitability.py b/erpnext/projects/report/project_profitability/project_profitability.py
index 9139d84fac..0a52f7bf90 100644
--- a/erpnext/projects/report/project_profitability/project_profitability.py
+++ b/erpnext/projects/report/project_profitability/project_profitability.py
@@ -208,4 +208,4 @@ def get_columns():
"options": "Currency",
"width": 80
}
- ]
\ No newline at end of file
+ ]
diff --git a/erpnext/projects/web_form/tasks/tasks.js b/erpnext/projects/web_form/tasks/tasks.js
index 699703c579..ffc5e98425 100644
--- a/erpnext/projects/web_form/tasks/tasks.js
+++ b/erpnext/projects/web_form/tasks/tasks.js
@@ -1,3 +1,3 @@
frappe.ready(function() {
// bind events here
-})
\ No newline at end of file
+})
diff --git a/erpnext/projects/web_form/tasks/tasks.py b/erpnext/projects/web_form/tasks/tasks.py
index e97f36d04b..e5a94048be 100644
--- a/erpnext/projects/web_form/tasks/tasks.py
+++ b/erpnext/projects/web_form/tasks/tasks.py
@@ -6,7 +6,7 @@ def get_context(context):
if frappe.form_dict.project:
context.parents = [{'title': frappe.form_dict.project, 'route': '/projects?project='+ frappe.form_dict.project}]
context.success_url = "/projects?project=" + frappe.form_dict.project
-
+
elif context.doc and context.doc.get('project'):
context.parents = [{'title': context.doc.project, 'route': '/projects?project='+ context.doc.project}]
context.success_url = "/projects?project=" + context.doc.project
diff --git a/erpnext/public/images/erpnext-favicon.svg b/erpnext/public/images/erpnext-favicon.svg
index a3ac3bb2ce..6bc6b2c2db 100644
--- a/erpnext/public/images/erpnext-favicon.svg
+++ b/erpnext/public/images/erpnext-favicon.svg
@@ -2,4 +2,4 @@
-
\ No newline at end of file
+
diff --git a/erpnext/public/images/erpnext-logo.svg b/erpnext/public/images/erpnext-logo.svg
index a3ac3bb2ce..6bc6b2c2db 100644
--- a/erpnext/public/images/erpnext-logo.svg
+++ b/erpnext/public/images/erpnext-logo.svg
@@ -2,4 +2,4 @@
-
\ No newline at end of file
+
diff --git a/erpnext/public/images/pos.svg b/erpnext/public/images/pos.svg
index 3d12d9cb86..90714e9491 100644
--- a/erpnext/public/images/pos.svg
+++ b/erpnext/public/images/pos.svg
@@ -1,4 +1,4 @@
-
\ No newline at end of file
+
diff --git a/erpnext/public/js/education/assessment_result_tool.html b/erpnext/public/js/education/assessment_result_tool.html
index b591010ec8..f7d1ab39fc 100644
--- a/erpnext/public/js/education/assessment_result_tool.html
+++ b/erpnext/public/js/education/assessment_result_tool.html
@@ -69,4 +69,4 @@
{% endfor %}
-
\ No newline at end of file
+
diff --git a/erpnext/public/js/education/student_button.html b/erpnext/public/js/education/student_button.html
index 3cf259216a..b64c73a43c 100644
--- a/erpnext/public/js/education/student_button.html
+++ b/erpnext/public/js/education/student_button.html
@@ -1,12 +1,12 @@
\ No newline at end of file
+
diff --git a/erpnext/public/js/erpnext.bundle.js b/erpnext/public/js/erpnext.bundle.js
index 519cfcac72..9f7f29ad72 100644
--- a/erpnext/public/js/erpnext.bundle.js
+++ b/erpnext/public/js/erpnext.bundle.js
@@ -24,4 +24,3 @@ import "./telephony";
import "./templates/call_link.html";
// import { sum } from 'frappe/public/utils/util.js'
-
diff --git a/erpnext/public/js/financial_statements.js b/erpnext/public/js/financial_statements.js
index b2f7afe53f..0d79b10c04 100644
--- a/erpnext/public/js/financial_statements.js
+++ b/erpnext/public/js/financial_statements.js
@@ -176,5 +176,3 @@ function get_filters() {
return filters;
}
-
-
diff --git a/erpnext/public/js/hierarchy-chart.bundle.js b/erpnext/public/js/hierarchy-chart.bundle.js
index 26ab6d92b9..02703139dd 100644
--- a/erpnext/public/js/hierarchy-chart.bundle.js
+++ b/erpnext/public/js/hierarchy-chart.bundle.js
@@ -1,3 +1,3 @@
import "./hierarchy_chart/hierarchy_chart_desktop.js";
import "./hierarchy_chart/hierarchy_chart_mobile.js";
-import "./templates/node_card.html";
\ No newline at end of file
+import "./templates/node_card.html";
diff --git a/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js b/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
index da050abc6e..23ec2fdb84 100644
--- a/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
+++ b/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
@@ -597,4 +597,4 @@ erpnext.HierarchyChart = class {
$(path).remove();
});
}
-};
\ No newline at end of file
+};
diff --git a/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js b/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
index bd7946a1e1..b1b78c0517 100644
--- a/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
+++ b/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
@@ -548,4 +548,4 @@ erpnext.HierarchyChartMobile = class {
$(`path[data-parent="${node_parent}"]`).remove();
this.add_connector(node_parent, node_id);
}
-};
\ No newline at end of file
+};
diff --git a/erpnext/public/js/hub/components/ReviewArea.vue b/erpnext/public/js/hub/components/ReviewArea.vue
index 5e4e439f3d..aa83bb0e46 100644
--- a/erpnext/public/js/hub/components/ReviewArea.vue
+++ b/erpnext/public/js/hub/components/ReviewArea.vue
@@ -137,4 +137,4 @@ export default {
}
}
}
-
\ No newline at end of file
+
diff --git a/erpnext/public/js/hub/components/ReviewTimelineItem.vue b/erpnext/public/js/hub/components/ReviewTimelineItem.vue
index f0fe001973..d0e83f3b1c 100644
--- a/erpnext/public/js/hub/components/ReviewTimelineItem.vue
+++ b/erpnext/public/js/hub/components/ReviewTimelineItem.vue
@@ -51,4 +51,3 @@ export default {
}
}
-
diff --git a/erpnext/public/js/hub/pages/FeaturedItems.vue b/erpnext/public/js/hub/pages/FeaturedItems.vue
index 63ae7e99bb..8380b2b2c0 100644
--- a/erpnext/public/js/hub/pages/FeaturedItems.vue
+++ b/erpnext/public/js/hub/pages/FeaturedItems.vue
@@ -69,7 +69,7 @@ export default {
const item_name = this.items.filter(item => item.hub_item_name === hub_item_name);
- alert_message = __('{0} removed. {1}', [item_name,
+ alert_message = __('{0} removed. {1}', [item_name,
`${__('Undo')} `]);
alert = frappe.show_alert(alert_message, grace_period / 1000,
{
diff --git a/erpnext/public/js/hub/pages/Publish.vue b/erpnext/public/js/hub/pages/Publish.vue
index 96fa0aae4e..ecba4b1e5a 100644
--- a/erpnext/public/js/hub/pages/Publish.vue
+++ b/erpnext/public/js/hub/pages/Publish.vue
@@ -78,7 +78,7 @@ export default {
empty_state_message: __('No Items selected yet. Browse and click on items below to publish.'),
valid_items_instruction: __('Only items with an image and description can be published. Please update them if an item in your inventory does not appear.'),
last_sync_message: (hub.settings.last_sync_datetime)
- ? __('Last sync was {0}.', [`${comment_when(hub.settings.last_sync_datetime)} `]) +
+ ? __('Last sync was {0}.', [`${comment_when(hub.settings.last_sync_datetime)} `]) +
` ${__('See your Published Items.')} `
: ''
};
diff --git a/erpnext/public/js/hub/pages/Seller.vue b/erpnext/public/js/hub/pages/Seller.vue
index c0903c64c3..3c9b800f4a 100644
--- a/erpnext/public/js/hub/pages/Seller.vue
+++ b/erpnext/public/js/hub/pages/Seller.vue
@@ -24,7 +24,7 @@
- {{ item_container_heading }}
+ {{ item_container_heading }}
Customize your Featured Items
@@ -160,7 +160,7 @@ export default {
];
setTimeout(() => this.init_seller_traffic_chart(), 1);
-
+
});
},
diff --git a/erpnext/public/js/hub/vue-plugins.js b/erpnext/public/js/hub/vue-plugins.js
index 6e6a7cb598..4912d68499 100644
--- a/erpnext/public/js/hub/vue-plugins.js
+++ b/erpnext/public/js/hub/vue-plugins.js
@@ -55,4 +55,4 @@ const handleImage = (el, src) => {
Vue.filter('striphtml', function (text) {
return strip_html(text || '');
-});
\ No newline at end of file
+});
diff --git a/erpnext/public/js/leaflet/leaflet.draw.js b/erpnext/public/js/leaflet/leaflet.draw.js
index 4352f7025b..26f1e19da5 100755
--- a/erpnext/public/js/leaflet/leaflet.draw.js
+++ b/erpnext/public/js/leaflet/leaflet.draw.js
@@ -140,4 +140,4 @@
e.on("click", this._removeLayer, this) }, _disableLayerDelete: function(t) { var e = t.layer || t.target || t;
e.off("click", this._removeLayer, this), this._deletedLayers.removeLayer(e) }, _removeLayer: function(t) { var e = t.layer || t.target || t;
this._deletableLayers.removeLayer(e), this._deletedLayers.addLayer(e) }, _onMouseMove: function(t) { this._tooltip.updatePosition(t.latlng) }, _hasAvailableLayers: function() { return 0 !== this._deletableLayers.getLayers().length } })
-}(window, document);
\ No newline at end of file
+}(window, document);
diff --git a/erpnext/public/js/leaflet/leaflet.js b/erpnext/public/js/leaflet/leaflet.js
index 41d9bb9ed4..91dd3d434c 100755
--- a/erpnext/public/js/leaflet/leaflet.js
+++ b/erpnext/public/js/leaflet/leaflet.js
@@ -768,4 +768,4 @@
r = this._locateOptions; if (r.setView) { var a = this.getBoundsZoom(s);
this.setView(n, r.maxZoom ? Math.min(a, r.maxZoom) : a) } var h = { latlng: n, bounds: s, timestamp: t.timestamp }; for (var l in t.coords) "number" == typeof t.coords[l] && (h[l] = t.coords[l]);
this.fire("locationfound", h) } })
-}(window, document);
\ No newline at end of file
+}(window, document);
diff --git a/erpnext/public/js/projects/timer.js b/erpnext/public/js/projects/timer.js
index 26be997d48..0e5c0d3720 100644
--- a/erpnext/public/js/projects/timer.js
+++ b/erpnext/public/js/projects/timer.js
@@ -159,4 +159,4 @@ erpnext.timesheet.control_timer = function(frm, dialog, row, timestamp=0) {
$btn_complete.hide();
$btn_start.show();
}
-};
\ No newline at end of file
+};
diff --git a/erpnext/public/js/setup_wizard.js b/erpnext/public/js/setup_wizard.js
index 6f5d67c746..38e1eb5156 100644
--- a/erpnext/public/js/setup_wizard.js
+++ b/erpnext/public/js/setup_wizard.js
@@ -147,7 +147,7 @@ erpnext.setup.slides_settings = [
}
// Validate bank name
- if(me.values.bank_account) {
+ if(me.values.bank_account) {
frappe.call({
async: false,
method: "erpnext.accounts.doctype.account.chart_of_accounts.chart_of_accounts.validate_bank_account",
diff --git a/erpnext/public/js/stock_analytics.js b/erpnext/public/js/stock_analytics.js
index dfe2c88ea8..a343c3402a 100644
--- a/erpnext/public/js/stock_analytics.js
+++ b/erpnext/public/js/stock_analytics.js
@@ -204,4 +204,3 @@ erpnext.StockAnalytics = class StockAnalytics extends erpnext.StockGridReport {
frappe.set_route("query-report", "Stock Ledger");
}
};
-
diff --git a/erpnext/public/js/templates/item_quick_entry.html b/erpnext/public/js/templates/item_quick_entry.html
index 6a5f36da77..e5e7869062 100644
--- a/erpnext/public/js/templates/item_quick_entry.html
+++ b/erpnext/public/js/templates/item_quick_entry.html
@@ -1,3 +1,3 @@
{{ __("Variant Attributes") }}
-
\ No newline at end of file
+
diff --git a/erpnext/public/js/templates/item_selector.html b/erpnext/public/js/templates/item_selector.html
index 58fb26c0e4..86a15f4907 100644
--- a/erpnext/public/js/templates/item_selector.html
+++ b/erpnext/public/js/templates/item_selector.html
@@ -34,4 +34,4 @@
{% if ((i % 4 === 3) || (i===data.length - 1)) { %}{% } %}
{% endfor %}
-
\ No newline at end of file
+
diff --git a/erpnext/public/js/templates/node_card.html b/erpnext/public/js/templates/node_card.html
index fb94df85ed..4cb6ee03c0 100644
--- a/erpnext/public/js/templates/node_card.html
+++ b/erpnext/public/js/templates/node_card.html
@@ -30,4 +30,4 @@
-
\ No newline at end of file
+
diff --git a/erpnext/public/js/utils/dimension_tree_filter.js b/erpnext/public/js/utils/dimension_tree_filter.js
index 96e181788e..bb23f1512b 100644
--- a/erpnext/public/js/utils/dimension_tree_filter.js
+++ b/erpnext/public/js/utils/dimension_tree_filter.js
@@ -100,4 +100,4 @@ erpnext.accounts.dimensions = {
});
}
}
-};
\ No newline at end of file
+};
diff --git a/erpnext/public/scss/hierarchy_chart.scss b/erpnext/public/scss/hierarchy_chart.scss
index a66d6474e0..57d5e8414a 100644
--- a/erpnext/public/scss/hierarchy_chart.scss
+++ b/erpnext/public/scss/hierarchy_chart.scss
@@ -310,4 +310,4 @@
display: flex;
flex-direction: column;
align-items: center;
-}
\ No newline at end of file
+}
diff --git a/erpnext/public/scss/shopping_cart.scss b/erpnext/public/scss/shopping_cart.scss
index 5962859be5..490a7c4af7 100644
--- a/erpnext/public/scss/shopping_cart.scss
+++ b/erpnext/public/scss/shopping_cart.scss
@@ -483,4 +483,3 @@ body.product-page {
border: 1px solid var(--dark-border-color);
}
}
-
diff --git a/erpnext/public/scss/website.scss b/erpnext/public/scss/website.scss
index f4325c03f5..9ea8416034 100644
--- a/erpnext/public/scss/website.scss
+++ b/erpnext/public/scss/website.scss
@@ -67,4 +67,4 @@
.card-body > .card-title {
line-height: 1.3;
}
-}
\ No newline at end of file
+}
diff --git a/erpnext/quality_management/doctype/quality_action/quality_action.js b/erpnext/quality_management/doctype/quality_action/quality_action.js
index e216a7539c..b44f2a2034 100644
--- a/erpnext/quality_management/doctype/quality_action/quality_action.js
+++ b/erpnext/quality_management/doctype/quality_action/quality_action.js
@@ -3,4 +3,4 @@
frappe.ui.form.on('Quality Action', {
-});
\ No newline at end of file
+});
diff --git a/erpnext/quality_management/doctype/quality_action/quality_action.py b/erpnext/quality_management/doctype/quality_action/quality_action.py
index d6fa5051ee..02401ba689 100644
--- a/erpnext/quality_management/doctype/quality_action/quality_action.py
+++ b/erpnext/quality_management/doctype/quality_action/quality_action.py
@@ -8,4 +8,4 @@ from frappe.model.document import Document
class QualityAction(Document):
def validate(self):
- self.status = 'Open' if any([d.status=='Open' for d in self.resolutions]) else 'Completed'
\ No newline at end of file
+ self.status = 'Open' if any([d.status=='Open' for d in self.resolutions]) else 'Completed'
diff --git a/erpnext/quality_management/doctype/quality_action/test_quality_action.py b/erpnext/quality_management/doctype/quality_action/test_quality_action.py
index 24b97ca3a0..98d665f391 100644
--- a/erpnext/quality_management/doctype/quality_action/test_quality_action.py
+++ b/erpnext/quality_management/doctype/quality_action/test_quality_action.py
@@ -8,4 +8,4 @@ import unittest
class TestQualityAction(unittest.TestCase):
# quality action has no code
- pass
\ No newline at end of file
+ pass
diff --git a/erpnext/quality_management/doctype/quality_feedback/quality_feedback.py b/erpnext/quality_management/doctype/quality_feedback/quality_feedback.py
index 5a8ec73cfe..d3e96cf2d9 100644
--- a/erpnext/quality_management/doctype/quality_feedback/quality_feedback.py
+++ b/erpnext/quality_management/doctype/quality_feedback/quality_feedback.py
@@ -21,4 +21,3 @@ class QualityFeedback(Document):
self.document_type ='User'
self.document_name = frappe.session.user
self.set_parameters()
-
diff --git a/erpnext/quality_management/doctype/quality_feedback_template/test_quality_feedback_template.py b/erpnext/quality_management/doctype/quality_feedback_template/test_quality_feedback_template.py
index b3eed10383..afed14b6ad 100644
--- a/erpnext/quality_management/doctype/quality_feedback_template/test_quality_feedback_template.py
+++ b/erpnext/quality_management/doctype/quality_feedback_template/test_quality_feedback_template.py
@@ -7,4 +7,4 @@ import frappe
import unittest
class TestQualityFeedbackTemplate(unittest.TestCase):
- pass
\ No newline at end of file
+ pass
diff --git a/erpnext/quality_management/doctype/quality_goal/quality_goal.py b/erpnext/quality_management/doctype/quality_goal/quality_goal.py
index f3fe986d53..3e616b75ce 100644
--- a/erpnext/quality_management/doctype/quality_goal/quality_goal.py
+++ b/erpnext/quality_management/doctype/quality_goal/quality_goal.py
@@ -9,4 +9,4 @@ from frappe.model.document import Document
class QualityGoal(Document):
def validate(self):
- pass
\ No newline at end of file
+ pass
diff --git a/erpnext/quality_management/doctype/quality_goal/test_quality_goal.py b/erpnext/quality_management/doctype/quality_goal/test_quality_goal.py
index f61d6e581d..0e135b5021 100644
--- a/erpnext/quality_management/doctype/quality_goal/test_quality_goal.py
+++ b/erpnext/quality_management/doctype/quality_goal/test_quality_goal.py
@@ -22,4 +22,4 @@ def get_quality_goal():
objectives = [
dict(objective = 'Check test cases', target='100', uom='Percent')
]
- )).insert()
\ No newline at end of file
+ )).insert()
diff --git a/erpnext/quality_management/doctype/quality_meeting/quality_meeting.py b/erpnext/quality_management/doctype/quality_meeting/quality_meeting.py
index f8de22958b..9e453ebfc2 100644
--- a/erpnext/quality_management/doctype/quality_meeting/quality_meeting.py
+++ b/erpnext/quality_management/doctype/quality_meeting/quality_meeting.py
@@ -6,4 +6,4 @@ from __future__ import unicode_literals
from frappe.model.document import Document
class QualityMeeting(Document):
- pass
\ No newline at end of file
+ pass
diff --git a/erpnext/quality_management/doctype/quality_meeting/quality_meeting_list.js b/erpnext/quality_management/doctype/quality_meeting/quality_meeting_list.js
index ff85c84dc9..5fd1b30eb4 100644
--- a/erpnext/quality_management/doctype/quality_meeting/quality_meeting_list.js
+++ b/erpnext/quality_management/doctype/quality_meeting/quality_meeting_list.js
@@ -8,4 +8,4 @@ frappe.listview_settings['Quality Meeting'] = {
return [__("Close"), "green", ",status=,Close"];
}
}
-};
\ No newline at end of file
+};
diff --git a/erpnext/quality_management/doctype/quality_meeting/test_quality_meeting.py b/erpnext/quality_management/doctype/quality_meeting/test_quality_meeting.py
index 754bccb06e..6bf4c179c6 100644
--- a/erpnext/quality_management/doctype/quality_meeting/test_quality_meeting.py
+++ b/erpnext/quality_management/doctype/quality_meeting/test_quality_meeting.py
@@ -8,4 +8,4 @@ import unittest
class TestQualityMeeting(unittest.TestCase):
# nothing to test
- pass
\ No newline at end of file
+ pass
diff --git a/erpnext/quality_management/doctype/quality_procedure/quality_procedure.js b/erpnext/quality_management/doctype/quality_procedure/quality_procedure.js
index ac876229ec..fd2b6a4eaa 100644
--- a/erpnext/quality_management/doctype/quality_procedure/quality_procedure.js
+++ b/erpnext/quality_management/doctype/quality_procedure/quality_procedure.js
@@ -19,4 +19,4 @@ frappe.ui.form.on('Quality Procedure', {
};
});
}
-});
\ No newline at end of file
+});
diff --git a/erpnext/quality_management/doctype/quality_procedure/quality_procedure.py b/erpnext/quality_management/doctype/quality_procedure/quality_procedure.py
index 53f4e6c70f..117db0012b 100644
--- a/erpnext/quality_management/doctype/quality_procedure/quality_procedure.py
+++ b/erpnext/quality_management/doctype/quality_procedure/quality_procedure.py
@@ -77,4 +77,4 @@ def add_node():
if args.parent_quality_procedure == 'All Quality Procedures':
args.parent_quality_procedure = None
- return frappe.get_doc(args).insert()
\ No newline at end of file
+ return frappe.get_doc(args).insert()
diff --git a/erpnext/quality_management/doctype/quality_procedure/quality_procedure_tree.js b/erpnext/quality_management/doctype/quality_procedure/quality_procedure_tree.js
index eeb4cf617c..2851fcc596 100644
--- a/erpnext/quality_management/doctype/quality_procedure/quality_procedure_tree.js
+++ b/erpnext/quality_management/doctype/quality_procedure/quality_procedure_tree.js
@@ -31,4 +31,4 @@ frappe.treeview_settings["Quality Procedure"] = {
onload: function(treeview) {
treeview.make_tree();
},
-};
\ No newline at end of file
+};
diff --git a/erpnext/quality_management/doctype/quality_procedure/test_quality_procedure.py b/erpnext/quality_management/doctype/quality_procedure/test_quality_procedure.py
index 36bdf26acf..4fa7734bc6 100644
--- a/erpnext/quality_management/doctype/quality_procedure/test_quality_procedure.py
+++ b/erpnext/quality_management/doctype/quality_procedure/test_quality_procedure.py
@@ -47,4 +47,4 @@ def create_procedure():
processes = [
dict(process_description = 'Test Step 1')
]
- )).insert()
\ No newline at end of file
+ )).insert()
diff --git a/erpnext/quality_management/doctype/quality_review/quality_review.js b/erpnext/quality_management/doctype/quality_review/quality_review.js
index 67371bfc5c..0e6b703410 100644
--- a/erpnext/quality_management/doctype/quality_review/quality_review.js
+++ b/erpnext/quality_management/doctype/quality_review/quality_review.js
@@ -22,4 +22,4 @@ frappe.ui.form.on('Quality Review', {
}
});
},
-});
\ No newline at end of file
+});
diff --git a/erpnext/quality_management/doctype/quality_review/quality_review.py b/erpnext/quality_management/doctype/quality_review/quality_review.py
index e3a8b073f0..34cc890e21 100644
--- a/erpnext/quality_management/doctype/quality_review/quality_review.py
+++ b/erpnext/quality_management/doctype/quality_review/quality_review.py
@@ -61,4 +61,4 @@ def get_quarter(month):
if month in ["January", "April", "July", "October"]:
return True
else:
- return False
\ No newline at end of file
+ return False
diff --git a/erpnext/quality_management/doctype/quality_review/quality_review_list.js b/erpnext/quality_management/doctype/quality_review/quality_review_list.js
index e2eb31b55a..b0be783de5 100644
--- a/erpnext/quality_management/doctype/quality_review/quality_review_list.js
+++ b/erpnext/quality_management/doctype/quality_review/quality_review_list.js
@@ -9,4 +9,4 @@ frappe.listview_settings['Quality Review'] = {
return [__("Action Initialised"), "red", "action,=,Action Initialised"];
}
}
-};
\ No newline at end of file
+};
diff --git a/erpnext/quality_management/doctype/quality_review/test_quality_review.py b/erpnext/quality_management/doctype/quality_review/test_quality_review.py
index a7d92da8ac..161ecd01ef 100644
--- a/erpnext/quality_management/doctype/quality_review/test_quality_review.py
+++ b/erpnext/quality_management/doctype/quality_review/test_quality_review.py
@@ -19,4 +19,4 @@ class TestQualityReview(unittest.TestCase):
self.assertEqual(quality_goal.objectives[0].target, quality_review.reviews[0].target)
quality_review.delete()
- quality_goal.delete()
\ No newline at end of file
+ quality_goal.delete()
diff --git a/erpnext/regional/address_template/setup.py b/erpnext/regional/address_template/setup.py
index 9f318de345..1b4087d77b 100644
--- a/erpnext/regional/address_template/setup.py
+++ b/erpnext/regional/address_template/setup.py
@@ -10,7 +10,7 @@ def set_up_address_templates(default_country=None):
def get_address_templates():
"""
Return country and path for all HTML files in this directory.
-
+
Returns a list of dicts.
"""
def country(file_name):
diff --git a/erpnext/regional/address_template/templates/germany.html b/erpnext/regional/address_template/templates/germany.html
index 7fa4c32612..25c9c9d32e 100644
--- a/erpnext/regional/address_template/templates/germany.html
+++ b/erpnext/regional/address_template/templates/germany.html
@@ -3,6 +3,6 @@
{% if country in ["Germany", "Deutschland"] %}
{{ pincode }} {{ city }}
{% else %}
- {{ pincode }} {{ city | upper }}
+ {{ pincode }} {{ city | upper }}
{{ country | upper }}
{% endif %}
diff --git a/erpnext/regional/doctype/e_invoice_settings/e_invoice_settings.py b/erpnext/regional/doctype/e_invoice_settings/e_invoice_settings.py
index c24ad886ea..4f6b3eca7a 100644
--- a/erpnext/regional/doctype/e_invoice_settings/e_invoice_settings.py
+++ b/erpnext/regional/doctype/e_invoice_settings/e_invoice_settings.py
@@ -11,4 +11,3 @@ class EInvoiceSettings(Document):
def validate(self):
if self.enable and not self.credentials:
frappe.throw(_('You must add atleast one credentials to be able to use E Invoicing.'))
-
diff --git a/erpnext/regional/doctype/gst_hsn_code/gst_hsn_code.js b/erpnext/regional/doctype/gst_hsn_code/gst_hsn_code.js
index 7ff4de4863..347fdfe61b 100644
--- a/erpnext/regional/doctype/gst_hsn_code/gst_hsn_code.js
+++ b/erpnext/regional/doctype/gst_hsn_code/gst_hsn_code.js
@@ -25,4 +25,4 @@ frappe.ui.form.on('GST HSN Code', {
});
}
}
-});
\ No newline at end of file
+});
diff --git a/erpnext/regional/doctype/gst_hsn_code/gst_hsn_code.py b/erpnext/regional/doctype/gst_hsn_code/gst_hsn_code.py
index 86cd4d1545..4791dc2675 100644
--- a/erpnext/regional/doctype/gst_hsn_code/gst_hsn_code.py
+++ b/erpnext/regional/doctype/gst_hsn_code/gst_hsn_code.py
@@ -30,4 +30,4 @@ def update_item_document(items, taxes):
'tax_category': tax.tax_category,
'valid_from': tax.valid_from
})
- item_to_be_updated.save()
\ No newline at end of file
+ item_to_be_updated.save()
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 3b6a45a3b4..f3fc60fdb6 100644
--- a/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.html
+++ b/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.html
@@ -294,4 +294,4 @@
text-align: right;
}
-
\ No newline at end of file
+
diff --git a/erpnext/regional/doctype/import_supplier_invoice/import_supplier_invoice.js b/erpnext/regional/doctype/import_supplier_invoice/import_supplier_invoice.js
index c2d6edfc77..5918ec8b31 100644
--- a/erpnext/regional/doctype/import_supplier_invoice/import_supplier_invoice.js
+++ b/erpnext/regional/doctype/import_supplier_invoice/import_supplier_invoice.js
@@ -43,4 +43,4 @@ frappe.ui.form.on('Import Supplier Invoice', {
}
}
-});
\ No newline at end of file
+});
diff --git a/erpnext/regional/doctype/lower_deduction_certificate/lower_deduction_certificate.py b/erpnext/regional/doctype/lower_deduction_certificate/lower_deduction_certificate.py
index ad60db0559..656c3296e5 100644
--- a/erpnext/regional/doctype/lower_deduction_certificate/lower_deduction_certificate.py
+++ b/erpnext/regional/doctype/lower_deduction_certificate/lower_deduction_certificate.py
@@ -13,7 +13,7 @@ class LowerDeductionCertificate(Document):
def validate(self):
self.validate_dates()
self.validate_supplier_against_section_code()
-
+
def validate_dates(self):
if getdate(self.valid_upto) < getdate(self.valid_from):
frappe.throw(_("Valid Upto date cannot be before Valid From date"))
@@ -44,4 +44,4 @@ class LowerDeductionCertificate(Document):
return True
elif getdate(self.valid_from) <= valid_from and valid_upto <= getdate(self.valid_upto):
return True
- return False
\ No newline at end of file
+ return False
diff --git a/erpnext/regional/doctype/tax_exemption_80g_certificate/test_tax_exemption_80g_certificate.py b/erpnext/regional/doctype/tax_exemption_80g_certificate/test_tax_exemption_80g_certificate.py
index c478b0f322..41b4203668 100644
--- a/erpnext/regional/doctype/tax_exemption_80g_certificate/test_tax_exemption_80g_certificate.py
+++ b/erpnext/regional/doctype/tax_exemption_80g_certificate/test_tax_exemption_80g_certificate.py
@@ -98,4 +98,4 @@ def create_80g_certificate(args):
certificate.update(args)
- return certificate
\ No newline at end of file
+ return certificate
diff --git a/erpnext/regional/germany/utils/datev/datev_constants.py b/erpnext/regional/germany/utils/datev/datev_constants.py
index 63f9a777bb..be3d7a3e54 100644
--- a/erpnext/regional/germany/utils/datev/datev_constants.py
+++ b/erpnext/regional/germany/utils/datev/datev_constants.py
@@ -455,7 +455,7 @@ ACCOUNT_NAME_COLUMNS = [
"Konto",
# Account name
"Kontenbeschriftung",
- # Language of the account name
+ # Language of the account name
# "de-DE" or "en-GB"
"Sprach-ID"
]
diff --git a/erpnext/regional/india/e_invoice/einvoice.js b/erpnext/regional/india/e_invoice/einvoice.js
index 8ad30fa910..348f0c6fee 100644
--- a/erpnext/regional/india/e_invoice/einvoice.js
+++ b/erpnext/regional/india/e_invoice/einvoice.js
@@ -289,4 +289,4 @@ const show_einvoice_preview = (frm, einvoice) => {
}
}
});
-};
\ No newline at end of file
+};
diff --git a/erpnext/regional/india/e_invoice/utils.py b/erpnext/regional/india/e_invoice/utils.py
index fa7e88d3a1..765b51f435 100644
--- a/erpnext/regional/india/e_invoice/utils.py
+++ b/erpnext/regional/india/e_invoice/utils.py
@@ -388,7 +388,7 @@ def validate_totals(einvoice):
frappe.throw(_('Total Taxable Value of the items is not equal to the Invoice Net Total. Please check item taxes / discounts for any correction.'))
if abs(
- flt(value_details['TotInvVal']) + flt(value_details['Discount']) -
+ flt(value_details['TotInvVal']) + flt(value_details['Discount']) -
flt(value_details['OthChrg']) - flt(value_details['RndOffAmt']) -
total_item_value) > 1:
frappe.throw(_('Total Value of the items is not equal to the Invoice Grand Total. Please check item taxes / discounts for any correction.'))
diff --git a/erpnext/regional/india/taxes.js b/erpnext/regional/india/taxes.js
index d3b7ea3b1a..5f6dcdeb92 100644
--- a/erpnext/regional/india/taxes.js
+++ b/erpnext/regional/india/taxes.js
@@ -49,4 +49,3 @@ erpnext.setup_auto_gst_taxation = (doctype) => {
}
});
}
-
diff --git a/erpnext/regional/india/utils.py b/erpnext/regional/india/utils.py
index a152797a5d..949733e0ad 100644
--- a/erpnext/regional/india/utils.py
+++ b/erpnext/regional/india/utils.py
@@ -845,7 +845,7 @@ def get_depreciation_amount(asset, depreciable_value, row):
else:
depreciation_amount = (flt(row.value_after_depreciation) -
flt(row.expected_value_after_useful_life)) / (date_diff(asset.to_date, asset.available_for_use_date) / 365)
-
+
else:
rate_of_depreciation = row.rate_of_depreciation
# if its the first depreciation
@@ -862,7 +862,7 @@ def get_depreciation_amount(asset, depreciable_value, row):
return depreciation_amount
def set_item_tax_from_hsn_code(item):
- if not item.taxes and item.gst_hsn_code:
+ if not item.taxes and item.gst_hsn_code:
hsn_doc = frappe.get_doc("GST HSN Code", item.gst_hsn_code)
for tax in hsn_doc.taxes:
@@ -870,4 +870,4 @@ def set_item_tax_from_hsn_code(item):
'item_tax_template': tax.item_tax_template,
'tax_category': tax.tax_category,
'valid_from': tax.valid_from
- })
\ No newline at end of file
+ })
diff --git a/erpnext/regional/italy/__init__.py b/erpnext/regional/italy/__init__.py
index ef1d5822ba..4932f660ca 100644
--- a/erpnext/regional/italy/__init__.py
+++ b/erpnext/regional/italy/__init__.py
@@ -76,4 +76,4 @@ state_codes = {'Siracusa': 'SR', 'Bologna': 'BO', 'Grosseto': 'GR', 'Caserta': '
'Cagliari': 'CA', 'Siena': 'SI', 'Vibo Valentia': 'VV', 'Reggio Calabria': 'RC', 'Ascoli Piceno': 'AP', 'Carbonia-Iglesias': 'CI', 'Oristano': 'OR',
'Asti': 'AT', 'Ravenna': 'RA', 'Vicenza': 'VI', 'Savona': 'SV', 'Biella': 'BI', 'Rimini': 'RN', 'Agrigento': 'AG', 'Prato': 'PO', 'Cuneo': 'CN',
'Cosenza': 'CS', 'Livorno or Leghorn': 'LI', 'Sondrio': 'SO', 'Cremona': 'CR', 'Isernia': 'IS', 'Trento': 'TN', 'Terni': 'TR', 'Bolzano/Bozen': 'BZ',
- 'Parma': 'PR', 'Varese': 'VA', 'Venezia': 'VE', 'Sassari': 'SS', 'Arezzo': 'AR'}
\ No newline at end of file
+ 'Parma': 'PR', 'Varese': 'VA', 'Venezia': 'VE', 'Sassari': 'SS', 'Arezzo': 'AR'}
diff --git a/erpnext/regional/report/datev/datev.py b/erpnext/regional/report/datev/datev.py
index a5ca7eee5d..86aed2ef81 100644
--- a/erpnext/regional/report/datev/datev.py
+++ b/erpnext/regional/report/datev/datev.py
@@ -202,7 +202,7 @@ def get_transactions(filters, as_dict=1):
FROM `tabGL Entry` gl
/* Kontonummer */
- left join `tabAccount` acc
+ left join `tabAccount` acc
on gl.account = acc.name
left join `tabCustomer` cus
@@ -218,7 +218,7 @@ def get_transactions(filters, as_dict=1):
and par.parenttype = gl.party_type
and par.company = %(company)s
- WHERE gl.company = %(company)s
+ WHERE gl.company = %(company)s
AND DATE(gl.posting_date) >= %(from_date)s
AND DATE(gl.posting_date) <= %(to_date)s
{}
diff --git a/erpnext/regional/report/e_invoice_summary/e_invoice_summary.py b/erpnext/regional/report/e_invoice_summary/e_invoice_summary.py
index 47acf291a3..66ffceae53 100644
--- a/erpnext/regional/report/e_invoice_summary/e_invoice_summary.py
+++ b/erpnext/regional/report/e_invoice_summary/e_invoice_summary.py
@@ -54,53 +54,53 @@ def get_columns():
"width": 0
},
{
- "fieldtype": "Link",
- "fieldname": "name",
+ "fieldtype": "Link",
+ "fieldname": "name",
"label": _("Sales Invoice"),
"options": "Sales Invoice",
"width": 140
},
- {
- "fieldtype": "Data",
- "fieldname": "einvoice_status",
- "label": _("Status"),
+ {
+ "fieldtype": "Data",
+ "fieldname": "einvoice_status",
+ "label": _("Status"),
"width": 100
},
- {
+ {
"fieldtype": "Link",
"fieldname": "customer",
"options": "Customer",
"label": _("Customer")
},
- {
+ {
"fieldtype": "Check",
"fieldname": "is_return",
"label": _("Is Return"),
"width": 85
},
{
- "fieldtype": "Data",
- "fieldname": "ack_no",
- "label": "Ack. No.",
+ "fieldtype": "Data",
+ "fieldname": "ack_no",
+ "label": "Ack. No.",
"width": 145
},
- {
- "fieldtype": "Data",
- "fieldname": "ack_date",
- "label": "Ack. Date",
+ {
+ "fieldtype": "Data",
+ "fieldname": "ack_date",
+ "label": "Ack. Date",
"width": 165
},
{
- "fieldtype": "Data",
- "fieldname": "irn",
+ "fieldtype": "Data",
+ "fieldname": "irn",
"label": _("IRN No."),
"width": 250
},
{
"fieldtype": "Currency",
- "options": "Company:company:default_currency",
- "fieldname": "base_grand_total",
+ "options": "Company:company:default_currency",
+ "fieldname": "base_grand_total",
"label": _("Grand Total"),
"width": 120
}
- ]
\ No newline at end of file
+ ]
diff --git a/erpnext/regional/report/electronic_invoice_register/electronic_invoice_register.js b/erpnext/regional/report/electronic_invoice_register/electronic_invoice_register.js
index 67297f757c..d7e3ac9a5d 100644
--- a/erpnext/regional/report/electronic_invoice_register/electronic_invoice_register.js
+++ b/erpnext/regional/report/electronic_invoice_register/electronic_invoice_register.js
@@ -41,7 +41,7 @@ frappe.query_reports["Electronic Invoice Register"] = {
var w = window.open(
frappe.urllib.get_full_url(
- "/api/method/erpnext.regional.italy.utils.export_invoices?"
+ "/api/method/erpnext.regional.italy.utils.export_invoices?"
+ "filters=" + JSON.stringify(reportview.get_filter_values())
)
);
diff --git a/erpnext/regional/report/eway_bill/eway_bill.py b/erpnext/regional/report/eway_bill/eway_bill.py
index 5b9896be2a..4f777fcf7e 100644
--- a/erpnext/regional/report/eway_bill/eway_bill.py
+++ b/erpnext/regional/report/eway_bill/eway_bill.py
@@ -388,4 +388,4 @@ def get_columns():
},
]
- return columns
\ No newline at end of file
+ return columns
diff --git a/erpnext/regional/report/gst_purchase_register/gst_purchase_register.js b/erpnext/regional/report/gst_purchase_register/gst_purchase_register.js
index 2b4359a749..bbcd355d13 100644
--- a/erpnext/regional/report/gst_purchase_register/gst_purchase_register.js
+++ b/erpnext/regional/report/gst_purchase_register/gst_purchase_register.js
@@ -4,4 +4,4 @@
{% include "erpnext/accounts/report/purchase_register/purchase_register.js" %}
-frappe.query_reports["GST Purchase Register"] = frappe.query_reports["Purchase Register"]
\ No newline at end of file
+frappe.query_reports["GST Purchase Register"] = frappe.query_reports["Purchase Register"]
diff --git a/erpnext/regional/report/gst_purchase_register/gst_purchase_register.py b/erpnext/regional/report/gst_purchase_register/gst_purchase_register.py
index 7274e0acce..12e9676b4b 100644
--- a/erpnext/regional/report/gst_purchase_register/gst_purchase_register.py
+++ b/erpnext/regional/report/gst_purchase_register/gst_purchase_register.py
@@ -21,4 +21,3 @@ def execute(filters=None):
'export_type',
'ecommerce_gstin'
])
-
diff --git a/erpnext/regional/report/hsn_wise_summary_of_outward_supplies/hsn_wise_summary_of_outward_supplies.py b/erpnext/regional/report/hsn_wise_summary_of_outward_supplies/hsn_wise_summary_of_outward_supplies.py
index 59389ce326..1adddbdae5 100644
--- a/erpnext/regional/report/hsn_wise_summary_of_outward_supplies/hsn_wise_summary_of_outward_supplies.py
+++ b/erpnext/regional/report/hsn_wise_summary_of_outward_supplies/hsn_wise_summary_of_outward_supplies.py
@@ -285,5 +285,3 @@ def get_hsn_wise_json_data(filters, report_data):
count +=1
return data
-
-
diff --git a/erpnext/regional/report/india_gst_common/india_gst_common.js b/erpnext/regional/report/india_gst_common/india_gst_common.js
index 4960601394..bddc32096f 100644
--- a/erpnext/regional/report/india_gst_common/india_gst_common.js
+++ b/erpnext/regional/report/india_gst_common/india_gst_common.js
@@ -18,4 +18,4 @@ function fetch_gstins(report) {
company_gstins.df.options = [""];
company_gstins.refresh();
}
-}
\ No newline at end of file
+}
diff --git a/erpnext/regional/report/irs_1099/irs_1099.py b/erpnext/regional/report/irs_1099/irs_1099.py
index 4e57ff7ea3..f67d622fdf 100644
--- a/erpnext/regional/report/irs_1099/irs_1099.py
+++ b/erpnext/regional/report/irs_1099/irs_1099.py
@@ -52,7 +52,7 @@ def execute(filters=None):
AND gl.party_type = "Supplier"
AND gl.company = %(company)s
{conditions}
-
+
GROUP BY
gl.party
diff --git a/erpnext/regional/report/professional_tax_deductions/professional_tax_deductions.js b/erpnext/regional/report/professional_tax_deductions/professional_tax_deductions.js
index 29c7dbf43c..bb75238b8c 100644
--- a/erpnext/regional/report/professional_tax_deductions/professional_tax_deductions.js
+++ b/erpnext/regional/report/professional_tax_deductions/professional_tax_deductions.js
@@ -4,4 +4,4 @@
frappe.require("assets/erpnext/js/salary_slip_deductions_report_filters.js", function() {
frappe.query_reports["Professional Tax Deductions"] = erpnext.salary_slip_deductions_report_filters;
-});
\ No newline at end of file
+});
diff --git a/erpnext/regional/report/professional_tax_deductions/professional_tax_deductions.py b/erpnext/regional/report/professional_tax_deductions/professional_tax_deductions.py
index acde68a942..54808e59e1 100644
--- a/erpnext/regional/report/professional_tax_deductions/professional_tax_deductions.py
+++ b/erpnext/regional/report/professional_tax_deductions/professional_tax_deductions.py
@@ -69,4 +69,4 @@ def get_data(filters):
data.append(employee)
- return data
\ No newline at end of file
+ return data
diff --git a/erpnext/regional/report/provident_fund_deductions/provident_fund_deductions.js b/erpnext/regional/report/provident_fund_deductions/provident_fund_deductions.js
index b4dc28d177..a91a30796b 100644
--- a/erpnext/regional/report/provident_fund_deductions/provident_fund_deductions.js
+++ b/erpnext/regional/report/provident_fund_deductions/provident_fund_deductions.js
@@ -4,4 +4,4 @@
frappe.require("assets/erpnext/js/salary_slip_deductions_report_filters.js", function() {
frappe.query_reports["Provident Fund Deductions"] = erpnext.salary_slip_deductions_report_filters;
-});
\ No newline at end of file
+});
diff --git a/erpnext/regional/report/provident_fund_deductions/provident_fund_deductions.py b/erpnext/regional/report/provident_fund_deductions/provident_fund_deductions.py
index 597072c53a..82423f005c 100644
--- a/erpnext/regional/report/provident_fund_deductions/provident_fund_deductions.py
+++ b/erpnext/regional/report/provident_fund_deductions/provident_fund_deductions.py
@@ -165,4 +165,4 @@ def get_years():
if not year_list:
year_list = [getdate().year]
- return "\n".join(str(year) for year in year_list)
\ No newline at end of file
+ return "\n".join(str(year) for year in year_list)
diff --git a/erpnext/regional/report/uae_vat_201/uae_vat_201.html b/erpnext/regional/report/uae_vat_201/uae_vat_201.html
index d9b9968d90..7328f3f218 100644
--- a/erpnext/regional/report/uae_vat_201/uae_vat_201.html
+++ b/erpnext/regional/report/uae_vat_201/uae_vat_201.html
@@ -74,4 +74,4 @@
{% } %}
-
\ No newline at end of file
+
diff --git a/erpnext/regional/report/vat_audit_report/vat_audit_report.py b/erpnext/regional/report/vat_audit_report/vat_audit_report.py
index 292605ef13..17aca17afd 100644
--- a/erpnext/regional/report/vat_audit_report/vat_audit_report.py
+++ b/erpnext/regional/report/vat_audit_report/vat_audit_report.py
@@ -189,7 +189,7 @@ class VATAuditReport(object):
row["posting_date"] = formatdate(inv_data.get("posting_date"), "dd-mm-yyyy")
row["voucher_type"] = doctype
row["voucher_no"] = inv
- row["party_type"] = "Customer" if doctype == "Sales Invoice" else "Supplier"
+ row["party_type"] = "Customer" if doctype == "Sales Invoice" else "Supplier"
row["party"] = inv_data.get("party")
row["remarks"] = inv_data.get("remarks")
row["gross_amount"]= item_details[0].get("gross_amount")
diff --git a/erpnext/regional/south_africa/setup.py b/erpnext/regional/south_africa/setup.py
index 4657ff833d..8a75987c3d 100644
--- a/erpnext/regional/south_africa/setup.py
+++ b/erpnext/regional/south_africa/setup.py
@@ -24,7 +24,7 @@ def make_custom_fields(update=True):
'Sales Invoice Item': is_zero_rated,
'Purchase Invoice Item': is_zero_rated
}
-
+
create_custom_fields(custom_fields, update=update)
def add_permissions():
@@ -36,7 +36,7 @@ def add_permissions():
add_permission(doctype, role, 0)
update_permission_property(doctype, role, 0, 'write', 1)
update_permission_property(doctype, role, 0, 'create', 1)
-
+
if not frappe.db.get_value('Custom Role', dict(report="VAT Audit Report")):
frappe.get_doc(dict(
@@ -47,4 +47,4 @@ def add_permissions():
dict(role='Accounts Manager'),
dict(role='Auditor')
]
- )).insert()
\ No newline at end of file
+ )).insert()
diff --git a/erpnext/regional/turkey/setup.py b/erpnext/regional/turkey/setup.py
index ebf3b2bee1..2396aab91f 100644
--- a/erpnext/regional/turkey/setup.py
+++ b/erpnext/regional/turkey/setup.py
@@ -1,4 +1,4 @@
from __future__ import unicode_literals
def setup(company=None, patch=True):
- pass
\ No newline at end of file
+ pass
diff --git a/erpnext/restaurant/doctype/restaurant/restaurant_dashboard.py b/erpnext/restaurant/doctype/restaurant/restaurant_dashboard.py
index ec62ba22b4..adce5c7335 100644
--- a/erpnext/restaurant/doctype/restaurant/restaurant_dashboard.py
+++ b/erpnext/restaurant/doctype/restaurant/restaurant_dashboard.py
@@ -14,4 +14,4 @@ def get_data():
'items': ['Restaurant Reservation', 'Sales Invoice']
}
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/restaurant/doctype/restaurant/test_restaurant.js b/erpnext/restaurant/doctype/restaurant/test_restaurant.js
index 26de5d04aa..8fe4e7b84d 100644
--- a/erpnext/restaurant/doctype/restaurant/test_restaurant.js
+++ b/erpnext/restaurant/doctype/restaurant/test_restaurant.js
@@ -18,7 +18,7 @@ QUnit.test("test: Restaurant", function (assert) {
frappe.run_serially([
// insert a new Restaurant
- () => frappe.tests.setup_doctype('Customer', customer),
+ () => frappe.tests.setup_doctype('Customer', customer),
() => {
return frappe.tests.make('Restaurant', [
// values to be set
diff --git a/erpnext/restaurant/doctype/restaurant_menu/restaurant_menu.py b/erpnext/restaurant/doctype/restaurant_menu/restaurant_menu.py
index 83020b6cca..952c46769b 100644
--- a/erpnext/restaurant/doctype/restaurant_menu/restaurant_menu.py
+++ b/erpnext/restaurant/doctype/restaurant_menu/restaurant_menu.py
@@ -57,5 +57,3 @@ class RestaurantMenu(Document):
price_list.save()
return price_list
-
-
diff --git a/erpnext/selling/doctype/customer/customer.js b/erpnext/selling/doctype/customer/customer.js
index 2849466267..2f06e98880 100644
--- a/erpnext/selling/doctype/customer/customer.js
+++ b/erpnext/selling/doctype/customer/customer.js
@@ -160,4 +160,3 @@ frappe.ui.form.on("Customer", {
}
});
-
diff --git a/erpnext/selling/doctype/customer/regional/india.js b/erpnext/selling/doctype/customer/regional/india.js
index edb83838b6..cad9a27ace 100644
--- a/erpnext/selling/doctype/customer/regional/india.js
+++ b/erpnext/selling/doctype/customer/regional/india.js
@@ -1,3 +1,3 @@
{% include "erpnext/regional/india/party.js" %}
-erpnext.setup_gst_reminder_button('Customer')
\ No newline at end of file
+erpnext.setup_gst_reminder_button('Customer')
diff --git a/erpnext/selling/doctype/industry_type/industry_type.js b/erpnext/selling/doctype/industry_type/industry_type.js
index 3878a791db..3680906057 100644
--- a/erpnext/selling/doctype/industry_type/industry_type.js
+++ b/erpnext/selling/doctype/industry_type/industry_type.js
@@ -1,13 +1,13 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
-
+
//--------- ONLOAD -------------
cur_frm.cscript.onload = function(doc, cdt, cdn) {
-
+
}
cur_frm.cscript.refresh = function(doc, cdt, cdn) {
-
-}
\ No newline at end of file
+
+}
diff --git a/erpnext/selling/doctype/industry_type/industry_type.py b/erpnext/selling/doctype/industry_type/industry_type.py
index 65b17e976a..7a30d6524a 100644
--- a/erpnext/selling/doctype/industry_type/industry_type.py
+++ b/erpnext/selling/doctype/industry_type/industry_type.py
@@ -7,4 +7,4 @@ import frappe
from frappe.model.document import Document
class IndustryType(Document):
- pass
\ No newline at end of file
+ pass
diff --git a/erpnext/selling/doctype/industry_type/test_industry_type.py b/erpnext/selling/doctype/industry_type/test_industry_type.py
index 1246a241c7..ebc6366155 100644
--- a/erpnext/selling/doctype/industry_type/test_industry_type.py
+++ b/erpnext/selling/doctype/industry_type/test_industry_type.py
@@ -4,4 +4,4 @@ from __future__ import unicode_literals
import frappe
-test_records = frappe.get_test_records('Industry Type')
\ No newline at end of file
+test_records = frappe.get_test_records('Industry Type')
diff --git a/erpnext/selling/doctype/installation_note_item/installation_note_item.py b/erpnext/selling/doctype/installation_note_item/installation_note_item.py
index 681b8171e2..7e1205231b 100644
--- a/erpnext/selling/doctype/installation_note_item/installation_note_item.py
+++ b/erpnext/selling/doctype/installation_note_item/installation_note_item.py
@@ -7,4 +7,4 @@ import frappe
from frappe.model.document import Document
class InstallationNoteItem(Document):
- pass
\ No newline at end of file
+ pass
diff --git a/erpnext/selling/doctype/product_bundle/test_product_bundle.js b/erpnext/selling/doctype/product_bundle/test_product_bundle.js
index ba5ba0dc3b..0dc90ec211 100644
--- a/erpnext/selling/doctype/product_bundle/test_product_bundle.js
+++ b/erpnext/selling/doctype/product_bundle/test_product_bundle.js
@@ -33,4 +33,3 @@ QUnit.test("test sales order", function(assert) {
() => done()
]);
});
-
diff --git a/erpnext/selling/doctype/quotation/quotation_dashboard.py b/erpnext/selling/doctype/quotation/quotation_dashboard.py
index f1ac951ef9..d1bb788937 100644
--- a/erpnext/selling/doctype/quotation/quotation_dashboard.py
+++ b/erpnext/selling/doctype/quotation/quotation_dashboard.py
@@ -17,4 +17,4 @@ def get_data():
'items': ['Auto Repeat']
},
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/selling/doctype/quotation/tests/test_quotation_with_discount_on_grand_total.js b/erpnext/selling/doctype/quotation/tests/test_quotation_with_discount_on_grand_total.js
index aeb5d1b9eb..b59bb0510e 100644
--- a/erpnext/selling/doctype/quotation/tests/test_quotation_with_discount_on_grand_total.js
+++ b/erpnext/selling/doctype/quotation/tests/test_quotation_with_discount_on_grand_total.js
@@ -41,4 +41,3 @@ QUnit.test("test quotation with additional discount in grand total", function(as
() => done()
]);
});
-
diff --git a/erpnext/selling/doctype/quotation/tests/test_quotation_with_item_wise_discount.js b/erpnext/selling/doctype/quotation/tests/test_quotation_with_item_wise_discount.js
index e7349e3201..f5172fbae2 100644
--- a/erpnext/selling/doctype/quotation/tests/test_quotation_with_item_wise_discount.js
+++ b/erpnext/selling/doctype/quotation/tests/test_quotation_with_item_wise_discount.js
@@ -35,4 +35,3 @@ QUnit.test("test quotation with item wise discount", function(assert) {
() => done()
]);
});
-
diff --git a/erpnext/selling/doctype/quotation/tests/test_quotation_with_margin.js b/erpnext/selling/doctype/quotation/tests/test_quotation_with_margin.js
index 5b4224dfe9..0d340997ad 100644
--- a/erpnext/selling/doctype/quotation/tests/test_quotation_with_margin.js
+++ b/erpnext/selling/doctype/quotation/tests/test_quotation_with_margin.js
@@ -33,4 +33,3 @@ QUnit.test("test quotation with margin", function(assert) {
() => done()
]);
});
-
diff --git a/erpnext/selling/doctype/quotation/tests/test_quotation_with_multi_uom.js b/erpnext/selling/doctype/quotation/tests/test_quotation_with_multi_uom.js
index 50b8a8396d..84be56f460 100644
--- a/erpnext/selling/doctype/quotation/tests/test_quotation_with_multi_uom.js
+++ b/erpnext/selling/doctype/quotation/tests/test_quotation_with_multi_uom.js
@@ -36,4 +36,3 @@ QUnit.test("test quotation with multi uom", function(assert) {
() => done()
]);
});
-
diff --git a/erpnext/selling/doctype/quotation/tests/test_quotation_with_taxes_and_charges.js b/erpnext/selling/doctype/quotation/tests/test_quotation_with_taxes_and_charges.js
index ac7ed65ec0..5e21f81757 100644
--- a/erpnext/selling/doctype/quotation/tests/test_quotation_with_taxes_and_charges.js
+++ b/erpnext/selling/doctype/quotation/tests/test_quotation_with_taxes_and_charges.js
@@ -38,4 +38,3 @@ QUnit.test("test quotation with taxes and charges", function(assert) {
() => done()
]);
});
-
diff --git a/erpnext/selling/doctype/sales_order/sales_order_dashboard.py b/erpnext/selling/doctype/sales_order/sales_order_dashboard.py
index 05a760de27..2a71c27009 100644
--- a/erpnext/selling/doctype/sales_order/sales_order_dashboard.py
+++ b/erpnext/selling/doctype/sales_order/sales_order_dashboard.py
@@ -41,4 +41,4 @@ def get_data():
'items': ['Payment Entry', 'Payment Request', 'Journal Entry']
},
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py
index a0a21eef5a..d685fbff82 100644
--- a/erpnext/selling/doctype/sales_order/test_sales_order.py
+++ b/erpnext/selling/doctype/sales_order/test_sales_order.py
@@ -1222,7 +1222,7 @@ class TestSalesOrder(unittest.TestCase):
def test_so_cancellation_when_si_drafted(self):
"""
Test to check if Sales Order gets cancelled if Sales Invoice is in Draft state
- Expected result: sales order should not get cancelled
+ Expected result: sales order should not get cancelled
"""
so = make_sales_order()
so.submit()
@@ -1250,7 +1250,7 @@ class TestSalesOrder(unittest.TestCase):
self.assertEqual(so.payment_terms_template, si.payment_terms_template)
compare_payment_schedules(self, so, si)
- automatically_fetch_payment_terms(enable=0)
+ automatically_fetch_payment_terms(enable=0)
def automatically_fetch_payment_terms(enable=1):
accounts_settings = frappe.get_doc("Accounts Settings")
diff --git a/erpnext/selling/doctype/sales_order/tests/test_sales_order_with_margin.js b/erpnext/selling/doctype/sales_order/tests/test_sales_order_with_margin.js
index 7426868507..9eebfdaf21 100644
--- a/erpnext/selling/doctype/sales_order/tests/test_sales_order_with_margin.js
+++ b/erpnext/selling/doctype/sales_order/tests/test_sales_order_with_margin.js
@@ -35,4 +35,3 @@ QUnit.test("test sales order with margin", function(assert) {
() => done()
]);
});
-
diff --git a/erpnext/selling/doctype/sales_order/tests/test_sales_order_with_multiple_delivery_date.js b/erpnext/selling/doctype/sales_order/tests/test_sales_order_with_multiple_delivery_date.js
index 8e0538511a..be76c49f84 100644
--- a/erpnext/selling/doctype/sales_order/tests/test_sales_order_with_multiple_delivery_date.js
+++ b/erpnext/selling/doctype/sales_order/tests/test_sales_order_with_multiple_delivery_date.js
@@ -56,4 +56,4 @@ QUnit.test("test: Sales Order", function (assert) {
},
() => done()
]);
-});
\ No newline at end of file
+});
diff --git a/erpnext/selling/doctype/sales_order_item/sales_order_item.py b/erpnext/selling/doctype/sales_order_item/sales_order_item.py
index 27f303d43b..62afef3e17 100644
--- a/erpnext/selling/doctype/sales_order_item/sales_order_item.py
+++ b/erpnext/selling/doctype/sales_order_item/sales_order_item.py
@@ -10,4 +10,4 @@ class SalesOrderItem(Document):
pass
def on_doctype_update():
- frappe.db.add_index("Sales Order Item", ["item_code", "warehouse"])
\ No newline at end of file
+ frappe.db.add_index("Sales Order Item", ["item_code", "warehouse"])
diff --git a/erpnext/selling/doctype/sales_team/sales_team.py b/erpnext/selling/doctype/sales_team/sales_team.py
index 1832108399..28bea254d6 100644
--- a/erpnext/selling/doctype/sales_team/sales_team.py
+++ b/erpnext/selling/doctype/sales_team/sales_team.py
@@ -7,4 +7,4 @@ import frappe
from frappe.model.document import Document
class SalesTeam(Document):
- pass
\ No newline at end of file
+ pass
diff --git a/erpnext/selling/doctype/selling_settings/selling_settings.js b/erpnext/selling/doctype/selling_settings/selling_settings.js
index 95a4243fb4..d8d30515f8 100644
--- a/erpnext/selling/doctype/selling_settings/selling_settings.js
+++ b/erpnext/selling/doctype/selling_settings/selling_settings.js
@@ -28,4 +28,4 @@ frappe.tour['Selling Settings'] = [
title: "Delivery Note Required for Sales Invoice Creation",
description: __("If this option is configured 'Yes', ERPNext will prevent you from creating a Sales Invoice without creating a Delivery Note first. This configuration can be overridden for a particular Customer by enabling the 'Allow Sales Invoice Creation Without Delivery Note' checkbox in the Customer master.")
}
-];
\ No newline at end of file
+];
diff --git a/erpnext/selling/doctype/sms_center/sms_center.py b/erpnext/selling/doctype/sms_center/sms_center.py
index d142d16248..87846a84d3 100644
--- a/erpnext/selling/doctype/sms_center/sms_center.py
+++ b/erpnext/selling/doctype/sms_center/sms_center.py
@@ -83,4 +83,3 @@ class SMSCenter(Document):
receiver_list = self.get_receiver_nos()
if receiver_list:
send_sms(receiver_list, cstr(self.message))
-
diff --git a/erpnext/selling/page/point_of_sale/point_of_sale.py b/erpnext/selling/page/point_of_sale/point_of_sale.py
index 8d1f112dc2..03c46bb2ae 100644
--- a/erpnext/selling/page/point_of_sale/point_of_sale.py
+++ b/erpnext/selling/page/point_of_sale/point_of_sale.py
@@ -146,7 +146,7 @@ def filter_service_items(items):
if not item['is_stock_item']:
if not frappe.db.exists('Product Bundle', item['item_code']):
items.remove(item)
-
+
return items
def get_conditions(search_term):
diff --git a/erpnext/selling/page/point_of_sale/pos_controller.js b/erpnext/selling/page/point_of_sale/pos_controller.js
index c827368dbf..e61a634aae 100644
--- a/erpnext/selling/page/point_of_sale/pos_controller.js
+++ b/erpnext/selling/page/point_of_sale/pos_controller.js
@@ -525,7 +525,7 @@ erpnext.PointOfSale.Controller = class {
}
} else {
- if (!this.frm.doc.customer)
+ if (!this.frm.doc.customer)
return this.raise_customer_selection_alert();
const { item_code, batch_no, serial_no, rate } = item;
@@ -549,7 +549,7 @@ erpnext.PointOfSale.Controller = class {
await this.check_stock_availability(item_row, value, this.frm.doc.set_warehouse);
await this.trigger_new_item_events(item_row);
-
+
this.update_cart_html(item_row);
if (this.item_details.$component.is(':visible'))
@@ -708,4 +708,3 @@ erpnext.PointOfSale.Controller = class {
.catch(e => console.log(e));
}
};
-
diff --git a/erpnext/selling/page/point_of_sale/pos_item_cart.js b/erpnext/selling/page/point_of_sale/pos_item_cart.js
index a4a4b0e0ed..9d8338e5fe 100644
--- a/erpnext/selling/page/point_of_sale/pos_item_cart.js
+++ b/erpnext/selling/page/point_of_sale/pos_item_cart.js
@@ -973,7 +973,7 @@ erpnext.PointOfSale.ItemCart = class {
load_invoice() {
const frm = this.events.get_frm();
-
+
this.attach_refresh_field_event(frm);
this.fetch_customer_details(frm.doc.customer).then(() => {
diff --git a/erpnext/selling/page/point_of_sale/pos_item_details.js b/erpnext/selling/page/point_of_sale/pos_item_details.js
index 6a4d3d5214..d899c5c19b 100644
--- a/erpnext/selling/page/point_of_sale/pos_item_details.js
+++ b/erpnext/selling/page/point_of_sale/pos_item_details.js
@@ -65,7 +65,7 @@ erpnext.PointOfSale.ItemDetails = class {
// if item is null or highlighted cart item is clicked twice
const hide_item_details = !Boolean(item) || !current_item_changed;
-
+
this.events.toggle_item_selector(!hide_item_details);
this.toggle_component(!hide_item_details);
@@ -127,7 +127,7 @@ erpnext.PointOfSale.ItemDetails = class {
this.$item_price.html(format_currency(price_list_rate, this.currency));
if (!this.hide_images && image) {
this.$item_image.html(
- ` ${qty_to_display}
-
";
}
diff --git a/erpnext/selling/report/sales_partner_target_variance_based_on_item_group/sales_partner_target_variance_based_on_item_group.py b/erpnext/selling/report/sales_partner_target_variance_based_on_item_group/sales_partner_target_variance_based_on_item_group.py
index e41011fba2..87ed5a8ea2 100644
--- a/erpnext/selling/report/sales_partner_target_variance_based_on_item_group/sales_partner_target_variance_based_on_item_group.py
+++ b/erpnext/selling/report/sales_partner_target_variance_based_on_item_group/sales_partner_target_variance_based_on_item_group.py
@@ -9,4 +9,3 @@ def execute(filters=None):
data = []
return get_data_column(filters, "Sales Partner")
-
diff --git a/erpnext/selling/report/sales_partner_transaction_summary/sales_partner_transaction_summary.py b/erpnext/selling/report/sales_partner_transaction_summary/sales_partner_transaction_summary.py
index 53560285b3..f07293d8ec 100644
--- a/erpnext/selling/report/sales_partner_transaction_summary/sales_partner_transaction_summary.py
+++ b/erpnext/selling/report/sales_partner_transaction_summary/sales_partner_transaction_summary.py
@@ -165,4 +165,4 @@ def get_conditions(filters, date_field):
`tabItem Group` where lft >= %s and rgt <= %s)""" % (lft, rgt)
- return conditions
\ No newline at end of file
+ return conditions
diff --git a/erpnext/selling/report/sales_person_commission_summary/sales_person_commission_summary.py b/erpnext/selling/report/sales_person_commission_summary/sales_person_commission_summary.py
index 0c84909611..9917d72af8 100644
--- a/erpnext/selling/report/sales_person_commission_summary/sales_person_commission_summary.py
+++ b/erpnext/selling/report/sales_person_commission_summary/sales_person_commission_summary.py
@@ -101,7 +101,7 @@ def get_columns(filters):
def get_entries(filters):
date_field = filters["doc_type"] == "Sales Order" and "transaction_date" or "posting_date"
-
+
conditions, values = get_conditions(filters, date_field)
entries = frappe.db.sql("""
select
@@ -111,7 +111,7 @@ def get_entries(filters):
`tab%s` dt, `tabSales Team` st
where
st.parent = dt.name and st.parenttype = %s
- and dt.docstatus = 1 %s order by dt.name desc,st.sales_person
+ and dt.docstatus = 1 %s order by dt.name desc,st.sales_person
""" %(date_field, filters["doc_type"], '%s', conditions),
tuple([filters["doc_type"]] + values), as_dict=1)
@@ -138,5 +138,3 @@ def get_conditions(filters, date_field):
values.append(filters["to_date"])
return " and ".join(conditions), values
-
-
diff --git a/erpnext/selling/report/sales_person_target_variance_based_on_item_group/sales_person_target_variance_based_on_item_group.js b/erpnext/selling/report/sales_person_target_variance_based_on_item_group/sales_person_target_variance_based_on_item_group.js
index a8e2fad373..2b8443627d 100644
--- a/erpnext/selling/report/sales_person_target_variance_based_on_item_group/sales_person_target_variance_based_on_item_group.js
+++ b/erpnext/selling/report/sales_person_target_variance_based_on_item_group/sales_person_target_variance_based_on_item_group.js
@@ -47,9 +47,9 @@ frappe.query_reports["Sales Person Target Variance Based On Item Group"] = {
],
"formatter": function (value, row, column, data, default_formatter) {
value = default_formatter(value, row, column, data);
-
+
if (column.fieldname.includes('variance')) {
-
+
if (data[column.fieldname] < 0) {
value = "
" + value + " ";
}
diff --git a/erpnext/selling/report/sales_person_target_variance_based_on_item_group/sales_person_target_variance_based_on_item_group.py b/erpnext/selling/report/sales_person_target_variance_based_on_item_group/sales_person_target_variance_based_on_item_group.py
index 5166cc808e..ea9bbab0c7 100644
--- a/erpnext/selling/report/sales_person_target_variance_based_on_item_group/sales_person_target_variance_based_on_item_group.py
+++ b/erpnext/selling/report/sales_person_target_variance_based_on_item_group/sales_person_target_variance_based_on_item_group.py
@@ -8,4 +8,4 @@ from erpnext.selling.report.sales_partner_target_variance_based_on_item_group.it
def execute(filters=None):
data = []
- return get_data_column(filters, "Sales Person")
\ No newline at end of file
+ return get_data_column(filters, "Sales Person")
diff --git a/erpnext/selling/report/sales_person_wise_transaction_summary/sales_person_wise_transaction_summary.js b/erpnext/selling/report/sales_person_wise_transaction_summary/sales_person_wise_transaction_summary.js
index b236151bad..e269f02d0c 100644
--- a/erpnext/selling/report/sales_person_wise_transaction_summary/sales_person_wise_transaction_summary.js
+++ b/erpnext/selling/report/sales_person_wise_transaction_summary/sales_person_wise_transaction_summary.js
@@ -67,4 +67,4 @@ frappe.query_reports["Sales Person-wise Transaction Summary"] = {
default: 0,
},
]
-}
\ No newline at end of file
+}
diff --git a/erpnext/selling/report/territory_target_variance_based_on_item_group/territory_target_variance_based_on_item_group.js b/erpnext/selling/report/territory_target_variance_based_on_item_group/territory_target_variance_based_on_item_group.js
index 263391a7f7..9f3d255e66 100644
--- a/erpnext/selling/report/territory_target_variance_based_on_item_group/territory_target_variance_based_on_item_group.js
+++ b/erpnext/selling/report/territory_target_variance_based_on_item_group/territory_target_variance_based_on_item_group.js
@@ -47,9 +47,9 @@ frappe.query_reports["Territory Target Variance Based On Item Group"] = {
],
"formatter": function (value, row, column, data, default_formatter) {
value = default_formatter(value, row, column, data);
-
+
if (column.fieldname.includes('variance')) {
-
+
if (data[column.fieldname] < 0) {
value = "
" + value + " ";
}
diff --git a/erpnext/selling/sales_common.js b/erpnext/selling/sales_common.js
index f515baf31b..22bf3fc94f 100644
--- a/erpnext/selling/sales_common.js
+++ b/erpnext/selling/sales_common.js
@@ -26,7 +26,7 @@ erpnext.selling.SellingController = class SellingController extends erpnext.Tran
}
};
});
- }
+ }
setup_queries() {
var me = this;
@@ -85,7 +85,7 @@ erpnext.selling.SellingController = class SellingController extends erpnext.Tran
refresh() {
super.refresh();
-
+
frappe.dynamic_link = {doc: this.frm.doc, fieldname: 'customer', doctype: 'Customer'}
this.frm.toggle_display("customer_name",
diff --git a/erpnext/setup/default_energy_point_rules.py b/erpnext/setup/default_energy_point_rules.py
index 94f5aa488d..8dbccc497b 100644
--- a/erpnext/setup/default_energy_point_rules.py
+++ b/erpnext/setup/default_energy_point_rules.py
@@ -55,4 +55,3 @@ def get_default_energy_point_rules():
'points': rule.get('points'),
'user_field': rule.get('user_field') or 'owner'
} for doctype, rule in doctype_rule_map.items()]
-
diff --git a/erpnext/setup/default_success_action.py b/erpnext/setup/default_success_action.py
index b8b09cbc53..827839f8b7 100644
--- a/erpnext/setup/default_success_action.py
+++ b/erpnext/setup/default_success_action.py
@@ -24,4 +24,3 @@ def get_default_success_action():
'first_success_message': get_first_success_message(doctype),
'next_actions': 'new\nprint\nemail'
} for doctype in doctype_list]
-
diff --git a/erpnext/setup/doctype/brand/brand.js b/erpnext/setup/doctype/brand/brand.js
index 3878a791db..3680906057 100644
--- a/erpnext/setup/doctype/brand/brand.js
+++ b/erpnext/setup/doctype/brand/brand.js
@@ -1,13 +1,13 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
-
+
//--------- ONLOAD -------------
cur_frm.cscript.onload = function(doc, cdt, cdn) {
-
+
}
cur_frm.cscript.refresh = function(doc, cdt, cdn) {
-
-}
\ No newline at end of file
+
+}
diff --git a/erpnext/setup/doctype/brand/brand.py b/erpnext/setup/doctype/brand/brand.py
index 12839d18ae..a8d1cf8ff2 100644
--- a/erpnext/setup/doctype/brand/brand.py
+++ b/erpnext/setup/doctype/brand/brand.py
@@ -21,4 +21,4 @@ def get_brand_defaults(item, company):
row.pop("name")
return row
- return frappe._dict()
\ No newline at end of file
+ return frappe._dict()
diff --git a/erpnext/setup/doctype/brand/test_brand.py b/erpnext/setup/doctype/brand/test_brand.py
index 265d2fe577..25ed86ef1d 100644
--- a/erpnext/setup/doctype/brand/test_brand.py
+++ b/erpnext/setup/doctype/brand/test_brand.py
@@ -4,4 +4,4 @@ from __future__ import unicode_literals
import frappe
-test_records = frappe.get_test_records('Brand')
\ No newline at end of file
+test_records = frappe.get_test_records('Brand')
diff --git a/erpnext/setup/doctype/company/company.js b/erpnext/setup/doctype/company/company.js
index d05541b634..8f83d3cd73 100644
--- a/erpnext/setup/doctype/company/company.js
+++ b/erpnext/setup/doctype/company/company.js
@@ -313,4 +313,3 @@ var disbale_coa_fields = function(frm, bool=true) {
frm.set_df_property("chart_of_accounts", "read_only", bool);
frm.set_df_property("existing_company", "read_only", bool);
}
-
diff --git a/erpnext/setup/doctype/company/company.py b/erpnext/setup/doctype/company/company.py
index 95cbf5150c..54c67538ae 100644
--- a/erpnext/setup/doctype/company/company.py
+++ b/erpnext/setup/doctype/company/company.py
@@ -108,7 +108,7 @@ class Company(NestedSet):
frappe.flags.country_change = True
self.create_default_accounts()
self.create_default_warehouses()
-
+
if not frappe.db.get_value("Cost Center", {"is_group": 0, "company": self.name}):
self.create_default_cost_center()
diff --git a/erpnext/setup/doctype/company/company_dashboard.py b/erpnext/setup/doctype/company/company_dashboard.py
index 9b483dd55e..2d760284e5 100644
--- a/erpnext/setup/doctype/company/company_dashboard.py
+++ b/erpnext/setup/doctype/company/company_dashboard.py
@@ -37,4 +37,4 @@ def get_data():
'items': ['Project']
}
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/setup/doctype/company/company_tree.js b/erpnext/setup/doctype/company/company_tree.js
index 19b276c77d..160481cc95 100644
--- a/erpnext/setup/doctype/company/company_tree.js
+++ b/erpnext/setup/doctype/company/company_tree.js
@@ -30,4 +30,4 @@ frappe.treeview_settings["Company"] = {
onload: function(treeview) {
treeview.make_tree();
}
-};
\ No newline at end of file
+};
diff --git a/erpnext/setup/doctype/company/test_company.py b/erpnext/setup/doctype/company/test_company.py
index e1c803a038..1b7fd4fd5c 100644
--- a/erpnext/setup/doctype/company/test_company.py
+++ b/erpnext/setup/doctype/company/test_company.py
@@ -130,4 +130,3 @@ def create_test_lead_in_company(company):
lead.company = company
lead.save()
return lead.name
-
diff --git a/erpnext/setup/doctype/company/tests/test_company.js b/erpnext/setup/doctype/company/tests/test_company.js
index 8c0b609775..b568494c84 100644
--- a/erpnext/setup/doctype/company/tests/test_company.js
+++ b/erpnext/setup/doctype/company/tests/test_company.js
@@ -22,4 +22,4 @@ QUnit.test("Test: Company [SetUp]", function (assert) {
'chart of cost centers created'),
() => done()
]);
-});
\ No newline at end of file
+});
diff --git a/erpnext/setup/doctype/company/tests/test_company_production.js b/erpnext/setup/doctype/company/tests/test_company_production.js
index bf6e5405b4..a4c1e2e7de 100644
--- a/erpnext/setup/doctype/company/tests/test_company_production.js
+++ b/erpnext/setup/doctype/company/tests/test_company_production.js
@@ -16,4 +16,4 @@ QUnit.test("Test: Company", function (assert) {
() => done()
]);
-});
\ No newline at end of file
+});
diff --git a/erpnext/setup/doctype/customer_group/customer_group.py b/erpnext/setup/doctype/customer_group/customer_group.py
index 68e1ccb635..c06669b16b 100644
--- a/erpnext/setup/doctype/customer_group/customer_group.py
+++ b/erpnext/setup/doctype/customer_group/customer_group.py
@@ -30,4 +30,4 @@ def get_parent_customer_groups(customer_group):
order by lft asc""", (lft, rgt), as_dict=True)
def on_doctype_update():
- frappe.db.add_index("Customer Group", ["lft", "rgt"])
\ No newline at end of file
+ frappe.db.add_index("Customer Group", ["lft", "rgt"])
diff --git a/erpnext/setup/doctype/customer_group/customer_group_tree.js b/erpnext/setup/doctype/customer_group/customer_group_tree.js
index b52c79c497..d50e9c8835 100644
--- a/erpnext/setup/doctype/customer_group/customer_group_tree.js
+++ b/erpnext/setup/doctype/customer_group/customer_group_tree.js
@@ -1,3 +1,3 @@
frappe.treeview_settings["Customer Group"] = {
ignore_fields:["parent_customer_group"]
-}
\ No newline at end of file
+}
diff --git a/erpnext/setup/doctype/customer_group/test_customer_group.py b/erpnext/setup/doctype/customer_group/test_customer_group.py
index ec1af7a676..ec90b376cd 100644
--- a/erpnext/setup/doctype/customer_group/test_customer_group.py
+++ b/erpnext/setup/doctype/customer_group/test_customer_group.py
@@ -7,4 +7,4 @@ test_ignore = ["Price List"]
import frappe
-test_records = frappe.get_test_records('Customer Group')
\ No newline at end of file
+test_records = frappe.get_test_records('Customer Group')
diff --git a/erpnext/setup/doctype/email_digest/email_digest.js b/erpnext/setup/doctype/email_digest/email_digest.js
index 2e415af282..c2c2710b02 100644
--- a/erpnext/setup/doctype/email_digest/email_digest.js
+++ b/erpnext/setup/doctype/email_digest/email_digest.js
@@ -28,4 +28,4 @@ frappe.ui.form.on("Email Digest", {
});
}
}
-});
\ No newline at end of file
+});
diff --git a/erpnext/setup/doctype/email_digest/quotes.py b/erpnext/setup/doctype/email_digest/quotes.py
index 95afe974b2..5451ee1daf 100644
--- a/erpnext/setup/doctype/email_digest/quotes.py
+++ b/erpnext/setup/doctype/email_digest/quotes.py
@@ -32,4 +32,3 @@ def get_random_quote():
]
return random.choice(quotes)
-
diff --git a/erpnext/setup/doctype/email_digest/templates/default.html b/erpnext/setup/doctype/email_digest/templates/default.html
index 4ee4b0ff16..666301a643 100644
--- a/erpnext/setup/doctype/email_digest/templates/default.html
+++ b/erpnext/setup/doctype/email_digest/templates/default.html
@@ -180,8 +180,8 @@
{% endif %}
-
-
+
+
{% if purchase_orders_items_overdue_list %}
{{ _("Purchase Order Items not received on time") }}
@@ -254,6 +254,6 @@
Please take necessary action
-{% endif %}
-
+{% endif %}
+
diff --git a/erpnext/setup/doctype/item_group/item_group_tree.js b/erpnext/setup/doctype/item_group/item_group_tree.js
index 57afe02d79..b2628f4f4f 100644
--- a/erpnext/setup/doctype/item_group/item_group_tree.js
+++ b/erpnext/setup/doctype/item_group/item_group_tree.js
@@ -1,3 +1,3 @@
frappe.treeview_settings["Item Group"] = {
ignore_fields:["parent_item_group"]
-}
\ No newline at end of file
+}
diff --git a/erpnext/setup/doctype/print_heading/print_heading.js b/erpnext/setup/doctype/print_heading/print_heading.js
index 3878a791db..3680906057 100644
--- a/erpnext/setup/doctype/print_heading/print_heading.js
+++ b/erpnext/setup/doctype/print_heading/print_heading.js
@@ -1,13 +1,13 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
-
+
//--------- ONLOAD -------------
cur_frm.cscript.onload = function(doc, cdt, cdn) {
-
+
}
cur_frm.cscript.refresh = function(doc, cdt, cdn) {
-
-}
\ No newline at end of file
+
+}
diff --git a/erpnext/setup/doctype/print_heading/print_heading.py b/erpnext/setup/doctype/print_heading/print_heading.py
index 00dc0f3d91..3d5cd2d6f9 100644
--- a/erpnext/setup/doctype/print_heading/print_heading.py
+++ b/erpnext/setup/doctype/print_heading/print_heading.py
@@ -7,4 +7,4 @@ import frappe
from frappe.model.document import Document
class PrintHeading(Document):
- pass
\ No newline at end of file
+ pass
diff --git a/erpnext/setup/doctype/print_heading/test_print_heading.py b/erpnext/setup/doctype/print_heading/test_print_heading.py
index 59455d2b1d..b2be2e375e 100644
--- a/erpnext/setup/doctype/print_heading/test_print_heading.py
+++ b/erpnext/setup/doctype/print_heading/test_print_heading.py
@@ -4,4 +4,4 @@ from __future__ import unicode_literals
import frappe
-test_records = frappe.get_test_records('Print Heading')
\ No newline at end of file
+test_records = frappe.get_test_records('Print Heading')
diff --git a/erpnext/setup/doctype/quotation_lost_reason/quotation_lost_reason.js b/erpnext/setup/doctype/quotation_lost_reason/quotation_lost_reason.js
index 3878a791db..3680906057 100644
--- a/erpnext/setup/doctype/quotation_lost_reason/quotation_lost_reason.js
+++ b/erpnext/setup/doctype/quotation_lost_reason/quotation_lost_reason.js
@@ -1,13 +1,13 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
-
+
//--------- ONLOAD -------------
cur_frm.cscript.onload = function(doc, cdt, cdn) {
-
+
}
cur_frm.cscript.refresh = function(doc, cdt, cdn) {
-
-}
\ No newline at end of file
+
+}
diff --git a/erpnext/setup/doctype/quotation_lost_reason/quotation_lost_reason.py b/erpnext/setup/doctype/quotation_lost_reason/quotation_lost_reason.py
index 2cc6235b94..42c5a5a54f 100644
--- a/erpnext/setup/doctype/quotation_lost_reason/quotation_lost_reason.py
+++ b/erpnext/setup/doctype/quotation_lost_reason/quotation_lost_reason.py
@@ -7,4 +7,4 @@ import frappe
from frappe.model.document import Document
class QuotationLostReason(Document):
- pass
\ No newline at end of file
+ pass
diff --git a/erpnext/setup/doctype/quotation_lost_reason/test_quotation_lost_reason.py b/erpnext/setup/doctype/quotation_lost_reason/test_quotation_lost_reason.py
index ff4c7885bc..f6b30b649b 100644
--- a/erpnext/setup/doctype/quotation_lost_reason/test_quotation_lost_reason.py
+++ b/erpnext/setup/doctype/quotation_lost_reason/test_quotation_lost_reason.py
@@ -4,4 +4,4 @@ from __future__ import unicode_literals
import frappe
-test_records = frappe.get_test_records('Quotation Lost Reason')
\ No newline at end of file
+test_records = frappe.get_test_records('Quotation Lost Reason')
diff --git a/erpnext/setup/doctype/sales_person/sales_person_dashboard.py b/erpnext/setup/doctype/sales_person/sales_person_dashboard.py
index 3d0b2ff7f8..662008ec8d 100644
--- a/erpnext/setup/doctype/sales_person/sales_person_dashboard.py
+++ b/erpnext/setup/doctype/sales_person/sales_person_dashboard.py
@@ -12,4 +12,4 @@ def get_data():
'items': ['Sales Order', 'Delivery Note', 'Sales Invoice']
},
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/setup/doctype/sales_person/sales_person_tree.js b/erpnext/setup/doctype/sales_person/sales_person_tree.js
index bcdfac926c..00056fde86 100644
--- a/erpnext/setup/doctype/sales_person/sales_person_tree.js
+++ b/erpnext/setup/doctype/sales_person/sales_person_tree.js
@@ -9,4 +9,4 @@ frappe.treeview_settings["Sales Person"] = {
{fieldtype:'Check', fieldname:'is_group', label:__('Group Node'),
description: __("Further nodes can be only created under 'Group' type nodes")}
],
-}
\ No newline at end of file
+}
diff --git a/erpnext/setup/doctype/supplier_group/supplier_group_tree.js b/erpnext/setup/doctype/supplier_group/supplier_group_tree.js
index 0788e2e167..728793eb25 100644
--- a/erpnext/setup/doctype/supplier_group/supplier_group_tree.js
+++ b/erpnext/setup/doctype/supplier_group/supplier_group_tree.js
@@ -1,4 +1,4 @@
frappe.treeview_settings["Supplier Group"] = {
breadcrumbs: "Buying",
ignore_fields:["parent_supplier_group"]
-};
\ No newline at end of file
+};
diff --git a/erpnext/setup/doctype/target_detail/target_detail.py b/erpnext/setup/doctype/target_detail/target_detail.py
index d2e2597cb4..633be45d20 100644
--- a/erpnext/setup/doctype/target_detail/target_detail.py
+++ b/erpnext/setup/doctype/target_detail/target_detail.py
@@ -7,4 +7,4 @@ import frappe
from frappe.model.document import Document
class TargetDetail(Document):
- pass
\ No newline at end of file
+ pass
diff --git a/erpnext/setup/doctype/terms_and_conditions/terms_and_conditions.js b/erpnext/setup/doctype/terms_and_conditions/terms_and_conditions.js
index 3878a791db..3680906057 100644
--- a/erpnext/setup/doctype/terms_and_conditions/terms_and_conditions.js
+++ b/erpnext/setup/doctype/terms_and_conditions/terms_and_conditions.js
@@ -1,13 +1,13 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
-
+
//--------- ONLOAD -------------
cur_frm.cscript.onload = function(doc, cdt, cdn) {
-
+
}
cur_frm.cscript.refresh = function(doc, cdt, cdn) {
-
-}
\ No newline at end of file
+
+}
diff --git a/erpnext/setup/doctype/terms_and_conditions/terms_and_conditions.py b/erpnext/setup/doctype/terms_and_conditions/terms_and_conditions.py
index 372cc6d3e3..5b00ccbdbb 100644
--- a/erpnext/setup/doctype/terms_and_conditions/terms_and_conditions.py
+++ b/erpnext/setup/doctype/terms_and_conditions/terms_and_conditions.py
@@ -24,6 +24,6 @@ def get_terms_and_conditions(template_name, doc):
doc = json.loads(doc)
terms_and_conditions = frappe.get_doc("Terms and Conditions", template_name)
-
+
if terms_and_conditions.terms:
- return frappe.render_template(terms_and_conditions.terms, doc)
\ No newline at end of file
+ return frappe.render_template(terms_and_conditions.terms, doc)
diff --git a/erpnext/setup/doctype/territory/territory.js b/erpnext/setup/doctype/territory/territory.js
index ceec47ae8c..3caf814c90 100644
--- a/erpnext/setup/doctype/territory/territory.js
+++ b/erpnext/setup/doctype/territory/territory.js
@@ -36,4 +36,4 @@ cur_frm.fields_dict['parent_territory'].get_query = function(doc,cdt,cdn) {
['Territory', 'name', '!=', doc.territory_name]
]
}
-}
\ No newline at end of file
+}
diff --git a/erpnext/setup/doctype/territory/territory.py b/erpnext/setup/doctype/territory/territory.py
index 05e8f666cf..7eefe77495 100644
--- a/erpnext/setup/doctype/territory/territory.py
+++ b/erpnext/setup/doctype/territory/territory.py
@@ -24,4 +24,4 @@ class Territory(NestedSet):
self.validate_one_root()
def on_doctype_update():
- frappe.db.add_index("Territory", ["lft", "rgt"])
\ No newline at end of file
+ frappe.db.add_index("Territory", ["lft", "rgt"])
diff --git a/erpnext/setup/doctype/territory/territory_tree.js b/erpnext/setup/doctype/territory/territory_tree.js
index edd11dfa69..dadeeef09e 100644
--- a/erpnext/setup/doctype/territory/territory_tree.js
+++ b/erpnext/setup/doctype/territory/territory_tree.js
@@ -1,3 +1,3 @@
frappe.treeview_settings["Territory"] = {
ignore_fields:["parent_territory"]
-}
\ No newline at end of file
+}
diff --git a/erpnext/setup/doctype/transaction_deletion_record/test_transaction_deletion_record.py b/erpnext/setup/doctype/transaction_deletion_record/test_transaction_deletion_record.py
index bbe68369ff..933a8c3bed 100644
--- a/erpnext/setup/doctype/transaction_deletion_record/test_transaction_deletion_record.py
+++ b/erpnext/setup/doctype/transaction_deletion_record/test_transaction_deletion_record.py
@@ -23,7 +23,7 @@ class TestTransactionDeletionRecord(unittest.TestCase):
contains_company = True
break
self.assertTrue(contains_company)
-
+
def test_no_of_docs_is_correct(self):
for i in range(5):
create_task('Dunder Mifflin Paper Co')
@@ -40,13 +40,13 @@ class TestTransactionDeletionRecord(unittest.TestCase):
'company' : 'Dunder Mifflin Paper Co'
})
self.assertEqual(tasks_containing_company, [])
-
+
def create_company(company_name):
company = frappe.get_doc({
'doctype': 'Company',
'company_name': company_name,
'default_currency': 'INR'
- })
+ })
company.insert(ignore_if_duplicate = True)
def create_transaction_deletion_request(company):
diff --git a/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.js b/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.js
index 20caa15ee4..6a50ef8bbd 100644
--- a/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.js
+++ b/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.js
@@ -4,7 +4,7 @@
frappe.ui.form.on('Transaction Deletion Record', {
onload: function(frm) {
if (frm.doc.docstatus == 0) {
- let doctypes_to_be_ignored_array;
+ let doctypes_to_be_ignored_array;
frappe.call({
method: 'erpnext.setup.doctype.transaction_deletion_record.transaction_deletion_record.get_doctypes_to_be_ignored',
callback: function(r) {
@@ -25,15 +25,15 @@ frappe.ui.form.on('Transaction Deletion Record', {
frm.fields_dict['doctypes_to_be_ignored'].grid.set_column_disp('no_of_docs', false);
frm.refresh_field('doctypes_to_be_ignored');
}
-
+
});
function populate_doctypes_to_be_ignored(doctypes_to_be_ignored_array, frm) {
if (!(frm.doc.doctypes_to_be_ignored)) {
var i;
- for (i = 0; i < doctypes_to_be_ignored_array.length; i++) {
+ for (i = 0; i < doctypes_to_be_ignored_array.length; i++) {
frm.add_child('doctypes_to_be_ignored', {
- doctype_name: doctypes_to_be_ignored_array[i]
+ doctype_name: doctypes_to_be_ignored_array[i]
});
}
}
diff --git a/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record_list.js b/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record_list.js
index d7175ddac4..c238f18aba 100644
--- a/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record_list.js
+++ b/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record_list.js
@@ -9,4 +9,4 @@ frappe.listview_settings['Transaction Deletion Record'] = {
return [__("Completed"), "green"];
}
}
-};
\ No newline at end of file
+};
diff --git a/erpnext/setup/doctype/uom/uom.js b/erpnext/setup/doctype/uom/uom.js
index 3878a791db..3680906057 100644
--- a/erpnext/setup/doctype/uom/uom.js
+++ b/erpnext/setup/doctype/uom/uom.js
@@ -1,13 +1,13 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
-
+
//--------- ONLOAD -------------
cur_frm.cscript.onload = function(doc, cdt, cdn) {
-
+
}
cur_frm.cscript.refresh = function(doc, cdt, cdn) {
-
-}
\ No newline at end of file
+
+}
diff --git a/erpnext/setup/doctype/uom/uom.py b/erpnext/setup/doctype/uom/uom.py
index f7f86d6750..404b84b113 100644
--- a/erpnext/setup/doctype/uom/uom.py
+++ b/erpnext/setup/doctype/uom/uom.py
@@ -7,4 +7,4 @@ import frappe
from frappe.model.document import Document
class UOM(Document):
- pass
\ No newline at end of file
+ pass
diff --git a/erpnext/setup/doctype/website_item_group/website_item_group.py b/erpnext/setup/doctype/website_item_group/website_item_group.py
index 9ac7df2c66..e416b509b9 100644
--- a/erpnext/setup/doctype/website_item_group/website_item_group.py
+++ b/erpnext/setup/doctype/website_item_group/website_item_group.py
@@ -9,4 +9,4 @@ import frappe
from frappe.model.document import Document
class WebsiteItemGroup(Document):
- pass
\ No newline at end of file
+ pass
diff --git a/erpnext/setup/setup_wizard/operations/sample_data.py b/erpnext/setup/setup_wizard/operations/sample_data.py
index c11a3885c9..c6d9f0851b 100644
--- a/erpnext/setup/setup_wizard/operations/sample_data.py
+++ b/erpnext/setup/setup_wizard/operations/sample_data.py
@@ -173,4 +173,4 @@ def test_sample():
frappe.db.sql('delete from tabProject')
frappe.db.sql('delete from tabTask')
make_projects('Education')
- import_notification()
\ No newline at end of file
+ import_notification()
diff --git a/erpnext/setup/setup_wizard/operations/taxes_setup.py b/erpnext/setup/setup_wizard/operations/taxes_setup.py
index bacada9f5c..faa25dfbaa 100644
--- a/erpnext/setup/setup_wizard/operations/taxes_setup.py
+++ b/erpnext/setup/setup_wizard/operations/taxes_setup.py
@@ -145,7 +145,7 @@ def make_taxes_and_charges_template(company_name, doctype, template):
doc = frappe.get_doc(template)
- # Data in country wise json is already pre validated, hence validations can be ignored
+ # Data in country wise json is already pre validated, hence validations can be ignored
# Ingone validations to make doctypes faster
doc.flags.ignore_links = True
doc.flags.ignore_validate = True
@@ -177,7 +177,7 @@ def make_item_tax_template(company_name, template):
doc = frappe.get_doc(template)
- # Data in country wise json is already pre validated, hence validations can be ignored
+ # Data in country wise json is already pre validated, hence validations can be ignored
# Ingone validations to make doctypes faster
doc.flags.ignore_links = True
doc.flags.ignore_validate = True
diff --git a/erpnext/shopping_cart/doctype/shopping_cart_settings/shopping_cart_settings.py b/erpnext/shopping_cart/doctype/shopping_cart_settings/shopping_cart_settings.py
index c069b90e98..2a497225fb 100644
--- a/erpnext/shopping_cart/doctype/shopping_cart_settings/shopping_cart_settings.py
+++ b/erpnext/shopping_cart/doctype/shopping_cart_settings/shopping_cart_settings.py
@@ -31,7 +31,7 @@ class ShoppingCartSettings(Document):
[self.price_list], "currency")
price_list_currency_map = dict(price_list_currency_map)
-
+
# check if all price lists have a currency
for price_list, currency in price_list_currency_map.items():
if not currency:
diff --git a/erpnext/shopping_cart/doctype/shopping_cart_settings/test_shopping_cart_settings.py b/erpnext/shopping_cart/doctype/shopping_cart_settings/test_shopping_cart_settings.py
index 75899e121a..008751e208 100644
--- a/erpnext/shopping_cart/doctype/shopping_cart_settings/test_shopping_cart_settings.py
+++ b/erpnext/shopping_cart/doctype/shopping_cart_settings/test_shopping_cart_settings.py
@@ -36,7 +36,7 @@ class TestShoppingCartSettings(unittest.TestCase):
cart_settings.enabled = 1
if not frappe.db.get_value("Tax Rule", {"use_for_shopping_cart": 1}, "name"):
self.assertRaises(ShoppingCartSetupError, cart_settings.validate_tax_rule)
-
+
frappe.db.sql("update `tabTax Rule` set use_for_shopping_cart = 1")
-test_dependencies = ["Tax Rule"]
\ No newline at end of file
+test_dependencies = ["Tax Rule"]
diff --git a/erpnext/shopping_cart/product_info.py b/erpnext/shopping_cart/product_info.py
index 29617a8748..6c9e531a4d 100644
--- a/erpnext/shopping_cart/product_info.py
+++ b/erpnext/shopping_cart/product_info.py
@@ -66,4 +66,4 @@ def set_product_info_for_website(item):
item["price_sales_uom"] = product_info.get("price").get("formatted_price_sales_uom")
else:
item["price_stock_uom"] = ""
- item["price_sales_uom"] = ""
\ No newline at end of file
+ item["price_sales_uom"] = ""
diff --git a/erpnext/shopping_cart/search.py b/erpnext/shopping_cart/search.py
index 63e9fe1b31..9f674dcebf 100644
--- a/erpnext/shopping_cart/search.py
+++ b/erpnext/shopping_cart/search.py
@@ -123,4 +123,4 @@ def remove_document_from_index(path):
def build_index_for_all_routes():
search = ProductSearch(INDEX_NAME)
- return search.build()
\ No newline at end of file
+ return search.build()
diff --git a/erpnext/shopping_cart/utils.py b/erpnext/shopping_cart/utils.py
index 3241234af5..0e1466fd1f 100644
--- a/erpnext/shopping_cart/utils.py
+++ b/erpnext/shopping_cart/utils.py
@@ -38,4 +38,4 @@ def check_customer_or_supplier():
if link.link_doctype in ('Customer', 'Supplier'):
return link.link_doctype, link.link_name
- return 'Customer', None
\ No newline at end of file
+ return 'Customer', None
diff --git a/erpnext/shopping_cart/web_template/hero_slider/hero_slider.html b/erpnext/shopping_cart/web_template/hero_slider/hero_slider.html
index 1b3953435e..1e3d0d069a 100644
--- a/erpnext/shopping_cart/web_template/hero_slider/hero_slider.html
+++ b/erpnext/shopping_cart/web_template/hero_slider/hero_slider.html
@@ -82,4 +82,4 @@
\ No newline at end of file
+
diff --git a/erpnext/shopping_cart/web_template/item_card_group/item_card_group.html b/erpnext/shopping_cart/web_template/item_card_group/item_card_group.html
index 890ae502c8..fe061d5f5f 100644
--- a/erpnext/shopping_cart/web_template/item_card_group/item_card_group.html
+++ b/erpnext/shopping_cart/web_template/item_card_group/item_card_group.html
@@ -35,4 +35,4 @@
\ No newline at end of file
+
diff --git a/erpnext/startup/filters.py b/erpnext/startup/filters.py
index ec07329ded..98210165df 100644
--- a/erpnext/startup/filters.py
+++ b/erpnext/startup/filters.py
@@ -11,4 +11,4 @@ def get_filters_config():
}
}
- return filters_config
\ No newline at end of file
+ return filters_config
diff --git a/erpnext/startup/leaderboard.py b/erpnext/startup/leaderboard.py
index 8819a55c0a..a89435d486 100644
--- a/erpnext/startup/leaderboard.py
+++ b/erpnext/startup/leaderboard.py
@@ -202,4 +202,4 @@ def get_date_condition(date_range, field):
date_condition = "and {0} between {1} and {2}".format(
field, frappe.db.escape(from_date), frappe.db.escape(to_date)
)
- return date_condition
\ No newline at end of file
+ return date_condition
diff --git a/erpnext/stock/dashboard/item_dashboard.html b/erpnext/stock/dashboard/item_dashboard.html
index 1e18969e63..99698ba69a 100644
--- a/erpnext/stock/dashboard/item_dashboard.html
+++ b/erpnext/stock/dashboard/item_dashboard.html
@@ -4,4 +4,4 @@
-
\ No newline at end of file
+
diff --git a/erpnext/stock/dashboard/warehouse_capacity_dashboard.py b/erpnext/stock/dashboard/warehouse_capacity_dashboard.py
index ab573e566a..70b030e48f 100644
--- a/erpnext/stock/dashboard/warehouse_capacity_dashboard.py
+++ b/erpnext/stock/dashboard/warehouse_capacity_dashboard.py
@@ -66,4 +66,4 @@ def get_warehouse_capacity_data(filters, start):
'percent_occupied': flt((flt(balance_qty) / flt(entry.stock_capacity)) * 100, 0)
})
- return capacity_data
\ No newline at end of file
+ return capacity_data
diff --git a/erpnext/stock/dashboard_chart_source/warehouse_wise_stock_value/warehouse_wise_stock_value.js b/erpnext/stock/dashboard_chart_source/warehouse_wise_stock_value/warehouse_wise_stock_value.js
index a4137547f7..2b9d46e4ab 100644
--- a/erpnext/stock/dashboard_chart_source/warehouse_wise_stock_value/warehouse_wise_stock_value.js
+++ b/erpnext/stock/dashboard_chart_source/warehouse_wise_stock_value/warehouse_wise_stock_value.js
@@ -11,4 +11,4 @@ frappe.dashboards.chart_sources["Warehouse wise Stock Value"] = {
default: frappe.defaults.get_user_default("Company")
}
]
-};
\ No newline at end of file
+};
diff --git a/erpnext/stock/dashboard_chart_source/warehouse_wise_stock_value/warehouse_wise_stock_value.py b/erpnext/stock/dashboard_chart_source/warehouse_wise_stock_value/warehouse_wise_stock_value.py
index 374a34ea7c..2258532c6f 100644
--- a/erpnext/stock/dashboard_chart_source/warehouse_wise_stock_value/warehouse_wise_stock_value.py
+++ b/erpnext/stock/dashboard_chart_source/warehouse_wise_stock_value/warehouse_wise_stock_value.py
@@ -45,4 +45,4 @@ def get(chart_name = None, chart = None, no_cache = None, filters = None, from_d
"values": datapoints
}],
"type": "bar"
- }
\ No newline at end of file
+ }
diff --git a/erpnext/stock/doctype/batch/test_batch.js b/erpnext/stock/doctype/batch/test_batch.js
index af7f50ff91..2d2150b8ac 100644
--- a/erpnext/stock/doctype/batch/test_batch.js
+++ b/erpnext/stock/doctype/batch/test_batch.js
@@ -20,4 +20,3 @@ QUnit.test("test Batch", function(assert) {
() => done()
]);
});
-
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note_dashboard.py b/erpnext/stock/doctype/delivery_note/delivery_note_dashboard.py
index 47684d5c6e..9db5db865f 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note_dashboard.py
+++ b/erpnext/stock/doctype/delivery_note/delivery_note_dashboard.py
@@ -30,4 +30,4 @@ def get_data():
'items': ['Auto Repeat']
},
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/stock/doctype/delivery_note/regional/india.js b/erpnext/stock/doctype/delivery_note/regional/india.js
index 5e1ff98000..e853858b60 100644
--- a/erpnext/stock/doctype/delivery_note/regional/india.js
+++ b/erpnext/stock/doctype/delivery_note/regional/india.js
@@ -27,4 +27,3 @@ frappe.ui.form.on('Delivery Note', {
}
}
})
-
diff --git a/erpnext/stock/doctype/delivery_note/test_delivery_note.js b/erpnext/stock/doctype/delivery_note/test_delivery_note.js
index 3f6e8d1503..76f7989429 100644
--- a/erpnext/stock/doctype/delivery_note/test_delivery_note.js
+++ b/erpnext/stock/doctype/delivery_note/test_delivery_note.js
@@ -33,4 +33,3 @@ QUnit.test("test delivery note", function(assert) {
() => done()
]);
});
-
diff --git a/erpnext/stock/doctype/delivery_note/test_delivery_note.py b/erpnext/stock/doctype/delivery_note/test_delivery_note.py
index 756825e826..91e7c006ee 100644
--- a/erpnext/stock/doctype/delivery_note/test_delivery_note.py
+++ b/erpnext/stock/doctype/delivery_note/test_delivery_note.py
@@ -772,7 +772,7 @@ class TestDeliveryNote(unittest.TestCase):
so.submit()
dn = create_dn_against_so(so.name, delivered_qty=10)
-
+
si = create_sales_invoice(qty=10, do_not_save=1)
si.items[0].delivery_note= dn.name
si.items[0].dn_detail = dn.items[0].name
diff --git a/erpnext/stock/doctype/delivery_note/test_delivery_note_with_margin.js b/erpnext/stock/doctype/delivery_note/test_delivery_note_with_margin.js
index 21eb35ce37..9f1375f563 100644
--- a/erpnext/stock/doctype/delivery_note/test_delivery_note_with_margin.js
+++ b/erpnext/stock/doctype/delivery_note/test_delivery_note_with_margin.js
@@ -34,4 +34,3 @@ QUnit.test("test delivery note with margin", function(assert) {
() => done()
]);
});
-
diff --git a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.py b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.py
index 5030595789..8bd381a2ed 100644
--- a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.py
+++ b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.py
@@ -7,4 +7,4 @@ import frappe
from frappe.model.document import Document
class DeliveryNoteItem(Document):
- pass
\ No newline at end of file
+ pass
diff --git a/erpnext/stock/doctype/delivery_trip/delivery_trip.py b/erpnext/stock/doctype/delivery_trip/delivery_trip.py
index 9ec28d8981..f76bb87efe 100644
--- a/erpnext/stock/doctype/delivery_trip/delivery_trip.py
+++ b/erpnext/stock/doctype/delivery_trip/delivery_trip.py
@@ -406,4 +406,4 @@ def make_expense_claim(source_name, target_doc=None):
}
}}, target_doc)
- return doc
\ No newline at end of file
+ return doc
diff --git a/erpnext/stock/doctype/delivery_trip/dispatch_notification_template.html b/erpnext/stock/doctype/delivery_trip/dispatch_notification_template.html
index 9c062bc34c..d12334e355 100644
--- a/erpnext/stock/doctype/delivery_trip/dispatch_notification_template.html
+++ b/erpnext/stock/doctype/delivery_trip/dispatch_notification_template.html
@@ -47,4 +47,4 @@
{{ vehicle }}
-
\ No newline at end of file
+
diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py
index 614c53abb5..422fe3e4b7 100644
--- a/erpnext/stock/doctype/item/item.py
+++ b/erpnext/stock/doctype/item/item.py
@@ -1309,4 +1309,4 @@ def on_doctype_update():
@erpnext.allow_regional
def set_item_tax_from_hsn_code(item):
- pass
\ No newline at end of file
+ pass
diff --git a/erpnext/stock/doctype/item/regional/india.js b/erpnext/stock/doctype/item/regional/india.js
index 77ae51fa34..cceb1ec895 100644
--- a/erpnext/stock/doctype/item/regional/india.js
+++ b/erpnext/stock/doctype/item/regional/india.js
@@ -12,4 +12,4 @@ frappe.ui.form.on('Item', {
});
}
},
-});
\ No newline at end of file
+});
diff --git a/erpnext/stock/doctype/item/templates/item.html b/erpnext/stock/doctype/item/templates/item.html
index db123090aa..5c42f3b124 100644
--- a/erpnext/stock/doctype/item/templates/item.html
+++ b/erpnext/stock/doctype/item/templates/item.html
@@ -4,4 +4,4 @@
{{ title }}
{% endblock %}
-
\ No newline at end of file
+
diff --git a/erpnext/stock/doctype/item/templates/item_row.html b/erpnext/stock/doctype/item/templates/item_row.html
index 2b999819cb..f81fc1d874 100644
--- a/erpnext/stock/doctype/item/templates/item_row.html
+++ b/erpnext/stock/doctype/item/templates/item_row.html
@@ -1,4 +1,4 @@
-
\ No newline at end of file
+
diff --git a/erpnext/stock/doctype/item/tests/test_item.js b/erpnext/stock/doctype/item/tests/test_item.js
index 5e3524e5b6..7f7e72d5c0 100644
--- a/erpnext/stock/doctype/item/tests/test_item.js
+++ b/erpnext/stock/doctype/item/tests/test_item.js
@@ -118,4 +118,4 @@ QUnit.test("test: item", function (assert) {
),
() => done()
]);
-});
\ No newline at end of file
+});
diff --git a/erpnext/stock/doctype/item_attribute/test_item_attribute.py b/erpnext/stock/doctype/item_attribute/test_item_attribute.py
index 61e53d24a4..07af176a94 100644
--- a/erpnext/stock/doctype/item_attribute/test_item_attribute.py
+++ b/erpnext/stock/doctype/item_attribute/test_item_attribute.py
@@ -28,4 +28,3 @@ class TestItemAttribute(unittest.TestCase):
item_attribute.increment = 0.5
item_attribute.save()
-
diff --git a/erpnext/stock/doctype/item_customer_detail/item_customer_detail.py b/erpnext/stock/doctype/item_customer_detail/item_customer_detail.py
index a9183ce586..3e4e850046 100644
--- a/erpnext/stock/doctype/item_customer_detail/item_customer_detail.py
+++ b/erpnext/stock/doctype/item_customer_detail/item_customer_detail.py
@@ -7,4 +7,4 @@ import frappe
from frappe.model.document import Document
class ItemCustomerDetail(Document):
- pass
\ No newline at end of file
+ pass
diff --git a/erpnext/stock/doctype/item_manufacturer/item_manufacturer.py b/erpnext/stock/doctype/item_manufacturer/item_manufacturer.py
index c27d1be789..939abf8d32 100644
--- a/erpnext/stock/doctype/item_manufacturer/item_manufacturer.py
+++ b/erpnext/stock/doctype/item_manufacturer/item_manufacturer.py
@@ -65,4 +65,4 @@ class ItemManufacturer(Document):
@frappe.whitelist()
def get_item_manufacturer_part_no(item_code, manufacturer):
return frappe.db.get_value("Item Manufacturer",
- {'item_code': item_code, 'manufacturer': manufacturer}, 'manufacturer_part_no')
\ No newline at end of file
+ {'item_code': item_code, 'manufacturer': manufacturer}, 'manufacturer_part_no')
diff --git a/erpnext/stock/doctype/item_quality_inspection_parameter/item_quality_inspection_parameter.py b/erpnext/stock/doctype/item_quality_inspection_parameter/item_quality_inspection_parameter.py
index 92aefc8d9e..785737b267 100644
--- a/erpnext/stock/doctype/item_quality_inspection_parameter/item_quality_inspection_parameter.py
+++ b/erpnext/stock/doctype/item_quality_inspection_parameter/item_quality_inspection_parameter.py
@@ -7,4 +7,4 @@ import frappe
from frappe.model.document import Document
class ItemQualityInspectionParameter(Document):
- pass
\ No newline at end of file
+ pass
diff --git a/erpnext/stock/doctype/item_reorder/item_reorder.py b/erpnext/stock/doctype/item_reorder/item_reorder.py
index 0f9c593d36..5cdaa22956 100644
--- a/erpnext/stock/doctype/item_reorder/item_reorder.py
+++ b/erpnext/stock/doctype/item_reorder/item_reorder.py
@@ -9,4 +9,4 @@ import frappe
from frappe.model.document import Document
class ItemReorder(Document):
- pass
\ No newline at end of file
+ pass
diff --git a/erpnext/stock/doctype/item_supplier/item_supplier.py b/erpnext/stock/doctype/item_supplier/item_supplier.py
index 1a07f03ec5..5dda535f81 100644
--- a/erpnext/stock/doctype/item_supplier/item_supplier.py
+++ b/erpnext/stock/doctype/item_supplier/item_supplier.py
@@ -7,4 +7,4 @@ import frappe
from frappe.model.document import Document
class ItemSupplier(Document):
- pass
\ No newline at end of file
+ pass
diff --git a/erpnext/stock/doctype/item_tax/item_tax.py b/erpnext/stock/doctype/item_tax/item_tax.py
index 1fe2f45468..7c9e811575 100644
--- a/erpnext/stock/doctype/item_tax/item_tax.py
+++ b/erpnext/stock/doctype/item_tax/item_tax.py
@@ -7,4 +7,4 @@ import frappe
from frappe.model.document import Document
class ItemTax(Document):
- pass
\ No newline at end of file
+ pass
diff --git a/erpnext/stock/doctype/item_website_specification/item_website_specification.py b/erpnext/stock/doctype/item_website_specification/item_website_specification.py
index 6d0dbad2a5..e3041cf3ee 100644
--- a/erpnext/stock/doctype/item_website_specification/item_website_specification.py
+++ b/erpnext/stock/doctype/item_website_specification/item_website_specification.py
@@ -9,4 +9,4 @@ import frappe
from frappe.model.document import Document
class ItemWebsiteSpecification(Document):
- pass
\ No newline at end of file
+ pass
diff --git a/erpnext/stock/doctype/landed_cost_item/landed_cost_item.py b/erpnext/stock/doctype/landed_cost_item/landed_cost_item.py
index 0521a7ad1c..493e8b239a 100644
--- a/erpnext/stock/doctype/landed_cost_item/landed_cost_item.py
+++ b/erpnext/stock/doctype/landed_cost_item/landed_cost_item.py
@@ -7,4 +7,4 @@ import frappe
from frappe.model.document import Document
class LandedCostItem(Document):
- pass
\ No newline at end of file
+ pass
diff --git a/erpnext/stock/doctype/landed_cost_purchase_receipt/landed_cost_purchase_receipt.py b/erpnext/stock/doctype/landed_cost_purchase_receipt/landed_cost_purchase_receipt.py
index f7ccb9b6e2..38f4eafc3a 100644
--- a/erpnext/stock/doctype/landed_cost_purchase_receipt/landed_cost_purchase_receipt.py
+++ b/erpnext/stock/doctype/landed_cost_purchase_receipt/landed_cost_purchase_receipt.py
@@ -7,4 +7,4 @@ import frappe
from frappe.model.document import Document
class LandedCostPurchaseReceipt(Document):
- pass
\ No newline at end of file
+ pass
diff --git a/erpnext/stock/doctype/landed_cost_taxes_and_charges/landed_cost_taxes_and_charges.py b/erpnext/stock/doctype/landed_cost_taxes_and_charges/landed_cost_taxes_and_charges.py
index e4458207db..0dc396aefa 100644
--- a/erpnext/stock/doctype/landed_cost_taxes_and_charges/landed_cost_taxes_and_charges.py
+++ b/erpnext/stock/doctype/landed_cost_taxes_and_charges/landed_cost_taxes_and_charges.py
@@ -6,4 +6,4 @@ import frappe
from frappe.model.document import Document
class LandedCostTaxesandCharges(Document):
- pass
\ No newline at end of file
+ pass
diff --git a/erpnext/stock/doctype/material_request/material_request_dashboard.py b/erpnext/stock/doctype/material_request/material_request_dashboard.py
index f3e5e5db25..e1e4faf682 100644
--- a/erpnext/stock/doctype/material_request/material_request_dashboard.py
+++ b/erpnext/stock/doctype/material_request/material_request_dashboard.py
@@ -20,4 +20,4 @@ def get_data():
'items': ['Work Order']
}
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/stock/doctype/material_request/tests/test_material_request.js b/erpnext/stock/doctype/material_request/tests/test_material_request.js
index bf26cd117f..a2cd03b649 100644
--- a/erpnext/stock/doctype/material_request/tests/test_material_request.js
+++ b/erpnext/stock/doctype/material_request/tests/test_material_request.js
@@ -37,4 +37,3 @@ QUnit.test("test material request", function(assert) {
() => done()
]);
});
-
diff --git a/erpnext/stock/doctype/material_request/tests/test_material_request_from_bom.js b/erpnext/stock/doctype/material_request/tests/test_material_request_from_bom.js
index d8b39fe5aa..6fb55ae02a 100644
--- a/erpnext/stock/doctype/material_request/tests/test_material_request_from_bom.js
+++ b/erpnext/stock/doctype/material_request/tests/test_material_request_from_bom.js
@@ -25,4 +25,3 @@ QUnit.test("test material request get items from BOM", function(assert) {
() => done()
]);
});
-
diff --git a/erpnext/stock/doctype/material_request/tests/test_material_request_type_manufacture.js b/erpnext/stock/doctype/material_request/tests/test_material_request_type_manufacture.js
index 91b47bac4d..137079b983 100644
--- a/erpnext/stock/doctype/material_request/tests/test_material_request_type_manufacture.js
+++ b/erpnext/stock/doctype/material_request/tests/test_material_request_type_manufacture.js
@@ -27,4 +27,3 @@ QUnit.test("test material request", function(assert) {
() => done()
]);
});
-
diff --git a/erpnext/stock/doctype/material_request/tests/test_material_request_type_material_issue.js b/erpnext/stock/doctype/material_request/tests/test_material_request_type_material_issue.js
index 050e0f0d1c..b03a8543c6 100644
--- a/erpnext/stock/doctype/material_request/tests/test_material_request_type_material_issue.js
+++ b/erpnext/stock/doctype/material_request/tests/test_material_request_type_material_issue.js
@@ -27,4 +27,3 @@ QUnit.test("test material request for issue", function(assert) {
() => done()
]);
});
-
diff --git a/erpnext/stock/doctype/material_request/tests/test_material_request_type_material_transfer.js b/erpnext/stock/doctype/material_request/tests/test_material_request_type_material_transfer.js
index d6f9b66141..7c62c2e63a 100644
--- a/erpnext/stock/doctype/material_request/tests/test_material_request_type_material_transfer.js
+++ b/erpnext/stock/doctype/material_request/tests/test_material_request_type_material_transfer.js
@@ -27,4 +27,3 @@ QUnit.test("test material request for transfer", function(assert) {
() => done()
]);
});
-
diff --git a/erpnext/stock/doctype/material_request_item/material_request_item.py b/erpnext/stock/doctype/material_request_item/material_request_item.py
index 16f007f6a2..e0066e65d2 100644
--- a/erpnext/stock/doctype/material_request_item/material_request_item.py
+++ b/erpnext/stock/doctype/material_request_item/material_request_item.py
@@ -12,4 +12,4 @@ class MaterialRequestItem(Document):
pass
def on_doctype_update():
- frappe.db.add_index("Material Request Item", ["item_code", "warehouse"])
\ No newline at end of file
+ frappe.db.add_index("Material Request Item", ["item_code", "warehouse"])
diff --git a/erpnext/stock/doctype/packing_slip_item/packing_slip_item.py b/erpnext/stock/doctype/packing_slip_item/packing_slip_item.py
index 694ab384bf..b0a855961f 100644
--- a/erpnext/stock/doctype/packing_slip_item/packing_slip_item.py
+++ b/erpnext/stock/doctype/packing_slip_item/packing_slip_item.py
@@ -9,4 +9,4 @@ import frappe
from frappe.model.document import Document
class PackingSlipItem(Document):
- pass
\ No newline at end of file
+ pass
diff --git a/erpnext/stock/doctype/pick_list/pick_list.js b/erpnext/stock/doctype/pick_list/pick_list.js
index ee218f2f68..730fd7a829 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.js
+++ b/erpnext/stock/doctype/pick_list/pick_list.js
@@ -201,4 +201,4 @@ function get_item_details(item_code, uom=null) {
uom
});
}
-}
\ No newline at end of file
+}
diff --git a/erpnext/stock/doctype/pick_list/pick_list_dashboard.py b/erpnext/stock/doctype/pick_list/pick_list_dashboard.py
index 6e007df5e6..7c321c450a 100644
--- a/erpnext/stock/doctype/pick_list/pick_list_dashboard.py
+++ b/erpnext/stock/doctype/pick_list/pick_list_dashboard.py
@@ -9,4 +9,4 @@ def get_data():
'items': ['Stock Entry', 'Delivery Note']
},
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/stock/doctype/price_list/price_list.css b/erpnext/stock/doctype/price_list/price_list.css
index 61b069442f..6832954a81 100644
--- a/erpnext/stock/doctype/price_list/price_list.css
+++ b/erpnext/stock/doctype/price_list/price_list.css
@@ -4,4 +4,4 @@
.table-grid thead tr {
height: 50px;
-}
\ No newline at end of file
+}
diff --git a/erpnext/stock/doctype/price_list/price_list.js b/erpnext/stock/doctype/price_list/price_list.js
index c362b5a765..9291498e86 100644
--- a/erpnext/stock/doctype/price_list/price_list.js
+++ b/erpnext/stock/doctype/price_list/price_list.js
@@ -11,4 +11,4 @@ frappe.ui.form.on("Price List", {
frappe.set_route("Report", "Item Price");
}, "fa fa-money");
}
-});
\ No newline at end of file
+});
diff --git a/erpnext/stock/doctype/price_list/price_list.py b/erpnext/stock/doctype/price_list/price_list.py
index 33713faf69..10abde17eb 100644
--- a/erpnext/stock/doctype/price_list/price_list.py
+++ b/erpnext/stock/doctype/price_list/price_list.py
@@ -62,4 +62,4 @@ def get_price_list_details(price_list):
frappe.cache().hset("price_list_details", price_list, price_list_details)
- return price_list_details or {}
\ No newline at end of file
+ return price_list_details or {}
diff --git a/erpnext/stock/doctype/price_list/test_price_list.py b/erpnext/stock/doctype/price_list/test_price_list.py
index 5979c86129..2c287c9033 100644
--- a/erpnext/stock/doctype/price_list/test_price_list.py
+++ b/erpnext/stock/doctype/price_list/test_price_list.py
@@ -6,4 +6,4 @@ import frappe
# test_ignore = ["Item"]
-test_records = frappe.get_test_records('Price List')
\ No newline at end of file
+test_records = frappe.get_test_records('Price List')
diff --git a/erpnext/stock/doctype/price_list/test_price_list_uom.js b/erpnext/stock/doctype/price_list/test_price_list_uom.js
index 7fbce7d59d..3896c0e59e 100644
--- a/erpnext/stock/doctype/price_list/test_price_list_uom.js
+++ b/erpnext/stock/doctype/price_list/test_price_list_uom.js
@@ -55,4 +55,4 @@ QUnit.test("test price list with uom dependancy", function(assert) {
() => done()
]);
-});
\ No newline at end of file
+});
diff --git a/erpnext/stock/doctype/purchase_receipt/regional/india.js b/erpnext/stock/doctype/purchase_receipt/regional/india.js
index b4f1201f36..2d982cc1bb 100644
--- a/erpnext/stock/doctype/purchase_receipt/regional/india.js
+++ b/erpnext/stock/doctype/purchase_receipt/regional/india.js
@@ -1,3 +1,3 @@
{% include "erpnext/regional/india/taxes.js" %}
-erpnext.setup_auto_gst_taxation('Purchase Receipt');
\ No newline at end of file
+erpnext.setup_auto_gst_taxation('Purchase Receipt');
diff --git a/erpnext/stock/doctype/putaway_rule/putaway_rule.py b/erpnext/stock/doctype/putaway_rule/putaway_rule.py
index 0f50bcd6ea..315e723fab 100644
--- a/erpnext/stock/doctype/putaway_rule/putaway_rule.py
+++ b/erpnext/stock/doctype/putaway_rule/putaway_rule.py
@@ -232,4 +232,4 @@ def get_serial_nos_to_allocate(serial_nos, to_allocate):
allocated_serial_nos = serial_nos[0: cint(to_allocate)]
serial_nos[:] = serial_nos[cint(to_allocate):] # pop out allocated serial nos and modify list
return "\n".join(allocated_serial_nos) if allocated_serial_nos else ""
- else: return ""
\ No newline at end of file
+ else: return ""
diff --git a/erpnext/stock/doctype/putaway_rule/test_putaway_rule.py b/erpnext/stock/doctype/putaway_rule/test_putaway_rule.py
index 86f7dc3e08..0590ae1abe 100644
--- a/erpnext/stock/doctype/putaway_rule/test_putaway_rule.py
+++ b/erpnext/stock/doctype/putaway_rule/test_putaway_rule.py
@@ -386,4 +386,4 @@ def create_putaway_rule(**args):
if not args.do_not_save:
putaway.save()
- return putaway
\ No newline at end of file
+ return putaway
diff --git a/erpnext/stock/doctype/quality_inspection/quality_inspection.js b/erpnext/stock/doctype/quality_inspection/quality_inspection.js
index f7565fd505..d08dc3e8b7 100644
--- a/erpnext/stock/doctype/quality_inspection/quality_inspection.js
+++ b/erpnext/stock/doctype/quality_inspection/quality_inspection.js
@@ -81,4 +81,4 @@ frappe.ui.form.on("Quality Inspection", {
});
}
},
-});
\ No newline at end of file
+});
diff --git a/erpnext/stock/doctype/quality_inspection_reading/quality_inspection_reading.py b/erpnext/stock/doctype/quality_inspection_reading/quality_inspection_reading.py
index 65188a22c6..b10fa310d6 100644
--- a/erpnext/stock/doctype/quality_inspection_reading/quality_inspection_reading.py
+++ b/erpnext/stock/doctype/quality_inspection_reading/quality_inspection_reading.py
@@ -7,4 +7,4 @@ import frappe
from frappe.model.document import Document
class QualityInspectionReading(Document):
- pass
\ No newline at end of file
+ pass
diff --git a/erpnext/stock/doctype/quality_inspection_template/quality_inspection_template.py b/erpnext/stock/doctype/quality_inspection_template/quality_inspection_template.py
index 01d2031b3a..971b3c2982 100644
--- a/erpnext/stock/doctype/quality_inspection_template/quality_inspection_template.py
+++ b/erpnext/stock/doctype/quality_inspection_template/quality_inspection_template.py
@@ -16,4 +16,4 @@ def get_template_details(template):
fields=["specification", "value", "acceptance_formula",
"numeric", "formula_based_criteria", "min_value", "max_value"],
filters={'parenttype': 'Quality Inspection Template', 'parent': template},
- order_by="idx")
\ No newline at end of file
+ order_by="idx")
diff --git a/erpnext/stock/doctype/serial_no/test_serial_no.py b/erpnext/stock/doctype/serial_no/test_serial_no.py
index b9a58cf43e..0eccce3a58 100644
--- a/erpnext/stock/doctype/serial_no/test_serial_no.py
+++ b/erpnext/stock/doctype/serial_no/test_serial_no.py
@@ -193,4 +193,4 @@ class TestSerialNo(unittest.TestCase):
frappe.db.rollback()
def tearDown(self):
- frappe.db.rollback()
\ No newline at end of file
+ frappe.db.rollback()
diff --git a/erpnext/stock/doctype/shipment/shipment.js b/erpnext/stock/doctype/shipment/shipment.js
index ce2906ecbe..13a17a2591 100644
--- a/erpnext/stock/doctype/shipment/shipment.js
+++ b/erpnext/stock/doctype/shipment/shipment.js
@@ -150,8 +150,8 @@ frappe.ui.form.on('Shipment', {
frm.set_value('pickup_contact_name', '');
frm.set_value('pickup_contact', '');
}
- frappe.throw(__("Email or Phone/Mobile of the Contact are mandatory to continue.")
- + "" + __("Please set Email/Phone for the contact")
+ frappe.throw(__("Email or Phone/Mobile of the Contact are mandatory to continue.")
+ + "" + __("Please set Email/Phone for the contact")
+ ` ${contact_name} `);
}
let contact_display = r.message.contact_display;
@@ -244,8 +244,8 @@ frappe.ui.form.on('Shipment', {
frm.set_value('pickup_company', '');
frm.set_value('pickup_contact', '');
}
- frappe.throw(__("Last Name, Email or Phone/Mobile of the user are mandatory to continue.") + ""
- + __("Please first set Last Name, Email and Phone for the user")
+ frappe.throw(__("Last Name, Email or Phone/Mobile of the user are mandatory to continue.") + ""
+ + __("Please first set Last Name, Email and Phone for the user")
+ ` ${frappe.session.user} `);
}
let contact_display = r.full_name;
diff --git a/erpnext/stock/doctype/shipment/shipment_list.js b/erpnext/stock/doctype/shipment/shipment_list.js
index 52b052c81f..ae6a3c154e 100644
--- a/erpnext/stock/doctype/shipment/shipment_list.js
+++ b/erpnext/stock/doctype/shipment/shipment_list.js
@@ -5,4 +5,4 @@ frappe.listview_settings['Shipment'] = {
return [__("Booked"), "green"];
}
}
-};
\ No newline at end of file
+};
diff --git a/erpnext/stock/doctype/shipment/test_shipment.py b/erpnext/stock/doctype/shipment/test_shipment.py
index 9c3e22f023..db2f116174 100644
--- a/erpnext/stock/doctype/shipment/test_shipment.py
+++ b/erpnext/stock/doctype/shipment/test_shipment.py
@@ -24,7 +24,7 @@ def create_test_delivery_note():
customer = get_shipment_customer()
item = get_shipment_item(company.name)
posting_date = date.today() + timedelta(days=1)
-
+
create_material_receipt(item, company.name)
delivery_note = frappe.new_doc("Delivery Note")
delivery_note.company = company.name
@@ -73,7 +73,7 @@ def create_test_shipment(delivery_notes = None):
shipment.pickup_to = '17:00'
shipment.description_of_content = 'unit test entry'
for delivery_note in delivery_notes:
- shipment.append('shipment_delivery_note',
+ shipment.append('shipment_delivery_note',
{
"delivery_note": delivery_note.name
}
@@ -222,7 +222,7 @@ def create_material_receipt(item, company):
)
stock.insert()
stock.submit()
-
+
def create_shipment_item(item_name, company_name):
item = frappe.new_doc("Item")
diff --git a/erpnext/stock/doctype/stock_entry/tests/test_stock_entry_for_material_issue.js b/erpnext/stock/doctype/stock_entry/tests/test_stock_entry_for_material_issue.js
index 3cf4861ccb..a87a7fb7fd 100644
--- a/erpnext/stock/doctype/stock_entry/tests/test_stock_entry_for_material_issue.js
+++ b/erpnext/stock/doctype/stock_entry/tests/test_stock_entry_for_material_issue.js
@@ -28,4 +28,3 @@ QUnit.test("test material request", function(assert) {
() => done()
]);
});
-
diff --git a/erpnext/stock/doctype/stock_entry/tests/test_stock_entry_for_material_issue_with_serialize_item.js b/erpnext/stock/doctype/stock_entry/tests/test_stock_entry_for_material_issue_with_serialize_item.js
index aac09c30cd..cae318d8f2 100644
--- a/erpnext/stock/doctype/stock_entry/tests/test_stock_entry_for_material_issue_with_serialize_item.js
+++ b/erpnext/stock/doctype/stock_entry/tests/test_stock_entry_for_material_issue_with_serialize_item.js
@@ -32,4 +32,3 @@ QUnit.test("test material issue", function(assert) {
() => done()
]);
});
-
diff --git a/erpnext/stock/doctype/stock_entry/tests/test_stock_entry_for_material_receipt.js b/erpnext/stock/doctype/stock_entry/tests/test_stock_entry_for_material_receipt.js
index 828738eb6c..ef0286fe1b 100644
--- a/erpnext/stock/doctype/stock_entry/tests/test_stock_entry_for_material_receipt.js
+++ b/erpnext/stock/doctype/stock_entry/tests/test_stock_entry_for_material_receipt.js
@@ -29,4 +29,3 @@ QUnit.test("test material request", function(assert) {
() => done()
]);
});
-
diff --git a/erpnext/stock/doctype/stock_entry/tests/test_stock_entry_for_material_receipt_for_serialize_item.js b/erpnext/stock/doctype/stock_entry/tests/test_stock_entry_for_material_receipt_for_serialize_item.js
index ffd06642bf..54e1ac8121 100644
--- a/erpnext/stock/doctype/stock_entry/tests/test_stock_entry_for_material_receipt_for_serialize_item.js
+++ b/erpnext/stock/doctype/stock_entry/tests/test_stock_entry_for_material_receipt_for_serialize_item.js
@@ -32,4 +32,3 @@ QUnit.test("test material receipt", function(assert) {
() => done()
]);
});
-
diff --git a/erpnext/stock/doctype/stock_entry/tests/test_stock_entry_for_material_transfer.js b/erpnext/stock/doctype/stock_entry/tests/test_stock_entry_for_material_transfer.js
index cdeb4ab04a..fac0b4b892 100644
--- a/erpnext/stock/doctype/stock_entry/tests/test_stock_entry_for_material_transfer.js
+++ b/erpnext/stock/doctype/stock_entry/tests/test_stock_entry_for_material_transfer.js
@@ -31,4 +31,3 @@ QUnit.test("test material request", function(assert) {
() => done()
]);
});
-
diff --git a/erpnext/stock/doctype/stock_entry/tests/test_stock_entry_for_material_transfer_for_manufacture.js b/erpnext/stock/doctype/stock_entry/tests/test_stock_entry_for_material_transfer_for_manufacture.js
index e8b2973c45..9f85307270 100644
--- a/erpnext/stock/doctype/stock_entry/tests/test_stock_entry_for_material_transfer_for_manufacture.js
+++ b/erpnext/stock/doctype/stock_entry/tests/test_stock_entry_for_material_transfer_for_manufacture.js
@@ -31,4 +31,3 @@ QUnit.test("test material Transfer to manufacture", function(assert) {
() => done()
]);
});
-
diff --git a/erpnext/stock/doctype/stock_entry/tests/test_stock_entry_for_repack.js b/erpnext/stock/doctype/stock_entry/tests/test_stock_entry_for_repack.js
index 699634df6d..20f119ad61 100644
--- a/erpnext/stock/doctype/stock_entry/tests/test_stock_entry_for_repack.js
+++ b/erpnext/stock/doctype/stock_entry/tests/test_stock_entry_for_repack.js
@@ -39,4 +39,3 @@ QUnit.test("test repack", function(assert) {
() => done()
]);
});
-
diff --git a/erpnext/stock/doctype/stock_entry/tests/test_stock_entry_for_subcontract.js b/erpnext/stock/doctype/stock_entry/tests/test_stock_entry_for_subcontract.js
index 770f886d04..8243426032 100644
--- a/erpnext/stock/doctype/stock_entry/tests/test_stock_entry_for_subcontract.js
+++ b/erpnext/stock/doctype/stock_entry/tests/test_stock_entry_for_subcontract.js
@@ -31,4 +31,3 @@ QUnit.test("test material Transfer to manufacture", function(assert) {
() => done()
]);
});
-
diff --git a/erpnext/stock/doctype/stock_entry_detail/stock_entry_detail.py b/erpnext/stock/doctype/stock_entry_detail/stock_entry_detail.py
index f9e062f851..a5623fded2 100644
--- a/erpnext/stock/doctype/stock_entry_detail/stock_entry_detail.py
+++ b/erpnext/stock/doctype/stock_entry_detail/stock_entry_detail.py
@@ -7,4 +7,4 @@ import frappe
from frappe.model.document import Document
class StockEntryDetail(Document):
- pass
\ No newline at end of file
+ pass
diff --git a/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.js b/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.js
index 80001d63fd..666d2c7144 100644
--- a/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.js
+++ b/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.js
@@ -29,4 +29,3 @@ QUnit.test("test Stock Reconciliation", function(assert) {
() => done()
]);
});
-
diff --git a/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py
index c192582531..94b006c894 100644
--- a/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py
+++ b/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py
@@ -458,4 +458,3 @@ def set_valuation_method(item_code, valuation_method):
}, allow_negative_stock=1)
test_dependencies = ["Item", "Warehouse"]
-
diff --git a/erpnext/stock/doctype/uom_conversion_detail/uom_conversion_detail.py b/erpnext/stock/doctype/uom_conversion_detail/uom_conversion_detail.py
index 67fe20bd37..fdead20567 100644
--- a/erpnext/stock/doctype/uom_conversion_detail/uom_conversion_detail.py
+++ b/erpnext/stock/doctype/uom_conversion_detail/uom_conversion_detail.py
@@ -7,4 +7,4 @@ import frappe
from frappe.model.document import Document
class UOMConversionDetail(Document):
- pass
\ No newline at end of file
+ pass
diff --git a/erpnext/stock/doctype/warehouse/test_warehouse.js b/erpnext/stock/doctype/warehouse/test_warehouse.js
index 8ea280cc59..850da1ee45 100644
--- a/erpnext/stock/doctype/warehouse/test_warehouse.js
+++ b/erpnext/stock/doctype/warehouse/test_warehouse.js
@@ -16,4 +16,4 @@ QUnit.test("test: warehouse", function (assert) {
() => done()
]);
-});
\ No newline at end of file
+});
diff --git a/erpnext/stock/doctype/warehouse/test_warehouse.py b/erpnext/stock/doctype/warehouse/test_warehouse.py
index e3981c913e..6e429a2255 100644
--- a/erpnext/stock/doctype/warehouse/test_warehouse.py
+++ b/erpnext/stock/doctype/warehouse/test_warehouse.py
@@ -180,4 +180,4 @@ def get_group_stock_account(company, company_abbr=None):
if not company_abbr:
company_abbr = frappe.get_cached_value("Company", company, 'abbr')
group_stock_account = "Current Assets - " + company_abbr
- return group_stock_account
\ No newline at end of file
+ return group_stock_account
diff --git a/erpnext/stock/doctype/warehouse/warehouse.js b/erpnext/stock/doctype/warehouse/warehouse.js
index 1f172504a7..9243e1ed84 100644
--- a/erpnext/stock/doctype/warehouse/warehouse.js
+++ b/erpnext/stock/doctype/warehouse/warehouse.js
@@ -48,11 +48,11 @@ frappe.ui.form.on("Warehouse", {
frm.add_custom_button(__('Non-Group to Group'),
function() { convert_to_group_or_ledger(frm); }, 'fa fa-retweet', 'btn-default')
}
-
+
frm.toggle_enable(['is_group', 'company'], false);
frappe.dynamic_link = {doc: frm.doc, fieldname: 'name', doctype: 'Warehouse'};
-
+
frm.fields_dict['parent_warehouse'].get_query = function(doc) {
return {
filters: {
@@ -83,6 +83,6 @@ function convert_to_group_or_ledger(frm){
callback: function(){
frm.refresh();
}
-
+
})
-}
\ No newline at end of file
+}
diff --git a/erpnext/stock/doctype/warehouse/warehouse_tree.js b/erpnext/stock/doctype/warehouse/warehouse_tree.js
index 407d7d1ccd..e9e14c7246 100644
--- a/erpnext/stock/doctype/warehouse/warehouse_tree.js
+++ b/erpnext/stock/doctype/warehouse/warehouse_tree.js
@@ -24,4 +24,4 @@ frappe.treeview_settings['Warehouse'] = {
+ '').insertBefore(node.$ul);
}
}
-}
\ No newline at end of file
+}
diff --git a/erpnext/stock/landed_taxes_and_charges_common.js b/erpnext/stock/landed_taxes_and_charges_common.js
index f3f61963a8..ff8a69fb03 100644
--- a/erpnext/stock/landed_taxes_and_charges_common.js
+++ b/erpnext/stock/landed_taxes_and_charges_common.js
@@ -59,4 +59,3 @@ document_list.forEach((doctype) => {
}
});
});
-
diff --git a/erpnext/stock/page/warehouse_capacity_summary/warehouse_capacity_summary.html b/erpnext/stock/page/warehouse_capacity_summary/warehouse_capacity_summary.html
index 90112c78a8..de7e38e7d3 100644
--- a/erpnext/stock/page/warehouse_capacity_summary/warehouse_capacity_summary.html
+++ b/erpnext/stock/page/warehouse_capacity_summary/warehouse_capacity_summary.html
@@ -37,4 +37,4 @@
{% endif %}
-{% endfor %}
\ No newline at end of file
+{% endfor %}
diff --git a/erpnext/stock/page/warehouse_capacity_summary/warehouse_capacity_summary_header.html b/erpnext/stock/page/warehouse_capacity_summary/warehouse_capacity_summary_header.html
index acaf180a90..7ac5e64030 100644
--- a/erpnext/stock/page/warehouse_capacity_summary/warehouse_capacity_summary_header.html
+++ b/erpnext/stock/page/warehouse_capacity_summary/warehouse_capacity_summary_header.html
@@ -16,4 +16,4 @@
% Occupied
-
\ No newline at end of file
+
diff --git a/erpnext/stock/report/batch_item_expiry_status/batch_item_expiry_status.py b/erpnext/stock/report/batch_item_expiry_status/batch_item_expiry_status.py
index 7354eee413..29689b1a91 100644
--- a/erpnext/stock/report/batch_item_expiry_status/batch_item_expiry_status.py
+++ b/erpnext/stock/report/batch_item_expiry_status/batch_item_expiry_status.py
@@ -24,7 +24,7 @@ def execute(filters=None):
data.append([item, item_map[item]["item_name"], item_map[item]["description"], wh, batch,
frappe.db.get_value('Batch', batch, 'expiry_date'), qty_dict.expiry_status
])
-
+
return columns, data
@@ -70,7 +70,7 @@ def get_item_warehouse_batch_map(filters, float_precision):
"expires_on": None, "expiry_status": None}))
qty_dict = iwb_map[d.item_code][d.warehouse][d.batch_no]
-
+
expiry_date_unicode = frappe.db.get_value('Batch', d.batch_no, 'expiry_date')
qty_dict.expires_on = expiry_date_unicode
diff --git a/erpnext/stock/report/cogs_by_item_group/cogs_by_item_group.py b/erpnext/stock/report/cogs_by_item_group/cogs_by_item_group.py
index 9e5e63e37e..da593a40d6 100644
--- a/erpnext/stock/report/cogs_by_item_group/cogs_by_item_group.py
+++ b/erpnext/stock/report/cogs_by_item_group/cogs_by_item_group.py
@@ -64,7 +64,7 @@ def get_data(filters: Filters) -> Data:
assign_self_values(leveled_dict, svd_list)
assign_agg_values(leveled_dict)
-
+
data = []
for item in leveled_dict.items():
i = item[1]
@@ -160,7 +160,7 @@ def get_row(name:str, value:float, is_bold:int, indent:int) -> Row:
if is_bold:
item_group = frappe.bold(item_group)
return frappe._dict(item_group=item_group, cogs_debit=value, indent=indent)
-
+
def assign_item_groups_to_svd_list(svd_list: SVDList) -> None:
ig_map = get_item_groups_map(svd_list)
diff --git a/erpnext/stock/report/delayed_item_report/delayed_item_report.py b/erpnext/stock/report/delayed_item_report/delayed_item_report.py
index 4fc4027200..61306662c0 100644
--- a/erpnext/stock/report/delayed_item_report/delayed_item_report.py
+++ b/erpnext/stock/report/delayed_item_report/delayed_item_report.py
@@ -174,4 +174,4 @@ class DelayedItemReport(object):
"fieldname": "po_no",
"fieldtype": "Data",
"width": 100
- }]
\ No newline at end of file
+ }]
diff --git a/erpnext/stock/report/delayed_order_report/delayed_order_report.py b/erpnext/stock/report/delayed_order_report/delayed_order_report.py
index 79dc5d8821..d915160688 100644
--- a/erpnext/stock/report/delayed_order_report/delayed_order_report.py
+++ b/erpnext/stock/report/delayed_order_report/delayed_order_report.py
@@ -87,4 +87,4 @@ class DelayedOrderReport(DelayedItemReport):
"fieldname": "po_no",
"fieldtype": "Data",
"width": 110
- }]
\ No newline at end of file
+ }]
diff --git a/erpnext/stock/report/delivery_note_trends/delivery_note_trends.js b/erpnext/stock/report/delivery_note_trends/delivery_note_trends.js
index ade004cde4..8a04565c19 100644
--- a/erpnext/stock/report/delivery_note_trends/delivery_note_trends.js
+++ b/erpnext/stock/report/delivery_note_trends/delivery_note_trends.js
@@ -6,4 +6,3 @@ frappe.require("assets/erpnext/js/sales_trends_filters.js", function() {
filters: erpnext.get_sales_trends_filters()
}
});
-
diff --git a/erpnext/stock/report/delivery_note_trends/delivery_note_trends.py b/erpnext/stock/report/delivery_note_trends/delivery_note_trends.py
index 446d3049b7..77fd2ff244 100644
--- a/erpnext/stock/report/delivery_note_trends/delivery_note_trends.py
+++ b/erpnext/stock/report/delivery_note_trends/delivery_note_trends.py
@@ -47,4 +47,4 @@ def get_chart_data(data, filters):
]
},
"type" : "bar"
- }
\ No newline at end of file
+ }
diff --git a/erpnext/stock/report/incorrect_balance_qty_after_transaction/incorrect_balance_qty_after_transaction.py b/erpnext/stock/report/incorrect_balance_qty_after_transaction/incorrect_balance_qty_after_transaction.py
index cf174c9368..00125e71a9 100644
--- a/erpnext/stock/report/incorrect_balance_qty_after_transaction/incorrect_balance_qty_after_transaction.py
+++ b/erpnext/stock/report/incorrect_balance_qty_after_transaction/incorrect_balance_qty_after_transaction.py
@@ -108,4 +108,4 @@ def get_columns():
'fieldtype': 'Float',
'fieldname': 'differnce',
'width': 110
- }]
\ No newline at end of file
+ }]
diff --git a/erpnext/stock/report/incorrect_serial_no_valuation/incorrect_serial_no_valuation.py b/erpnext/stock/report/incorrect_serial_no_valuation/incorrect_serial_no_valuation.py
index e54cf4c66c..b3b7594ffd 100644
--- a/erpnext/stock/report/incorrect_serial_no_valuation/incorrect_serial_no_valuation.py
+++ b/erpnext/stock/report/incorrect_serial_no_valuation/incorrect_serial_no_valuation.py
@@ -145,4 +145,4 @@ def get_columns():
'fieldtype': 'Currency',
'fieldname': 'valuation_rate',
'width': 110
- }]
\ No newline at end of file
+ }]
diff --git a/erpnext/stock/report/incorrect_stock_value_report/incorrect_stock_value_report.py b/erpnext/stock/report/incorrect_stock_value_report/incorrect_stock_value_report.py
index a7243878eb..c8f60a15d6 100644
--- a/erpnext/stock/report/incorrect_stock_value_report/incorrect_stock_value_report.py
+++ b/erpnext/stock/report/incorrect_stock_value_report/incorrect_stock_value_report.py
@@ -138,4 +138,4 @@ def get_columns(filters):
"fieldtype": "Currency",
"width": "150"
}
- ]
\ No newline at end of file
+ ]
diff --git a/erpnext/stock/report/item_price_stock/item_price_stock.js b/erpnext/stock/report/item_price_stock/item_price_stock.js
index 0bbc61b9db..7af1dab6a0 100644
--- a/erpnext/stock/report/item_price_stock/item_price_stock.js
+++ b/erpnext/stock/report/item_price_stock/item_price_stock.js
@@ -11,4 +11,4 @@ frappe.query_reports["Item Price Stock"] = {
"options": "Item"
}
]
-}
\ No newline at end of file
+}
diff --git a/erpnext/stock/report/item_shortage_report/item_shortage_report.py b/erpnext/stock/report/item_shortage_report/item_shortage_report.py
index 086d833bbc..c67eed7e92 100644
--- a/erpnext/stock/report/item_shortage_report/item_shortage_report.py
+++ b/erpnext/stock/report/item_shortage_report/item_shortage_report.py
@@ -158,5 +158,3 @@ def get_columns():
]
return columns
-
-
diff --git a/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.js b/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.js
index c0535bf0ef..173aad6d5a 100644
--- a/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.js
+++ b/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.js
@@ -29,4 +29,4 @@ frappe.query_reports["Itemwise Recommended Reorder Level"] = {
"options": "Brand"
}
]
-}
\ No newline at end of file
+}
diff --git a/erpnext/stock/report/purchase_receipt_trends/purchase_receipt_trends.js b/erpnext/stock/report/purchase_receipt_trends/purchase_receipt_trends.js
index d16485e8cc..695efacb69 100644
--- a/erpnext/stock/report/purchase_receipt_trends/purchase_receipt_trends.js
+++ b/erpnext/stock/report/purchase_receipt_trends/purchase_receipt_trends.js
@@ -6,4 +6,3 @@ frappe.require("assets/erpnext/js/purchase_trends_filters.js", function() {
filters: erpnext.get_purchase_trends_filters()
}
});
-
diff --git a/erpnext/stock/report/purchase_receipt_trends/purchase_receipt_trends.py b/erpnext/stock/report/purchase_receipt_trends/purchase_receipt_trends.py
index 8227f1548c..0d96ea6aa8 100644
--- a/erpnext/stock/report/purchase_receipt_trends/purchase_receipt_trends.py
+++ b/erpnext/stock/report/purchase_receipt_trends/purchase_receipt_trends.py
@@ -48,4 +48,4 @@ def get_chart_data(data, filters):
},
"type" : "bar",
"colors":["#5e64ff"]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/stock/report/serial_no_ledger/serial_no_ledger.py b/erpnext/stock/report/serial_no_ledger/serial_no_ledger.py
index c3339fd341..cc3aa3522d 100644
--- a/erpnext/stock/report/serial_no_ledger/serial_no_ledger.py
+++ b/erpnext/stock/report/serial_no_ledger/serial_no_ledger.py
@@ -50,4 +50,3 @@ def get_columns(filters):
def get_data(filters):
return get_stock_ledger_entries(filters, '<=', order="asc") or []
-
diff --git a/erpnext/stock/report/stock_ageing/stock_ageing.js b/erpnext/stock/report/stock_ageing/stock_ageing.js
index 8495142ba5..b22788f7a2 100644
--- a/erpnext/stock/report/stock_ageing/stock_ageing.js
+++ b/erpnext/stock/report/stock_ageing/stock_ageing.js
@@ -64,4 +64,4 @@ frappe.query_reports["Stock Ageing"] = {
"default": 0
}
]
-}
\ No newline at end of file
+}
diff --git a/erpnext/stock/report/stock_analytics/stock_analytics.py b/erpnext/stock/report/stock_analytics/stock_analytics.py
index fde934b133..d62abed91f 100644
--- a/erpnext/stock/report/stock_analytics/stock_analytics.py
+++ b/erpnext/stock/report/stock_analytics/stock_analytics.py
@@ -208,7 +208,3 @@ def get_chart_data(columns):
chart["type"] = "line"
return chart
-
-
-
-
diff --git a/erpnext/stock/report/stock_and_account_value_comparison/stock_and_account_value_comparison.py b/erpnext/stock/report/stock_and_account_value_comparison/stock_and_account_value_comparison.py
index bfc4471b9a..7e0c0e8ab3 100644
--- a/erpnext/stock/report/stock_and_account_value_comparison/stock_and_account_value_comparison.py
+++ b/erpnext/stock/report/stock_and_account_value_comparison/stock_and_account_value_comparison.py
@@ -128,4 +128,4 @@ def get_columns(filters):
"fieldtype": "Currency",
"width": "120"
}
- ]
\ No newline at end of file
+ ]
diff --git a/erpnext/stock/report/stock_projected_qty/stock_projected_qty.py b/erpnext/stock/report/stock_projected_qty/stock_projected_qty.py
index 808d279170..7956f2e864 100644
--- a/erpnext/stock/report/stock_projected_qty/stock_projected_qty.py
+++ b/erpnext/stock/report/stock_projected_qty/stock_projected_qty.py
@@ -32,7 +32,7 @@ def execute(filters=None):
if filters.brand and filters.brand != item.brand:
continue
-
+
elif filters.item_group and filters.item_group != item.item_group:
continue
diff --git a/erpnext/stock/report/stock_qty_vs_serial_no_count/stock_qty_vs_serial_no_count.py b/erpnext/stock/report/stock_qty_vs_serial_no_count/stock_qty_vs_serial_no_count.py
index 78e95df989..fa19eeba58 100644
--- a/erpnext/stock/report/stock_qty_vs_serial_no_count/stock_qty_vs_serial_no_count.py
+++ b/erpnext/stock/report/stock_qty_vs_serial_no_count/stock_qty_vs_serial_no_count.py
@@ -58,14 +58,14 @@ def get_data(warehouse):
serial_item_list = frappe.get_all("Item", filters={
'has_serial_no': True,
}, fields=['item_code', 'item_name'])
-
+
status_list = ['Active', 'Expired']
data = []
for item in serial_item_list:
- total_serial_no = frappe.db.count("Serial No",
+ total_serial_no = frappe.db.count("Serial No",
filters={"item_code": item.item_code, "status": ("in", status_list), "warehouse": warehouse})
- actual_qty = frappe.db.get_value('Bin', fieldname=['actual_qty'],
+ actual_qty = frappe.db.get_value('Bin', fieldname=['actual_qty'],
filters={"warehouse": warehouse, "item_code": item.item_code})
# frappe.db.get_value returns null if no record exist.
@@ -84,4 +84,4 @@ def get_data(warehouse):
data.append(row)
- return data
\ No newline at end of file
+ return data
diff --git a/erpnext/stock/report/supplier_wise_sales_analytics/supplier_wise_sales_analytics.js b/erpnext/stock/report/supplier_wise_sales_analytics/supplier_wise_sales_analytics.js
index cdc9895917..5b00647075 100644
--- a/erpnext/stock/report/supplier_wise_sales_analytics/supplier_wise_sales_analytics.js
+++ b/erpnext/stock/report/supplier_wise_sales_analytics/supplier_wise_sales_analytics.js
@@ -25,4 +25,4 @@ frappe.query_reports["Supplier-Wise Sales Analytics"] = {
"default": frappe.datetime.month_end()
},
]
-}
\ No newline at end of file
+}
diff --git a/erpnext/stock/report/total_stock_summary/total_stock_summary.js b/erpnext/stock/report/total_stock_summary/total_stock_summary.js
index 264642856d..90648f1b24 100644
--- a/erpnext/stock/report/total_stock_summary/total_stock_summary.js
+++ b/erpnext/stock/report/total_stock_summary/total_stock_summary.js
@@ -38,4 +38,4 @@ frappe.query_reports["Total Stock Summary"] = {
"reqd": 1
},
]
-}
\ No newline at end of file
+}
diff --git a/erpnext/support/doctype/issue/issue.js b/erpnext/support/doctype/issue/issue.js
index 9ac1efa268..d4daacd4ea 100644
--- a/erpnext/support/doctype/issue/issue.js
+++ b/erpnext/support/doctype/issue/issue.js
@@ -145,4 +145,4 @@ frappe.ui.form.on("Issue", {
// frm.timeline.wrapper.data("help-article-event-attached", true);
// }
},
-});
\ No newline at end of file
+});
diff --git a/erpnext/support/doctype/issue/test_issue.py b/erpnext/support/doctype/issue/test_issue.py
index 739324f562..4146e48862 100644
--- a/erpnext/support/doctype/issue/test_issue.py
+++ b/erpnext/support/doctype/issue/test_issue.py
@@ -182,7 +182,7 @@ class TestFirstResponseTime(TestSetUp):
# issue creation and first response are on consecutive days
def test_first_response_time_case6(self):
"""
- Test frt when the issue was created before working hours and the first response is also sent before working hours, but on the next day.
+ Test frt when the issue was created before working hours and the first response is also sent before working hours, but on the next day.
"""
issue = create_issue_and_communication(get_datetime("06-28-2021 6:00"), get_datetime("06-29-2021 6:00"))
self.assertEqual(issue.first_response_time, 28800.0)
@@ -204,7 +204,7 @@ class TestFirstResponseTime(TestSetUp):
def test_first_response_time_case9(self):
"""
Test frt when the issue was created before working hours and the first response is sent on the next day, which is not a work day.
- """
+ """
issue = create_issue_and_communication(get_datetime("06-25-2021 6:00"), get_datetime("06-26-2021 11:00"))
self.assertEqual(issue.first_response_time, 28800.0)
@@ -232,7 +232,7 @@ class TestFirstResponseTime(TestSetUp):
def test_first_response_time_case13(self):
"""
Test frt when the issue was created during working hours and the first response is sent on the next day, which is not a work day.
- """
+ """
issue = create_issue_and_communication(get_datetime("06-25-2021 12:00"), get_datetime("06-26-2021 11:00"))
self.assertEqual(issue.first_response_time, 21600.0)
@@ -348,7 +348,7 @@ class TestFirstResponseTime(TestSetUp):
"""
issue = create_issue_and_communication(get_datetime("06-25-2021 20:00"), get_datetime("06-27-2021 11:00"))
self.assertEqual(issue.first_response_time, 1.0)
-
+
def create_issue_and_communication(issue_creation, first_responded_on):
issue = make_issue(issue_creation, index=1)
sender = create_user("test@admin.com")
@@ -422,4 +422,4 @@ def create_communication(reference_name, sender, sent_or_received, creation):
"creation": creation,
"reference_name": reference_name
})
- communication.save()
\ No newline at end of file
+ communication.save()
diff --git a/erpnext/support/doctype/issue_priority/issue_priority.py b/erpnext/support/doctype/issue_priority/issue_priority.py
index 7c8925ebc3..514b6cc26b 100644
--- a/erpnext/support/doctype/issue_priority/issue_priority.py
+++ b/erpnext/support/doctype/issue_priority/issue_priority.py
@@ -8,4 +8,4 @@ from frappe import _
from frappe.model.document import Document
class IssuePriority(Document):
- pass
\ No newline at end of file
+ pass
diff --git a/erpnext/support/doctype/issue_priority/test_issue_priority.py b/erpnext/support/doctype/issue_priority/test_issue_priority.py
index a7b55f8a74..618c93ea9d 100644
--- a/erpnext/support/doctype/issue_priority/test_issue_priority.py
+++ b/erpnext/support/doctype/issue_priority/test_issue_priority.py
@@ -25,4 +25,4 @@ def insert_priority(name):
frappe.get_doc({
"doctype": "Issue Priority",
"name": name
- }).insert(ignore_permissions=True)
\ No newline at end of file
+ }).insert(ignore_permissions=True)
diff --git a/erpnext/support/doctype/service_level_agreement/service_level_agreement.py b/erpnext/support/doctype/service_level_agreement/service_level_agreement.py
index 472e96c059..8c1c1ef0de 100644
--- a/erpnext/support/doctype/service_level_agreement/service_level_agreement.py
+++ b/erpnext/support/doctype/service_level_agreement/service_level_agreement.py
@@ -246,7 +246,7 @@ def get_active_service_level_agreement_for(doc):
filters += [["Service Level Agreement", "default_service_level_agreement", "=", 0]]
agreements = frappe.get_all("Service Level Agreement", filters=filters, or_filters=or_filters,
fields=["name", "default_priority", "apply_sla_for_resolution", "condition"])
-
+
# check if the current document on which SLA is to be applied fulfills all the conditions
filtered_agreements = []
for agreement in agreements:
diff --git a/erpnext/support/doctype/service_level_agreement/service_level_agreement_dashboard.py b/erpnext/support/doctype/service_level_agreement/service_level_agreement_dashboard.py
index f2bd681396..7e7a405d6e 100644
--- a/erpnext/support/doctype/service_level_agreement/service_level_agreement_dashboard.py
+++ b/erpnext/support/doctype/service_level_agreement/service_level_agreement_dashboard.py
@@ -9,4 +9,4 @@ def get_data():
'items': ['Issue']
}
]
- }
\ No newline at end of file
+ }
diff --git a/erpnext/support/doctype/service_level_agreement/test_service_level_agreement.py b/erpnext/support/doctype/service_level_agreement/test_service_level_agreement.py
index 1a5ff27d2a..a81516ec11 100644
--- a/erpnext/support/doctype/service_level_agreement/test_service_level_agreement.py
+++ b/erpnext/support/doctype/service_level_agreement/test_service_level_agreement.py
@@ -511,4 +511,4 @@ def make_lead(creation=None, index=0):
"creation": creation,
"service_level_agreement_creation": creation,
"priority": "Medium"
- }).insert(ignore_permissions=True)
\ No newline at end of file
+ }).insert(ignore_permissions=True)
diff --git a/erpnext/support/report/first_response_time_for_issues/first_response_time_for_issues.py b/erpnext/support/report/first_response_time_for_issues/first_response_time_for_issues.py
index 922da2b33d..69bf2730d3 100644
--- a/erpnext/support/report/first_response_time_for_issues/first_response_time_for_issues.py
+++ b/erpnext/support/report/first_response_time_for_issues/first_response_time_for_issues.py
@@ -32,4 +32,4 @@ def execute(filters=None):
ORDER BY creation_date desc
''', (filters.from_date, filters.to_date))
- return columns, data
\ No newline at end of file
+ return columns, data
diff --git a/erpnext/support/report/issue_analytics/issue_analytics.py b/erpnext/support/report/issue_analytics/issue_analytics.py
index 3fdb10ddf3..54fce0b359 100644
--- a/erpnext/support/report/issue_analytics/issue_analytics.py
+++ b/erpnext/support/report/issue_analytics/issue_analytics.py
@@ -218,4 +218,4 @@ class IssueAnalytics(object):
'datasets': []
},
'type': 'line'
- }
\ No newline at end of file
+ }
diff --git a/erpnext/support/report/issue_analytics/test_issue_analytics.py b/erpnext/support/report/issue_analytics/test_issue_analytics.py
index 77483198ec..a9d961a459 100644
--- a/erpnext/support/report/issue_analytics/test_issue_analytics.py
+++ b/erpnext/support/report/issue_analytics/test_issue_analytics.py
@@ -22,7 +22,7 @@ class TestIssueAnalytics(unittest.TestCase):
if current_month_date.year != last_month_date.year:
self.current_month += '_' + str(current_month_date.year)
self.last_month += '_' + str(last_month_date.year)
-
+
def test_issue_analytics(self):
create_service_level_agreements_for_issues()
create_issue_types()
@@ -211,4 +211,4 @@ def create_records():
"assign_to": ["test@example.com", "test1@example.com"],
"doctype": "Issue",
"name": issue.name
- })
\ No newline at end of file
+ })
diff --git a/erpnext/support/report/issue_summary/issue_summary.py b/erpnext/support/report/issue_summary/issue_summary.py
index bba25b8bed..7c4af39f10 100644
--- a/erpnext/support/report/issue_summary/issue_summary.py
+++ b/erpnext/support/report/issue_summary/issue_summary.py
@@ -362,4 +362,3 @@ class IssueSummary(object):
'datatype': 'Int',
}
]
-
diff --git a/erpnext/support/web_form/issues/issues.js b/erpnext/support/web_form/issues/issues.js
index 699703c579..ffc5e98425 100644
--- a/erpnext/support/web_form/issues/issues.js
+++ b/erpnext/support/web_form/issues/issues.js
@@ -1,3 +1,3 @@
frappe.ready(function() {
// bind events here
-})
\ No newline at end of file
+})
diff --git a/erpnext/telephony/doctype/call_log/call_log.py b/erpnext/telephony/doctype/call_log/call_log.py
index c00dfa9056..6f8e411695 100644
--- a/erpnext/telephony/doctype/call_log/call_log.py
+++ b/erpnext/telephony/doctype/call_log/call_log.py
@@ -173,4 +173,3 @@ def get_linked_call_logs(doctype, docname):
})
return timeline_contents
-
diff --git a/erpnext/telephony/doctype/incoming_call_settings/incoming_call_settings.js b/erpnext/telephony/doctype/incoming_call_settings/incoming_call_settings.js
index 1bcc846132..b80acdb376 100644
--- a/erpnext/telephony/doctype/incoming_call_settings/incoming_call_settings.js
+++ b/erpnext/telephony/doctype/incoming_call_settings/incoming_call_settings.js
@@ -99,4 +99,3 @@ frappe.ui.form.on('Incoming Call Settings', {
validate_call_schedule(frm.doc.call_handling_schedule);
}
});
-
diff --git a/erpnext/templates/emails/birthday_reminder.html b/erpnext/templates/emails/birthday_reminder.html
index 12cdf1ec60..1f57b4969c 100644
--- a/erpnext/templates/emails/birthday_reminder.html
+++ b/erpnext/templates/emails/birthday_reminder.html
@@ -22,4 +22,4 @@
{{ reminder_text }}
{{ message }}
-
\ No newline at end of file
+
diff --git a/erpnext/templates/emails/daily_project_summary.html b/erpnext/templates/emails/daily_project_summary.html
index 8b60830db6..5ccc610166 100644
--- a/erpnext/templates/emails/daily_project_summary.html
+++ b/erpnext/templates/emails/daily_project_summary.html
@@ -43,4 +43,4 @@
-{% endfor %}
\ No newline at end of file
+{% endfor %}
diff --git a/erpnext/templates/emails/daily_work_summary.html b/erpnext/templates/emails/daily_work_summary.html
index a22e09cb8d..1764e8f703 100644
--- a/erpnext/templates/emails/daily_work_summary.html
+++ b/erpnext/templates/emails/daily_work_summary.html
@@ -52,4 +52,4 @@
-{% endif %}
\ No newline at end of file
+{% endif %}
diff --git a/erpnext/templates/emails/request_for_quotation.html b/erpnext/templates/emails/request_for_quotation.html
index 812939a553..3283987fab 100644
--- a/erpnext/templates/emails/request_for_quotation.html
+++ b/erpnext/templates/emails/request_for_quotation.html
@@ -21,4 +21,4 @@
-{% endif %}
\ No newline at end of file
+{% endif %}
diff --git a/erpnext/templates/emails/training_event.html b/erpnext/templates/emails/training_event.html
index 51c232d8e8..8a2414a3c9 100644
--- a/erpnext/templates/emails/training_event.html
+++ b/erpnext/templates/emails/training_event.html
@@ -11,7 +11,7 @@
{{_("Update Response")}}
{% if not self_study %}
{{_("Please update your status for this training event")}}:
-
+
{% else %}
{{_("Please confirm once you have completed your training")}}:
diff --git a/erpnext/templates/generators/item/item_inquiry.js b/erpnext/templates/generators/item/item_inquiry.js
index e7db3a368d..4724b68119 100644
--- a/erpnext/templates/generators/item/item_inquiry.js
+++ b/erpnext/templates/generators/item/item_inquiry.js
@@ -74,4 +74,4 @@ frappe.ready(() => {
d.show();
});
-});
\ No newline at end of file
+});
diff --git a/erpnext/templates/generators/item/item_specifications.html b/erpnext/templates/generators/item/item_specifications.html
index 469a45fd7d..d4dfa8e591 100644
--- a/erpnext/templates/generators/item/item_specifications.html
+++ b/erpnext/templates/generators/item/item_specifications.html
@@ -11,4 +11,4 @@
-{%- endif %}
\ No newline at end of file
+{%- endif %}
diff --git a/erpnext/templates/generators/item_group.html b/erpnext/templates/generators/item_group.html
index 9050cc388a..b5f18ba66d 100644
--- a/erpnext/templates/generators/item_group.html
+++ b/erpnext/templates/generators/item_group.html
@@ -159,4 +159,4 @@
});
});
-{% endblock %}
\ No newline at end of file
+{% endblock %}
diff --git a/erpnext/templates/generators/job_opening.html b/erpnext/templates/generators/job_opening.html
index c562db3c25..135fb3643d 100644
--- a/erpnext/templates/generators/job_opening.html
+++ b/erpnext/templates/generators/job_opening.html
@@ -14,17 +14,17 @@
{{ description }}
{% endif %}
-{%- if publish_salary_range -%}
+{%- if publish_salary_range -%}
{{_("Salary range per month")}}: {{ frappe.format_value(frappe.utils.flt(lower_range), currency=currency) }} - {{ frappe.format_value(frappe.utils.flt(upper_range), currency=currency) }}
{% endif %}
{%- if job_application_route -%}
-
{{ _("Apply Now") }}
{% else %}
-
{{ _("Apply Now") }}
{% endif %}
diff --git a/erpnext/templates/generators/student_admission.html b/erpnext/templates/generators/student_admission.html
index 8b153448ee..8cc58a0a1f 100644
--- a/erpnext/templates/generators/student_admission.html
+++ b/erpnext/templates/generators/student_admission.html
@@ -14,7 +14,7 @@
{%- if introduction -%}
{{ introduction }}
-{% endif %}
+{% endif %}
{%- if doc.enable_admission_application -%}
diff --git a/erpnext/templates/includes/cart/address_picker_card.html b/erpnext/templates/includes/cart/address_picker_card.html
index 2334ea2955..646210e65f 100644
--- a/erpnext/templates/includes/cart/address_picker_card.html
+++ b/erpnext/templates/includes/cart/address_picker_card.html
@@ -9,4 +9,4 @@
{{ _('Edit') }}
-
\ No newline at end of file
+
diff --git a/erpnext/templates/includes/cart/cart_address_picker.html b/erpnext/templates/includes/cart/cart_address_picker.html
index 72cc5f5142..66a50ecc9f 100644
--- a/erpnext/templates/includes/cart/cart_address_picker.html
+++ b/erpnext/templates/includes/cart/cart_address_picker.html
@@ -1,4 +1,3 @@
{{ _("Shipping Address") }}
-
diff --git a/erpnext/templates/includes/cart/cart_items_dropdown.html b/erpnext/templates/includes/cart/cart_items_dropdown.html
index b2ba4312d6..5d107fc0d0 100644
--- a/erpnext/templates/includes/cart/cart_items_dropdown.html
+++ b/erpnext/templates/includes/cart/cart_items_dropdown.html
@@ -9,4 +9,4 @@
{{ d.get_formatted("amount") }}
-{% endfor %}
\ No newline at end of file
+{% endfor %}
diff --git a/erpnext/templates/includes/course/macros.html b/erpnext/templates/includes/course/macros.html
index c80dca4bcc..334b5ea200 100644
--- a/erpnext/templates/includes/course/macros.html
+++ b/erpnext/templates/includes/course/macros.html
@@ -1 +1 @@
-{% macro back_link(doc) %}&back-to=/courses?course={{ doc.name }}&back-to-title={{ doc.course_name }}{% endmacro %}
\ No newline at end of file
+{% macro back_link(doc) %}&back-to=/courses?course={{ doc.name }}&back-to-title={{ doc.course_name }}{% endmacro %}
diff --git a/erpnext/templates/includes/itemised_tax_breakup.html b/erpnext/templates/includes/itemised_tax_breakup.html
index c2f13539cd..5652bb1ddd 100644
--- a/erpnext/templates/includes/itemised_tax_breakup.html
+++ b/erpnext/templates/includes/itemised_tax_breakup.html
@@ -43,4 +43,4 @@
{% endfor %}
-
\ No newline at end of file
+
diff --git a/erpnext/templates/includes/macros.html b/erpnext/templates/includes/macros.html
index c44bfb5384..be0d47f371 100644
--- a/erpnext/templates/includes/macros.html
+++ b/erpnext/templates/includes/macros.html
@@ -120,4 +120,4 @@
{% endif %}
-{%- endmacro -%}
\ No newline at end of file
+{%- endmacro -%}
diff --git a/erpnext/templates/includes/navbar/navbar_items.html b/erpnext/templates/includes/navbar/navbar_items.html
index 133d99e5eb..291220629c 100644
--- a/erpnext/templates/includes/navbar/navbar_items.html
+++ b/erpnext/templates/includes/navbar/navbar_items.html
@@ -9,4 +9,4 @@
-{% endblock %}
\ No newline at end of file
+{% endblock %}
diff --git a/erpnext/templates/includes/order/order_macros.html b/erpnext/templates/includes/order/order_macros.html
index da4fb8c046..7b3c9a4131 100644
--- a/erpnext/templates/includes/order/order_macros.html
+++ b/erpnext/templates/includes/order/order_macros.html
@@ -40,4 +40,4 @@
-{% endmacro %}
\ No newline at end of file
+{% endmacro %}
diff --git a/erpnext/templates/includes/projects.css b/erpnext/templates/includes/projects.css
index 5a717fc669..5d9fc50385 100644
--- a/erpnext/templates/includes/projects.css
+++ b/erpnext/templates/includes/projects.css
@@ -86,4 +86,4 @@
.progress-hg{
margin-bottom: 30!important;
height:2px;
-}
\ No newline at end of file
+}
diff --git a/erpnext/templates/includes/projects/project_search_box.html b/erpnext/templates/includes/projects/project_search_box.html
index 6f53bae2e8..d7466873dd 100644
--- a/erpnext/templates/includes/projects/project_search_box.html
+++ b/erpnext/templates/includes/projects/project_search_box.html
@@ -27,4 +27,4 @@ frappe.ready(function() {
});
$(".form-search").on("submit", function() { return false; });
});
-
\ No newline at end of file
+
diff --git a/erpnext/templates/includes/salary_slip_log.html b/erpnext/templates/includes/salary_slip_log.html
index 107df51dd8..d36ee6e23b 100644
--- a/erpnext/templates/includes/salary_slip_log.html
+++ b/erpnext/templates/includes/salary_slip_log.html
@@ -16,4 +16,4 @@
{% endfor %}
-
\ No newline at end of file
+
diff --git a/erpnext/templates/includes/topic/topic_row.html b/erpnext/templates/includes/topic/topic_row.html
index 3401bd3937..38d46b7fe0 100644
--- a/erpnext/templates/includes/topic/topic_row.html
+++ b/erpnext/templates/includes/topic/topic_row.html
@@ -1,4 +1,4 @@
-
+
\ No newline at end of file
+
diff --git a/erpnext/templates/pages/cart_terms.html b/erpnext/templates/pages/cart_terms.html
index 521c583cb6..6d84fb86a7 100644
--- a/erpnext/templates/pages/cart_terms.html
+++ b/erpnext/templates/pages/cart_terms.html
@@ -1,2 +1,2 @@
-{{doc.terms}}
\ No newline at end of file
+{{doc.terms}}
diff --git a/erpnext/templates/pages/courses.html b/erpnext/templates/pages/courses.html
index 42e7f3e70b..6592f7a2e5 100644
--- a/erpnext/templates/pages/courses.html
+++ b/erpnext/templates/pages/courses.html
@@ -8,4 +8,4 @@
{{ intro }}
-{% endblock %}
\ No newline at end of file
+{% endblock %}
diff --git a/erpnext/templates/pages/courses.py b/erpnext/templates/pages/courses.py
index c80d8e7d22..92c38f6fca 100644
--- a/erpnext/templates/pages/courses.py
+++ b/erpnext/templates/pages/courses.py
@@ -17,4 +17,3 @@ def get_context(context):
context.doc = course
context.sidebar_title = sidebar_title
context.intro = course.course_intro
-
diff --git a/erpnext/templates/pages/home.css b/erpnext/templates/pages/home.css
index cf5476635b..785d8059ba 100644
--- a/erpnext/templates/pages/home.css
+++ b/erpnext/templates/pages/home.css
@@ -6,4 +6,4 @@
padding: 10rem 0;
}
{% endif %}
-/* csslint ignore:end */
\ No newline at end of file
+/* csslint ignore:end */
diff --git a/erpnext/templates/pages/home.html b/erpnext/templates/pages/home.html
index 2ef9c10534..9a61eabaf8 100644
--- a/erpnext/templates/pages/home.html
+++ b/erpnext/templates/pages/home.html
@@ -72,4 +72,4 @@
{{ render_homepage_section(section) }}
{% endfor %}
-{% endblock %}
\ No newline at end of file
+{% endblock %}
diff --git a/erpnext/templates/pages/integrations/gocardless_checkout.html b/erpnext/templates/pages/integrations/gocardless_checkout.html
index 7193d755a1..6072db49ea 100644
--- a/erpnext/templates/pages/integrations/gocardless_checkout.html
+++ b/erpnext/templates/pages/integrations/gocardless_checkout.html
@@ -13,4 +13,4 @@
{{ _("Loading Payment System") }}
-{% endblock %}
\ No newline at end of file
+{% endblock %}
diff --git a/erpnext/templates/pages/integrations/gocardless_checkout.py b/erpnext/templates/pages/integrations/gocardless_checkout.py
index 96a0f42a05..bdef79cfbe 100644
--- a/erpnext/templates/pages/integrations/gocardless_checkout.py
+++ b/erpnext/templates/pages/integrations/gocardless_checkout.py
@@ -74,4 +74,4 @@ def check_mandate(data, reference_doctype, reference_docname):
except Exception as e:
frappe.log_error(e, "GoCardless Payment Error")
- return {"redirect_to": '/integrations/payment-failed'}
\ No newline at end of file
+ return {"redirect_to": '/integrations/payment-failed'}
diff --git a/erpnext/templates/pages/integrations/gocardless_confirmation.html b/erpnext/templates/pages/integrations/gocardless_confirmation.html
index 6ba154a06c..d961c6344a 100644
--- a/erpnext/templates/pages/integrations/gocardless_confirmation.html
+++ b/erpnext/templates/pages/integrations/gocardless_confirmation.html
@@ -13,4 +13,4 @@
{{ _("Payment Confirmation") }}
-{% endblock %}
\ No newline at end of file
+{% endblock %}
diff --git a/erpnext/templates/pages/integrations/gocardless_confirmation.py b/erpnext/templates/pages/integrations/gocardless_confirmation.py
index cfaa1a15cf..0b72e9f8b6 100644
--- a/erpnext/templates/pages/integrations/gocardless_confirmation.py
+++ b/erpnext/templates/pages/integrations/gocardless_confirmation.py
@@ -86,4 +86,4 @@ def create_mandate(data):
}).insert(ignore_permissions=True)
except Exception:
- frappe.log_error(frappe.get_traceback())
\ No newline at end of file
+ frappe.log_error(frappe.get_traceback())
diff --git a/erpnext/templates/pages/material_request_info.html b/erpnext/templates/pages/material_request_info.html
index 0c2772e4d8..151d029ee4 100644
--- a/erpnext/templates/pages/material_request_info.html
+++ b/erpnext/templates/pages/material_request_info.html
@@ -71,4 +71,4 @@
{% endfor %}
-{% endblock %}
\ No newline at end of file
+{% endblock %}
diff --git a/erpnext/templates/pages/material_request_info.py b/erpnext/templates/pages/material_request_info.py
index 28e541a5d9..e29860ddd6 100644
--- a/erpnext/templates/pages/material_request_info.py
+++ b/erpnext/templates/pages/material_request_info.py
@@ -19,7 +19,7 @@ def get_context(context):
if not frappe.has_website_permission(context.doc):
frappe.throw(_("Not Permitted"), frappe.PermissionError)
-
+
default_print_format = frappe.db.get_value('Property Setter', dict(property='default_print_format', doc_type=frappe.form_dict.doctype), "value")
if default_print_format:
context.print_format = default_print_format
@@ -45,5 +45,5 @@ def get_more_items_info(items, material_request):
item.delivered_qty = flt(frappe.db.sql("""select sum(transfer_qty)
from `tabStock Entry Detail` where material_request = %s
and item_code = %s and docstatus = 1""",
- (material_request, item.item_code))[0][0])
- return items
\ No newline at end of file
+ (material_request, item.item_code))[0][0])
+ return items
diff --git a/erpnext/templates/pages/non_profit/join-chapter.html b/erpnext/templates/pages/non_profit/join-chapter.html
index 89a7d2aace..4923efc4e8 100644
--- a/erpnext/templates/pages/non_profit/join-chapter.html
+++ b/erpnext/templates/pages/non_profit/join-chapter.html
@@ -56,4 +56,4 @@
{% endif %}
-{% endblock %}
\ No newline at end of file
+{% endblock %}
diff --git a/erpnext/templates/pages/non_profit/leave-chapter.html b/erpnext/templates/pages/non_profit/leave-chapter.html
index bc4242f919..fd7658b3b1 100644
--- a/erpnext/templates/pages/non_profit/leave-chapter.html
+++ b/erpnext/templates/pages/non_profit/leave-chapter.html
@@ -39,4 +39,4 @@
});
})
-{% endblock %}
\ No newline at end of file
+{% endblock %}
diff --git a/erpnext/templates/pages/order.py b/erpnext/templates/pages/order.py
index 34985d94ea..816a25963f 100644
--- a/erpnext/templates/pages/order.py
+++ b/erpnext/templates/pages/order.py
@@ -32,9 +32,9 @@ def get_context(context):
if not frappe.has_website_permission(context.doc):
frappe.throw(_("Not Permitted"), frappe.PermissionError)
-
+
# check for the loyalty program of the customer
- customer_loyalty_program = frappe.db.get_value("Customer", context.doc.customer, "loyalty_program")
+ customer_loyalty_program = frappe.db.get_value("Customer", context.doc.customer, "loyalty_program")
if customer_loyalty_program:
from erpnext.accounts.doctype.loyalty_program.loyalty_program import get_loyalty_program_details_with_points
loyalty_program_details = get_loyalty_program_details_with_points(context.doc.customer, customer_loyalty_program)
diff --git a/erpnext/templates/pages/product_search.py b/erpnext/templates/pages/product_search.py
index d0d72f073a..9ab76deff7 100644
--- a/erpnext/templates/pages/product_search.py
+++ b/erpnext/templates/pages/product_search.py
@@ -47,4 +47,3 @@ def get_product_list(search=None, start=0, limit=12):
set_product_info_for_website(item)
return [get_item_for_list_in_html(r) for r in data]
-
diff --git a/erpnext/templates/pages/projects.js b/erpnext/templates/pages/projects.js
index 262167fc0b..bd6bcea7ca 100644
--- a/erpnext/templates/pages/projects.js
+++ b/erpnext/templates/pages/projects.js
@@ -117,4 +117,4 @@ frappe.ready(function() {
})
return false;
}
-});
\ No newline at end of file
+});
diff --git a/erpnext/templates/pages/task_info.html b/erpnext/templates/pages/task_info.html
index 6cd6a7e51a..fe4d304a39 100644
--- a/erpnext/templates/pages/task_info.html
+++ b/erpnext/templates/pages/task_info.html
@@ -147,4 +147,4 @@
});
-{% endblock %}
\ No newline at end of file
+{% endblock %}
diff --git a/erpnext/templates/pages/task_info.py b/erpnext/templates/pages/task_info.py
index b832b88048..260e2788cd 100644
--- a/erpnext/templates/pages/task_info.py
+++ b/erpnext/templates/pages/task_info.py
@@ -7,8 +7,8 @@ def get_context(context):
context.no_cache = 1
task = frappe.get_doc('Task', frappe.form_dict.task)
-
+
context.comments = frappe.get_all('Communication', filters={'reference_name': task.name, 'comment_type': 'comment'},
fields=['subject', 'sender_full_name', 'communication_date'])
-
- context.doc = task
\ No newline at end of file
+
+ context.doc = task
diff --git a/erpnext/templates/pages/timelog_info.html b/erpnext/templates/pages/timelog_info.html
index 22ea3e45d3..be13826444 100644
--- a/erpnext/templates/pages/timelog_info.html
+++ b/erpnext/templates/pages/timelog_info.html
@@ -45,4 +45,4 @@
-{% endblock %}
\ No newline at end of file
+{% endblock %}
diff --git a/erpnext/templates/pages/timelog_info.py b/erpnext/templates/pages/timelog_info.py
index 7a3361c2ef..ee86483fa2 100644
--- a/erpnext/templates/pages/timelog_info.py
+++ b/erpnext/templates/pages/timelog_info.py
@@ -7,5 +7,5 @@ def get_context(context):
context.no_cache = 1
timelog = frappe.get_doc('Time Log', frappe.form_dict.timelog)
-
- context.doc = timelog
\ No newline at end of file
+
+ context.doc = timelog
diff --git a/erpnext/templates/print_formats/includes/item_table_qty.html b/erpnext/templates/print_formats/includes/item_table_qty.html
index 8e68f1cc63..aaa949192c 100644
--- a/erpnext/templates/print_formats/includes/item_table_qty.html
+++ b/erpnext/templates/print_formats/includes/item_table_qty.html
@@ -12,4 +12,3 @@
{%- endif %}
{{ doc.get_formatted("qty", doc) }}
{%- endif %}
-
diff --git a/erpnext/tests/test_regional.py b/erpnext/tests/test_regional.py
index 282fc6454b..5b3f45a1af 100644
--- a/erpnext/tests/test_regional.py
+++ b/erpnext/tests/test_regional.py
@@ -14,4 +14,4 @@ class TestInit(unittest.TestCase):
self.assertEqual(test_method(), 'original')
frappe.flags.country = 'France'
- self.assertEqual(test_method(), 'overridden')
\ No newline at end of file
+ self.assertEqual(test_method(), 'overridden')
diff --git a/erpnext/tests/test_subcontracting.py b/erpnext/tests/test_subcontracting.py
index 8b0ce0957d..f55137bc9c 100644
--- a/erpnext/tests/test_subcontracting.py
+++ b/erpnext/tests/test_subcontracting.py
@@ -874,4 +874,4 @@ def make_bom_for_subcontracted_items():
def set_backflush_based_on(based_on):
frappe.db.set_value('Buying Settings', None,
- 'backflush_raw_materials_of_subcontract_based_on', based_on)
\ No newline at end of file
+ 'backflush_raw_materials_of_subcontract_based_on', based_on)
diff --git a/erpnext/tests/ui/setup_wizard.js b/erpnext/tests/ui/setup_wizard.js
index aeb8d2a116..ccff785ec9 100644
--- a/erpnext/tests/ui/setup_wizard.js
+++ b/erpnext/tests/ui/setup_wizard.js
@@ -44,4 +44,4 @@ module.exports = {
after: browser => {
browser.end();
},
-};
\ No newline at end of file
+};
diff --git a/erpnext/tests/ui_test_helpers.py b/erpnext/tests/ui_test_helpers.py
index fc3aa29824..902fd64d68 100644
--- a/erpnext/tests/ui_test_helpers.py
+++ b/erpnext/tests/ui_test_helpers.py
@@ -56,4 +56,4 @@ def create_missing_designation():
frappe.get_doc({
'doctype': 'Designation',
'designation_name': 'CTO'
- }).insert()
\ No newline at end of file
+ }).insert()
diff --git a/erpnext/utilities/activation.py b/erpnext/utilities/activation.py
index 50c4b255ce..0f9f2f886d 100644
--- a/erpnext/utilities/activation.py
+++ b/erpnext/utilities/activation.py
@@ -13,33 +13,33 @@ def get_level():
min_count = 0
doctypes = {
"Asset": 5,
- "BOM": 3,
- "Customer": 5,
+ "BOM": 3,
+ "Customer": 5,
"Delivery Note": 5,
- "Employee": 3,
- "Instructor": 5,
+ "Employee": 3,
+ "Instructor": 5,
"Issue": 5,
- "Item": 5,
- "Journal Entry": 3,
+ "Item": 5,
+ "Journal Entry": 3,
"Lead": 3,
"Leave Application": 5,
"Material Request": 5,
- "Opportunity": 5,
- "Payment Entry": 2,
+ "Opportunity": 5,
+ "Payment Entry": 2,
"Project": 5,
- "Purchase Order": 2,
+ "Purchase Order": 2,
"Purchase Invoice": 5,
"Purchase Receipt": 5,
"Quotation": 3,
"Salary Slip": 5,
"Salary Structure": 5,
- "Sales Order": 2,
- "Sales Invoice": 2,
+ "Sales Order": 2,
+ "Sales Invoice": 2,
"Stock Entry": 3,
- "Student": 5,
+ "Student": 5,
"Supplier": 5,
"Task": 5,
- "User": 5,
+ "User": 5,
"Work Order": 5
}
diff --git a/erpnext/utilities/bot.py b/erpnext/utilities/bot.py
index b2e74da921..485b0b3383 100644
--- a/erpnext/utilities/bot.py
+++ b/erpnext/utilities/bot.py
@@ -36,4 +36,4 @@ class FindItemBot(BotParser):
return "\n\n".join(out)
else:
- return _("Did not find any item called {0}").format(item)
\ No newline at end of file
+ return _("Did not find any item called {0}").format(item)
diff --git a/erpnext/utilities/doctype/rename_tool/rename_tool.py b/erpnext/utilities/doctype/rename_tool/rename_tool.py
index 0f8a7a385c..5e3ac1a4c9 100644
--- a/erpnext/utilities/doctype/rename_tool/rename_tool.py
+++ b/erpnext/utilities/doctype/rename_tool/rename_tool.py
@@ -29,4 +29,3 @@ def upload(select_doctype=None, rows=None):
rows = read_csv_content_from_attached_file(frappe.get_doc("Rename Tool", "Rename Tool"))
return bulk_rename(select_doctype, rows=rows)
-
diff --git a/erpnext/utilities/doctype/video/video_list.js b/erpnext/utilities/doctype/video/video_list.js
index 8273a4a781..6f78f6ee12 100644
--- a/erpnext/utilities/doctype/video/video_list.js
+++ b/erpnext/utilities/doctype/video/video_list.js
@@ -4,4 +4,4 @@ frappe.listview_settings["Video"] = {
frappe.set_route("Form","Video Settings", "Video Settings");
});
}
-}
\ No newline at end of file
+}
diff --git a/erpnext/utilities/doctype/video_settings/video_settings.py b/erpnext/utilities/doctype/video_settings/video_settings.py
index 36fb54f015..db021b473a 100644
--- a/erpnext/utilities/doctype/video_settings/video_settings.py
+++ b/erpnext/utilities/doctype/video_settings/video_settings.py
@@ -19,4 +19,4 @@ class VideoSettings(Document):
except Exception:
title = _("Failed to Authenticate the API key.")
frappe.log_error(title + "\n\n" + frappe.get_traceback(), title=title)
- frappe.throw(title + " Please check the error logs.", title=_("Invalid Credentials"))
\ No newline at end of file
+ frappe.throw(title + " Please check the error logs.", title=_("Invalid Credentials"))
diff --git a/erpnext/utilities/hierarchy_chart.py b/erpnext/utilities/hierarchy_chart.py
index fb58a5d586..384d84194b 100644
--- a/erpnext/utilities/hierarchy_chart.py
+++ b/erpnext/utilities/hierarchy_chart.py
@@ -26,4 +26,4 @@ def get_all_nodes(parent, parent_name, method, company):
if d.get('expandable'):
nodes_to_expand.append({'id': d.get('id'), 'name': d.get('name')})
- return result
\ No newline at end of file
+ return result
diff --git a/erpnext/utilities/report/youtube_interactions/youtube_interactions.py b/erpnext/utilities/report/youtube_interactions/youtube_interactions.py
index 3516a35097..29a489ddcc 100644
--- a/erpnext/utilities/report/youtube_interactions/youtube_interactions.py
+++ b/erpnext/utilities/report/youtube_interactions/youtube_interactions.py
@@ -110,4 +110,4 @@ def get_chart_summary_data(data):
"datatype": "Float",
}
]
- return chart_data, summary
\ No newline at end of file
+ return chart_data, summary
diff --git a/erpnext/utilities/web_form/addresses/addresses.js b/erpnext/utilities/web_form/addresses/addresses.js
index 699703c579..ffc5e98425 100644
--- a/erpnext/utilities/web_form/addresses/addresses.js
+++ b/erpnext/utilities/web_form/addresses/addresses.js
@@ -1,3 +1,3 @@
frappe.ready(function() {
// bind events here
-})
\ No newline at end of file
+})
diff --git a/erpnext/www/all-products/index.html b/erpnext/www/all-products/index.html
index 92c76ad879..7c18ecc41f 100644
--- a/erpnext/www/all-products/index.html
+++ b/erpnext/www/all-products/index.html
@@ -164,4 +164,4 @@
});
-{% endblock %}
\ No newline at end of file
+{% endblock %}
diff --git a/erpnext/www/all-products/item_row.html b/erpnext/www/all-products/item_row.html
index 20fc9a4878..a7e994c1e3 100644
--- a/erpnext/www/all-products/item_row.html
+++ b/erpnext/www/all-products/item_row.html
@@ -4,4 +4,3 @@
item.item_name or item.name, item.website_image or item.image, item.route, item.website_description or item.description,
item.formatted_price, item.item_group
) }}
-
diff --git a/erpnext/www/all-products/not_found.html b/erpnext/www/all-products/not_found.html
index e1986b4415..91989a9ef4 100644
--- a/erpnext/www/all-products/not_found.html
+++ b/erpnext/www/all-products/not_found.html
@@ -1 +1 @@
-{{ _('No products found') }}
\ No newline at end of file
+{{ _('No products found') }}
diff --git a/erpnext/www/book_appointment/index.css b/erpnext/www/book_appointment/index.css
index 6c49fde739..277610876f 100644
--- a/erpnext/www/book_appointment/index.css
+++ b/erpnext/www/book_appointment/index.css
@@ -12,7 +12,7 @@
@media (max-width: 768px) {
#submit-button-area {
display: grid;
- grid-template-areas:
+ grid-template-areas:
"submit"
"back";
}
diff --git a/erpnext/www/book_appointment/index.html b/erpnext/www/book_appointment/index.html
index f242f43ad5..207175f89d 100644
--- a/erpnext/www/book_appointment/index.html
+++ b/erpnext/www/book_appointment/index.html
@@ -63,4 +63,4 @@
-{% endblock %}
\ No newline at end of file
+{% endblock %}
diff --git a/erpnext/www/book_appointment/verify/index.html b/erpnext/www/book_appointment/verify/index.html
index ebb65b1f24..9bcd3d202e 100644
--- a/erpnext/www/book_appointment/verify/index.html
+++ b/erpnext/www/book_appointment/verify/index.html
@@ -3,7 +3,7 @@
{% block title %}
{{ _("Verify Email") }}
{% endblock%}
-
+
{% block page_content %}
{% if success==True %}
@@ -15,4 +15,4 @@
Verification failed please check the link
{% endif %}
-{% endblock%}
\ No newline at end of file
+{% endblock%}
diff --git a/erpnext/www/book_appointment/verify/index.py b/erpnext/www/book_appointment/verify/index.py
index d4478ae34a..bd766c0ea8 100644
--- a/erpnext/www/book_appointment/verify/index.py
+++ b/erpnext/www/book_appointment/verify/index.py
@@ -17,4 +17,4 @@ def get_context(context):
return context
else:
context.success = False
- return context
\ No newline at end of file
+ return context
diff --git a/erpnext/www/lms/content.py b/erpnext/www/lms/content.py
index 0c04845362..05cbb16d3c 100644
--- a/erpnext/www/lms/content.py
+++ b/erpnext/www/lms/content.py
@@ -65,4 +65,4 @@ def allowed_content_access(program, content, content_type):
and `tabTopic Content`.parent = `tabCourse Topic`.topic
and `tabProgram Course`.parent = %(program)s""", {'program': program})
- return (content, content_type) in contents_of_program
\ No newline at end of file
+ return (content, content_type) in contents_of_program
diff --git a/erpnext/www/lms/course.html b/erpnext/www/lms/course.html
index 0d70ed5cef..c07b9402b1 100644
--- a/erpnext/www/lms/course.html
+++ b/erpnext/www/lms/course.html
@@ -103,4 +103,4 @@
-{% endblock %}
\ No newline at end of file
+{% endblock %}
diff --git a/erpnext/www/lms/index.py b/erpnext/www/lms/index.py
index 26f59a2395..c14b94326b 100644
--- a/erpnext/www/lms/index.py
+++ b/erpnext/www/lms/index.py
@@ -13,4 +13,4 @@ def get_context(context):
def get_featured_programs():
- return utils.get_portal_programs() or []
\ No newline at end of file
+ return utils.get_portal_programs() or []
diff --git a/erpnext/www/lms/macros/card.html b/erpnext/www/lms/macros/card.html
index dc8fc5c72c..3cbdec61aa 100644
--- a/erpnext/www/lms/macros/card.html
+++ b/erpnext/www/lms/macros/card.html
@@ -31,4 +31,4 @@
-{% endmacro %}
\ No newline at end of file
+{% endmacro %}
diff --git a/erpnext/www/lms/macros/hero.html b/erpnext/www/lms/macros/hero.html
index 94f239eb8e..e72bfc8175 100644
--- a/erpnext/www/lms/macros/hero.html
+++ b/erpnext/www/lms/macros/hero.html
@@ -52,4 +52,4 @@
}
{% endblock %}
-{% endmacro %}
\ No newline at end of file
+{% endmacro %}
diff --git a/erpnext/www/lms/profile.py b/erpnext/www/lms/profile.py
index 4788ea6e70..7e338e38f1 100644
--- a/erpnext/www/lms/profile.py
+++ b/erpnext/www/lms/profile.py
@@ -23,4 +23,4 @@ def get_program_progress(student):
completion = utils.get_program_completion(program)
student_progress.append({'program': program.program_name, 'name': program.name, 'progress':progress, 'completion': completion})
- return student_progress
\ No newline at end of file
+ return student_progress
diff --git a/erpnext/www/lms/program.html b/erpnext/www/lms/program.html
index 7ad618630a..30528c667d 100644
--- a/erpnext/www/lms/program.html
+++ b/erpnext/www/lms/program.html
@@ -84,4 +84,4 @@
-{% endblock %}
\ No newline at end of file
+{% endblock %}
diff --git a/erpnext/www/lms/program.py b/erpnext/www/lms/program.py
index 104d3fa315..a4f588ccf1 100644
--- a/erpnext/www/lms/program.py
+++ b/erpnext/www/lms/program.py
@@ -26,4 +26,4 @@ def get_program(program_name):
def get_course_progress(courses, program):
progress = {course.name: utils.get_course_progress(course, program) for course in courses}
- return progress or {}
\ No newline at end of file
+ return progress or {}
diff --git a/erpnext/www/lms/topic.html b/erpnext/www/lms/topic.html
index cd24616cd4..dc69599112 100644
--- a/erpnext/www/lms/topic.html
+++ b/erpnext/www/lms/topic.html
@@ -55,4 +55,4 @@
-{% endblock %}
\ No newline at end of file
+{% endblock %}
diff --git a/erpnext/www/lms/topic.py b/erpnext/www/lms/topic.py
index 8abbc72e91..993828090c 100644
--- a/erpnext/www/lms/topic.py
+++ b/erpnext/www/lms/topic.py
@@ -42,4 +42,4 @@ def get_contents(topic, course, program):
result = None
progress.append({'content': content, 'content_type': content.doctype, 'completed': status, 'score': score, 'result': result})
- return progress
\ No newline at end of file
+ return progress
diff --git a/erpnext/www/support/index.html b/erpnext/www/support/index.html
index 12b4c2c081..3c19198cc1 100644
--- a/erpnext/www/support/index.html
+++ b/erpnext/www/support/index.html
@@ -96,6 +96,6 @@
.search-container {
margin-top: 1.2rem;
max-width: 500px;
- }
+ }
{%- endblock -%}
diff --git a/erpnext/www/support/index.py b/erpnext/www/support/index.py
index 5d267430c1..70090c7805 100644
--- a/erpnext/www/support/index.py
+++ b/erpnext/www/support/index.py
@@ -8,7 +8,7 @@ def get_context(context):
context.greeting_title = setting.greeting_title
context.greeting_subtitle = setting.greeting_subtitle
-
+
# Support content
favorite_articles = get_favorite_articles_by_page_view()
if len(favorite_articles) < 6:
@@ -16,15 +16,15 @@ def get_context(context):
if favorite_articles:
for article in favorite_articles:
name_list.append(article.name)
- for record in (frappe.get_all("Help Article",
- fields=["title", "content", "route", "category"],
- filters={"name": ['not in', tuple(name_list)], "published": 1},
+ for record in (frappe.get_all("Help Article",
+ fields=["title", "content", "route", "category"],
+ filters={"name": ['not in', tuple(name_list)], "published": 1},
order_by="creation desc", limit=(6-len(favorite_articles)))):
favorite_articles.append(record)
-
+
context.favorite_article_list = get_favorite_articles(favorite_articles)
context.help_article_list = get_help_article_list()
-
+
def get_favorite_articles_by_page_view():
return frappe.db.sql(
"""
@@ -34,13 +34,13 @@ def get_favorite_articles_by_page_view():
t1.content as content,
t1.route as route,
t1.category as category,
- count(t1.route) as count
- FROM `tabHelp Article` AS t1
+ count(t1.route) as count
+ FROM `tabHelp Article` AS t1
INNER JOIN
- `tabWeb Page View` AS t2
- ON t1.route = t2.path
+ `tabWeb Page View` AS t2
+ ON t1.route = t2.path
WHERE t1.published = 1
- GROUP BY route
+ GROUP BY route
ORDER BY count DESC
LIMIT 6;
""", as_dict=True)
@@ -71,4 +71,4 @@ def get_help_article_list():
'articles': help_articles,
}
help_article_list.append(help_aricles_per_caetgory)
- return help_article_list
\ No newline at end of file
+ return help_article_list
From 49db369d21315a49a09f6024b8eee19f250833fd Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Thu, 19 Aug 2021 13:43:01 +0530
Subject: [PATCH 369/386] chore: update git-blame-ignore-revs
---
.git-blame-ignore-revs | 3 +++
1 file changed, 3 insertions(+)
diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs
index e7fa354a2e..566323a9e9 100644
--- a/.git-blame-ignore-revs
+++ b/.git-blame-ignore-revs
@@ -13,3 +13,6 @@
# This commit just changes spaces to tabs for indentation in some files
5f473611bd6ed57703716244a054d3fb5ba9cd23
+
+# Whitespace fix throughout codebase
+4551d7d6029b6f587f6c99d4f8df5519241c6a86
From 2c40b7c206adaecccbd487b0b3df7406a625c7d9 Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Thu, 19 Aug 2021 14:12:09 +0530
Subject: [PATCH 370/386] chore: ignore whitespace fixes from git blame
---
.git-blame-ignore-revs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs
index 566323a9e9..068672a790 100644
--- a/.git-blame-ignore-revs
+++ b/.git-blame-ignore-revs
@@ -15,4 +15,4 @@
5f473611bd6ed57703716244a054d3fb5ba9cd23
# Whitespace fix throughout codebase
-4551d7d6029b6f587f6c99d4f8df5519241c6a86
+0ef5247e2f6e9562fe837394243b71642d1d98d6
From 5b54d0436b4dce36a0a1e10cb6a8dc2347672762 Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Thu, 19 Aug 2021 14:18:39 +0530
Subject: [PATCH 371/386] chore: revert "chore: ignore whitespace fixes from
git blame"
This reverts commit 2c40b7c206adaecccbd487b0b3df7406a625c7d9.
---
.git-blame-ignore-revs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs
index 068672a790..566323a9e9 100644
--- a/.git-blame-ignore-revs
+++ b/.git-blame-ignore-revs
@@ -15,4 +15,4 @@
5f473611bd6ed57703716244a054d3fb5ba9cd23
# Whitespace fix throughout codebase
-0ef5247e2f6e9562fe837394243b71642d1d98d6
+4551d7d6029b6f587f6c99d4f8df5519241c6a86
From cf8d2d97dddb02e23fa338d9c15269528187c02b Mon Sep 17 00:00:00 2001
From: Noah Jacob
Date: Thu, 19 Aug 2021 15:27:30 +0530
Subject: [PATCH 372/386] fix: Incorrect mandatory error message for warehouse
---
erpnext/stock/doctype/stock_entry/stock_entry.py | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py
index 7b31d2fdf2..90a33d3617 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.py
@@ -317,9 +317,6 @@ class StockEntry(StockController):
d.s_warehouse = self.from_warehouse
d.t_warehouse = self.to_warehouse
- if not (d.s_warehouse or d.t_warehouse):
- frappe.throw(_("Atleast one warehouse is mandatory"))
-
if self.purpose in source_mandatory and not d.s_warehouse:
if self.from_warehouse:
d.s_warehouse = self.from_warehouse
@@ -332,6 +329,7 @@ class StockEntry(StockController):
else:
frappe.throw(_("Target warehouse is mandatory for row {0}").format(d.idx))
+
if self.purpose == "Manufacture":
if validate_for_manufacture:
if d.is_finished_item or d.is_scrap_item:
@@ -346,6 +344,9 @@ class StockEntry(StockController):
if cstr(d.s_warehouse) == cstr(d.t_warehouse) and not self.purpose == "Material Transfer for Manufacture":
frappe.throw(_("Source and target warehouse cannot be same for row {0}").format(d.idx))
+ if not (d.s_warehouse or d.t_warehouse):
+ frappe.throw(_("Atleast one warehouse is mandatory"))
+
def validate_work_order(self):
if self.purpose in ("Manufacture", "Material Transfer for Manufacture", "Material Consumption for Manufacture"):
# check if work order is entered
From 993b0532f8b9240c8cc5ac8fb56a202a783fab4f Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Thu, 19 Aug 2021 15:43:34 +0530
Subject: [PATCH 373/386] Merge pull request #27026 from ankush/eq_assign
fix: equality check instead of assignment
[skip ci]
---
erpnext/shopping_cart/cart.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/shopping_cart/cart.py b/erpnext/shopping_cart/cart.py
index 56afe95efd..e9f4bd57a6 100644
--- a/erpnext/shopping_cart/cart.py
+++ b/erpnext/shopping_cart/cart.py
@@ -308,7 +308,7 @@ def update_party(fullname, company_name=None, mobile_no=None, phone=None):
party = get_party()
party.customer_name = company_name or fullname
- party.customer_type == "Company" if company_name else "Individual"
+ party.customer_type = "Company" if company_name else "Individual"
contact_name = frappe.db.get_value("Contact", {"email_id": frappe.session.user})
contact = frappe.get_doc("Contact", contact_name)
From 09f34e558eb695d451c393a6b76c7517b5f283c6 Mon Sep 17 00:00:00 2001
From: Alan <2.alan.tom@gmail.com>
Date: Thu, 19 Aug 2021 15:51:36 +0530
Subject: [PATCH 374/386] fix: set production plan to completed even on over
production (#27027)
---
.../manufacturing/doctype/production_plan/production_plan.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.py b/erpnext/manufacturing/doctype/production_plan/production_plan.py
index 8c27d6ccc9..7e7dc044e4 100644
--- a/erpnext/manufacturing/doctype/production_plan/production_plan.py
+++ b/erpnext/manufacturing/doctype/production_plan/production_plan.py
@@ -297,7 +297,7 @@ class ProductionPlan(Document):
if self.total_produced_qty > 0:
self.status = "In Process"
- if self.total_produced_qty == self.total_planned_qty:
+ if self.total_produced_qty >= self.total_planned_qty:
self.status = "Completed"
if self.status != 'Completed':
From 6541453c1697571bbc8fd50d0598cc20dfef2c34 Mon Sep 17 00:00:00 2001
From: Noah Jacob
Date: Thu, 19 Aug 2021 15:53:55 +0530
Subject: [PATCH 375/386] fix(ux): removed rate from grid view
---
.../promotional_scheme_price_discount.json | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/erpnext/accounts/doctype/promotional_scheme_price_discount/promotional_scheme_price_discount.json b/erpnext/accounts/doctype/promotional_scheme_price_discount/promotional_scheme_price_discount.json
index 795fb1c6f4..a70d5c9d43 100644
--- a/erpnext/accounts/doctype/promotional_scheme_price_discount/promotional_scheme_price_discount.json
+++ b/erpnext/accounts/doctype/promotional_scheme_price_discount/promotional_scheme_price_discount.json
@@ -106,7 +106,6 @@
"depends_on": "eval:doc.rate_or_discount==\"Rate\"",
"fieldname": "rate",
"fieldtype": "Currency",
- "in_list_view": 1,
"label": "Rate"
},
{
@@ -170,7 +169,7 @@
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
- "modified": "2021-03-07 11:56:23.424137",
+ "modified": "2021-08-19 15:49:29.598727",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Promotional Scheme Price Discount",
From c60d5523bca0a0631555a6234a485cd7a1e3c245 Mon Sep 17 00:00:00 2001
From: Afshan <33727827+AfshanKhan@users.noreply.github.com>
Date: Thu, 19 Aug 2021 16:23:18 +0530
Subject: [PATCH 376/386] fix: add child item groups into the filters (#26997)
* fix: add child item groups into the filters
* fix: appending values to proper variable
* fix: refactor the loop
---
.../item_group_wise_sales_target_variance.py | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/erpnext/selling/report/sales_partner_target_variance_based_on_item_group/item_group_wise_sales_target_variance.py b/erpnext/selling/report/sales_partner_target_variance_based_on_item_group/item_group_wise_sales_target_variance.py
index 89cfa16abe..24ca666f6b 100644
--- a/erpnext/selling/report/sales_partner_target_variance_based_on_item_group/item_group_wise_sales_target_variance.py
+++ b/erpnext/selling/report/sales_partner_target_variance_based_on_item_group/item_group_wise_sales_target_variance.py
@@ -44,6 +44,18 @@ def get_data(filters, period_list, partner_doctype):
if d.item_group not in item_groups:
item_groups.append(d.item_group)
+ if item_groups:
+ child_items = []
+ for item_group in item_groups:
+ if frappe.db.get_value("Item Group", {"name":item_group}, "is_group"):
+ for child_item_group in frappe.get_all("Item Group", {"parent_item_group":item_group}):
+ if child_item_group['name'] not in child_items:
+ child_items.append(child_item_group['name'])
+
+ for item in child_items:
+ if item not in item_groups:
+ item_groups.append(item)
+
date_field = ("transaction_date"
if filters.get('doctype') == "Sales Order" else "posting_date")
From 9225f02599c87ab9ee720e84877e5a3d7badadc2 Mon Sep 17 00:00:00 2001
From: Alan <2.alan.tom@gmail.com>
Date: Thu, 19 Aug 2021 18:49:20 +0530
Subject: [PATCH 377/386] fix: pass planned start date to created work order
(#27031)
* fix: pass planned start date to created workorder
* test: production plan to work order start date
Co-authored-by: Ankush Menat
---
.../doctype/production_plan/production_plan.py | 1 +
.../production_plan/test_production_plan.py | 17 ++++++++++++++++-
2 files changed, 17 insertions(+), 1 deletion(-)
diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.py b/erpnext/manufacturing/doctype/production_plan/production_plan.py
index 7e7dc044e4..b4c663507c 100644
--- a/erpnext/manufacturing/doctype/production_plan/production_plan.py
+++ b/erpnext/manufacturing/doctype/production_plan/production_plan.py
@@ -346,6 +346,7 @@ class ProductionPlan(Document):
"production_plan" : self.name,
"production_plan_item" : d.name,
"product_bundle_item" : d.product_bundle_item,
+ "planned_start_date" : d.planned_start_date,
"make_work_order_for_sub_assembly_items": d.get("make_work_order_for_sub_assembly_items", 0)
}
diff --git a/erpnext/manufacturing/doctype/production_plan/test_production_plan.py b/erpnext/manufacturing/doctype/production_plan/test_production_plan.py
index af8de8ee0e..a5b9ff845f 100644
--- a/erpnext/manufacturing/doctype/production_plan/test_production_plan.py
+++ b/erpnext/manufacturing/doctype/production_plan/test_production_plan.py
@@ -5,7 +5,7 @@ from __future__ import unicode_literals
import frappe
import unittest
-from frappe.utils import nowdate, now_datetime, flt
+from frappe.utils import nowdate, now_datetime, flt, add_to_date
from erpnext.stock.doctype.item.test_item import create_item
from erpnext.manufacturing.doctype.production_plan.production_plan import get_sales_orders
from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import create_stock_reconciliation
@@ -61,6 +61,21 @@ class TestProductionPlan(unittest.TestCase):
pln = frappe.get_doc('Production Plan', pln.name)
pln.cancel()
+ def test_production_plan_start_date(self):
+ planned_date = add_to_date(date=None, days=3)
+ plan = create_production_plan(item_code='Test Production Item 1', planned_start_date=planned_date)
+ plan.make_work_order()
+
+ work_orders = frappe.get_all('Work Order', fields = ['name', 'planned_start_date'],
+ filters = {'production_plan': plan.name})
+
+ self.assertEqual(work_orders[0].planned_start_date, planned_date)
+
+ for wo in work_orders:
+ frappe.delete_doc('Work Order', wo.name)
+
+ frappe.get_doc('Production Plan', plan.name).cancel()
+
def test_production_plan_for_existing_ordered_qty(self):
sr1 = create_stock_reconciliation(item_code="Raw Material Item 1",
target="_Test Warehouse - _TC", qty=1, rate=110)
From 45617ae22fbcb2c32343acc0324151e24a51e48b Mon Sep 17 00:00:00 2001
From: marination
Date: Thu, 19 Aug 2021 17:40:00 +0530
Subject: [PATCH 378/386] fix: Shopping cart Exchange rate validation
- Use `get_exchange_rate` to check for price list exchange rate in cart settings
- Move cart exchange rate validation for Price List from hooks to doc event
- Call cart exchange rate validation on PL update only if PL is in cart and currency is changed
---
erpnext/hooks.py | 2 +-
.../shopping_cart_settings.py | 61 ++++++++-----------
.../test_shopping_cart_settings.py | 4 +-
.../stock/doctype/price_list/price_list.py | 14 +++++
4 files changed, 42 insertions(+), 39 deletions(-)
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index 8f7c7db208..1aaf4ccd33 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -251,7 +251,7 @@ doc_events = {
"erpnext.support.doctype.issue.issue.set_first_response_time"
]
},
- ("Sales Taxes and Charges Template", 'Price List'): {
+ "Sales Taxes and Charges Template": {
"on_update": "erpnext.shopping_cart.doctype.shopping_cart_settings.shopping_cart_settings.validate_cart_settings"
},
"Website Settings": {
diff --git a/erpnext/shopping_cart/doctype/shopping_cart_settings/shopping_cart_settings.py b/erpnext/shopping_cart/doctype/shopping_cart_settings/shopping_cart_settings.py
index 2a497225fb..efed1968a1 100644
--- a/erpnext/shopping_cart/doctype/shopping_cart_settings/shopping_cart_settings.py
+++ b/erpnext/shopping_cart/doctype/shopping_cart_settings/shopping_cart_settings.py
@@ -6,7 +6,7 @@
from __future__ import unicode_literals
import frappe
from frappe import _, msgprint
-from frappe.utils import comma_and
+from frappe.utils import flt
from frappe.model.document import Document
from frappe.utils import get_datetime, get_datetime_str, now_datetime
@@ -18,46 +18,35 @@ class ShoppingCartSettings(Document):
def validate(self):
if self.enabled:
- self.validate_exchange_rates_exist()
+ self.validate_price_list_exchange_rate()
+
+ def validate_price_list_exchange_rate(self):
+ "Check if exchange rate exists for Price List currency (to Company's currency)."
+ from erpnext.setup.utils import get_exchange_rate
+
+ if not self.enabled or not self.company or not self.price_list:
+ return # this function is also called from hooks, check values again
+
+ company_currency = frappe.get_cached_value("Company", self.company, "default_currency")
+ price_list_currency = frappe.db.get_value("Price List", self.price_list, "currency")
- def validate_exchange_rates_exist(self):
- """check if exchange rates exist for all Price List currencies (to company's currency)"""
- company_currency = frappe.get_cached_value('Company', self.company, "default_currency")
if not company_currency:
- msgprint(_("Please specify currency in Company") + ": " + self.company,
- raise_exception=ShoppingCartSetupError)
+ msg = f"Please specify currency in Company {self.company}"
+ frappe.throw(_(msg), title=_("Missing Currency"), exc=ShoppingCartSetupError)
- price_list_currency_map = frappe.db.get_values("Price List",
- [self.price_list], "currency")
+ if not price_list_currency:
+ msg = f"Please specify currency in Price List {frappe.bold(self.price_list)}"
+ frappe.throw(_(msg), title=_("Missing Currency"), exc=ShoppingCartSetupError)
- price_list_currency_map = dict(price_list_currency_map)
+ if price_list_currency != company_currency:
+ from_currency, to_currency = price_list_currency, company_currency
- # check if all price lists have a currency
- for price_list, currency in price_list_currency_map.items():
- if not currency:
- frappe.throw(_("Currency is required for Price List {0}").format(price_list))
+ # Get exchange rate checks Currency Exchange Records too
+ exchange_rate = get_exchange_rate(from_currency, to_currency, args="for_selling")
- expected_to_exist = [currency + "-" + company_currency
- for currency in price_list_currency_map.values()
- if currency != company_currency]
-
- # manqala 20/09/2016: set up selection parameters for query from tabCurrency Exchange
- from_currency = [currency for currency in price_list_currency_map.values() if currency != company_currency]
- to_currency = company_currency
- # manqala end
-
- if expected_to_exist:
- # manqala 20/09/2016: modify query so that it uses date in the selection from Currency Exchange.
- # exchange rates defined with date less than the date on which this document is being saved will be selected
- exists = frappe.db.sql_list("""select CONCAT(from_currency,'-',to_currency) from `tabCurrency Exchange`
- where from_currency in (%s) and to_currency = "%s" and date <= curdate()""" % (", ".join(["%s"]*len(from_currency)), to_currency), tuple(from_currency))
- # manqala end
-
- missing = list(set(expected_to_exist).difference(exists))
-
- if missing:
- msgprint(_("Missing Currency Exchange Rates for {0}").format(comma_and(missing)),
- raise_exception=ShoppingCartSetupError)
+ if not flt(exchange_rate):
+ msg = f"Missing Currency Exchange Rates for {from_currency}-{to_currency}"
+ frappe.throw(_(msg), title=_("Missing"), exc=ShoppingCartSetupError)
def validate_tax_rule(self):
if not frappe.db.get_value("Tax Rule", {"use_for_shopping_cart" : 1}, "name"):
@@ -71,7 +60,7 @@ class ShoppingCartSettings(Document):
def get_shipping_rules(self, shipping_territory):
return self.get_name_from_territory(shipping_territory, "shipping_rules", "shipping_rule")
-def validate_cart_settings(doc, method):
+def validate_cart_settings(doc=None, method=None):
frappe.get_doc("Shopping Cart Settings", "Shopping Cart Settings").run_method("validate")
def get_shopping_cart_settings():
diff --git a/erpnext/shopping_cart/doctype/shopping_cart_settings/test_shopping_cart_settings.py b/erpnext/shopping_cart/doctype/shopping_cart_settings/test_shopping_cart_settings.py
index 008751e208..18a492b2c0 100644
--- a/erpnext/shopping_cart/doctype/shopping_cart_settings/test_shopping_cart_settings.py
+++ b/erpnext/shopping_cart/doctype/shopping_cart_settings/test_shopping_cart_settings.py
@@ -21,12 +21,12 @@ class TestShoppingCartSettings(unittest.TestCase):
cart_settings = self.get_cart_settings()
cart_settings.price_list = "_Test Price List Rest of the World"
- self.assertRaises(ShoppingCartSetupError, cart_settings.validate_exchange_rates_exist)
+ self.assertRaises(ShoppingCartSetupError, cart_settings.validate_price_list_exchange_rate)
from erpnext.setup.doctype.currency_exchange.test_currency_exchange import test_records as \
currency_exchange_records
frappe.get_doc(currency_exchange_records[0]).insert()
- cart_settings.validate_exchange_rates_exist()
+ cart_settings.validate_price_list_exchange_rate()
def test_tax_rule_validation(self):
frappe.db.sql("update `tabTax Rule` set use_for_shopping_cart = 0")
diff --git a/erpnext/stock/doctype/price_list/price_list.py b/erpnext/stock/doctype/price_list/price_list.py
index 10abde17eb..002d3d898e 100644
--- a/erpnext/stock/doctype/price_list/price_list.py
+++ b/erpnext/stock/doctype/price_list/price_list.py
@@ -13,6 +13,9 @@ class PriceList(Document):
if not cint(self.buying) and not cint(self.selling):
throw(_("Price List must be applicable for Buying or Selling"))
+ if not self.is_new():
+ self.check_impact_on_shopping_cart()
+
def on_update(self):
self.set_default_if_missing()
self.update_item_price()
@@ -32,6 +35,17 @@ class PriceList(Document):
buying=%s, selling=%s, modified=NOW() where price_list=%s""",
(self.currency, cint(self.buying), cint(self.selling), self.name))
+ def check_impact_on_shopping_cart(self):
+ "Check if Price List currency change impacts Shopping Cart."
+ from erpnext.shopping_cart.doctype.shopping_cart_settings.shopping_cart_settings import validate_cart_settings
+
+ doc_before_save = self.get_doc_before_save()
+ currency_changed = self.currency != doc_before_save.currency
+ affects_cart = self.name == frappe.get_cached_value("Shopping Cart Settings", None, "price_list")
+
+ if currency_changed and affects_cart:
+ validate_cart_settings()
+
def on_trash(self):
self.delete_price_list_details_key()
From f13315809e2bd56edb62955c7aa7b0b4bc4998bb Mon Sep 17 00:00:00 2001
From: Noah Jacob
Date: Thu, 19 Aug 2021 20:28:30 +0530
Subject: [PATCH 379/386] refactor: renamed varint_item_code to
variant_item_code (#27025)
---
erpnext/manufacturing/doctype/bom/bom.js | 6 +++---
erpnext/manufacturing/doctype/work_order/work_order.py | 4 ++--
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/erpnext/manufacturing/doctype/bom/bom.js b/erpnext/manufacturing/doctype/bom/bom.js
index 3f50b41be1..e72c8eb408 100644
--- a/erpnext/manufacturing/doctype/bom/bom.js
+++ b/erpnext/manufacturing/doctype/bom/bom.js
@@ -235,7 +235,7 @@ frappe.ui.form.on("BOM", {
reqd: 1,
},
{
- fieldname: "varint_item_code",
+ fieldname: "variant_item_code",
options: "Item",
label: __("Variant Item"),
fieldtype: "Link",
@@ -287,7 +287,7 @@ frappe.ui.form.on("BOM", {
let variant_items = data.items || [];
variant_items.forEach(d => {
- if (!d.varint_item_code) {
+ if (!d.variant_item_code) {
frappe.throw(__("Select variant item code for the template item {0}", [d.item_code]));
}
})
@@ -299,7 +299,7 @@ frappe.ui.form.on("BOM", {
has_template_rm.forEach(d => {
dialog.fields_dict.items.df.data.push({
"item_code": d.item_code,
- "varint_item_code": "",
+ "variant_item_code": "",
"qty": d.qty,
"source_warehouse": d.source_warehouse,
"operation": d.operation
diff --git a/erpnext/manufacturing/doctype/work_order/work_order.py b/erpnext/manufacturing/doctype/work_order/work_order.py
index 282b5d0afe..69a4b95c9a 100644
--- a/erpnext/manufacturing/doctype/work_order/work_order.py
+++ b/erpnext/manufacturing/doctype/work_order/work_order.py
@@ -838,7 +838,7 @@ def add_variant_item(variant_items, wo_doc, bom_no, table_name="items"):
for item in variant_items:
args = frappe._dict({
- "item_code": item.get("varint_item_code"),
+ "item_code": item.get("variant_item_code"),
"required_qty": item.get("qty"),
"qty": item.get("qty"), # for bom
"source_warehouse": item.get("source_warehouse"),
@@ -859,7 +859,7 @@ def add_variant_item(variant_items, wo_doc, bom_no, table_name="items"):
}, bom_doc)
if not args.source_warehouse:
- args["source_warehouse"] = get_item_defaults(item.get("varint_item_code"),
+ args["source_warehouse"] = get_item_defaults(item.get("variant_item_code"),
wo_doc.company).default_warehouse
args["amount"] = flt(args.get("required_qty")) * flt(args.get("rate"))
From 8046d15ef0edf2d9abc708133a39830b9a45b843 Mon Sep 17 00:00:00 2001
From: marination
Date: Thu, 19 Aug 2021 21:10:30 +0530
Subject: [PATCH 380/386] chore: Comment out obsolete test
- Modifying this test means considering extreme edge cases, which seems pointless now
---
.../test_shopping_cart_settings.py | 26 ++++++++++++-------
1 file changed, 17 insertions(+), 9 deletions(-)
diff --git a/erpnext/shopping_cart/doctype/shopping_cart_settings/test_shopping_cart_settings.py b/erpnext/shopping_cart/doctype/shopping_cart_settings/test_shopping_cart_settings.py
index 18a492b2c0..9965e1af67 100644
--- a/erpnext/shopping_cart/doctype/shopping_cart_settings/test_shopping_cart_settings.py
+++ b/erpnext/shopping_cart/doctype/shopping_cart_settings/test_shopping_cart_settings.py
@@ -16,17 +16,25 @@ class TestShoppingCartSettings(unittest.TestCase):
return frappe.get_doc({"doctype": "Shopping Cart Settings",
"company": "_Test Company"})
- def test_exchange_rate_exists(self):
- frappe.db.sql("""delete from `tabCurrency Exchange`""")
+ # NOTE: Exchangrate API has all enabled currencies that ERPNext supports.
+ # We aren't checking just currency exchange record anymore
+ # while validating price list currency exchange rate to that of company.
+ # The API is being used to fetch the rate which again almost always
+ # gives back a valid value (for valid currencies).
+ # This makes the test obsolete.
+ # Commenting because im not sure if there's a better test we can write
- cart_settings = self.get_cart_settings()
- cart_settings.price_list = "_Test Price List Rest of the World"
- self.assertRaises(ShoppingCartSetupError, cart_settings.validate_price_list_exchange_rate)
+ # def test_exchange_rate_exists(self):
+ # frappe.db.sql("""delete from `tabCurrency Exchange`""")
- from erpnext.setup.doctype.currency_exchange.test_currency_exchange import test_records as \
- currency_exchange_records
- frappe.get_doc(currency_exchange_records[0]).insert()
- cart_settings.validate_price_list_exchange_rate()
+ # cart_settings = self.get_cart_settings()
+ # cart_settings.price_list = "_Test Price List Rest of the World"
+ # self.assertRaises(ShoppingCartSetupError, cart_settings.validate_price_list_exchange_rate)
+
+ # from erpnext.setup.doctype.currency_exchange.test_currency_exchange import test_records as \
+ # currency_exchange_records
+ # frappe.get_doc(currency_exchange_records[0]).insert()
+ # cart_settings.validate_price_list_exchange_rate()
def test_tax_rule_validation(self):
frappe.db.sql("update `tabTax Rule` set use_for_shopping_cart = 0")
From 153fe1cdb4a0029d7327c2835007a96395479173 Mon Sep 17 00:00:00 2001
From: Saqib
Date: Fri, 20 Aug 2021 11:09:51 +0530
Subject: [PATCH 381/386] refactor: scan barcode field scanning (#26990)
---
.../doctype/pos_invoice/pos_invoice.json | 5 ++--
.../purchase_invoice/purchase_invoice.json | 5 ++--
.../doctype/sales_invoice/sales_invoice.json | 3 ++-
.../purchase_order/purchase_order.json | 3 ++-
erpnext/public/js/controllers/transaction.js | 24 -------------------
.../doctype/sales_order/sales_order.json | 5 ++--
.../doctype/delivery_note/delivery_note.json | 5 ++--
.../material_request/material_request.json | 7 +++---
.../purchase_receipt/purchase_receipt.json | 5 ++--
.../doctype/stock_entry/stock_entry.json | 3 ++-
10 files changed, 24 insertions(+), 41 deletions(-)
diff --git a/erpnext/accounts/doctype/pos_invoice/pos_invoice.json b/erpnext/accounts/doctype/pos_invoice/pos_invoice.json
index 33c3e0432b..fcccb39b70 100644
--- a/erpnext/accounts/doctype/pos_invoice/pos_invoice.json
+++ b/erpnext/accounts/doctype/pos_invoice/pos_invoice.json
@@ -595,7 +595,8 @@
{
"fieldname": "scan_barcode",
"fieldtype": "Data",
- "label": "Scan Barcode"
+ "label": "Scan Barcode",
+ "options": "Barcode"
},
{
"allow_bulk_edit": 1,
@@ -1553,7 +1554,7 @@
"icon": "fa fa-file-text",
"is_submittable": 1,
"links": [],
- "modified": "2021-07-29 13:37:20.636171",
+ "modified": "2021-08-17 20:13:44.255437",
"modified_by": "Administrator",
"module": "Accounts",
"name": "POS Invoice",
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
index 7025dd98db..7822f747f6 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
@@ -668,8 +668,7 @@
"fieldname": "scan_barcode",
"fieldtype": "Data",
"label": "Scan Barcode",
- "show_days": 1,
- "show_seconds": 1
+ "options": "Barcode"
},
{
"allow_bulk_edit": 1,
@@ -1715,7 +1714,7 @@
"idx": 204,
"is_submittable": 1,
"links": [],
- "modified": "2021-08-07 17:53:14.351439",
+ "modified": "2021-08-17 20:16:12.737743",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Invoice",
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
index b65b101051..e317443b91 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
@@ -692,6 +692,7 @@
{
"fieldname": "scan_barcode",
"fieldtype": "Data",
+ "options": "Barcode",
"hide_days": 1,
"hide_seconds": 1,
"label": "Scan Barcode"
@@ -2013,7 +2014,7 @@
"link_fieldname": "consolidated_invoice"
}
],
- "modified": "2021-08-17 19:00:32.230701",
+ "modified": "2021-08-17 20:16:12.737743",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice",
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.json b/erpnext/buying/doctype/purchase_order/purchase_order.json
index bb0ad60cab..a55a0b7f9f 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.json
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.json
@@ -565,6 +565,7 @@
"fieldname": "scan_barcode",
"fieldtype": "Data",
"label": "Scan Barcode",
+ "options": "Barcode",
"show_days": 1,
"show_seconds": 1
},
@@ -1378,7 +1379,7 @@
"idx": 105,
"is_submittable": 1,
"links": [],
- "modified": "2021-05-30 15:17:53.663648",
+ "modified": "2021-08-17 20:16:12.737743",
"modified_by": "Administrator",
"module": "Buying",
"name": "Purchase Order",
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index 3c6c347540..9375e358a9 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -342,30 +342,6 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe
this.set_dynamic_labels();
this.setup_sms();
this.setup_quality_inspection();
- let scan_barcode_field = this.frm.get_field('scan_barcode');
- if (scan_barcode_field && scan_barcode_field.get_value()) {
- scan_barcode_field.set_value("");
- scan_barcode_field.set_new_description("");
-
- if (frappe.is_mobile()) {
- if (scan_barcode_field.$input_wrapper.find('.input-group').length) return;
-
- let $input_group = $('');
- scan_barcode_field.$input_wrapper.find('.control-input').append($input_group);
- $input_group.append(scan_barcode_field.$input);
- $(`
-
-
-
- `)
- .on('click', '.btn', () => {
- frappe.barcode.scan_barcode().then(barcode => {
- scan_barcode_field.set_value(barcode);
- });
- })
- .appendTo($input_group);
- }
- }
}
scan_barcode() {
diff --git a/erpnext/selling/doctype/sales_order/sales_order.json b/erpnext/selling/doctype/sales_order/sales_order.json
index d31db820ab..38ea5c81d4 100644
--- a/erpnext/selling/doctype/sales_order/sales_order.json
+++ b/erpnext/selling/doctype/sales_order/sales_order.json
@@ -571,7 +571,8 @@
"fieldtype": "Data",
"hide_days": 1,
"hide_seconds": 1,
- "label": "Scan Barcode"
+ "label": "Scan Barcode",
+ "options": "Barcode"
},
{
"allow_bulk_edit": 1,
@@ -1510,7 +1511,7 @@
"idx": 105,
"is_submittable": 1,
"links": [],
- "modified": "2021-07-08 21:37:44.177493",
+ "modified": "2021-08-17 20:15:26.531553",
"modified_by": "Administrator",
"module": "Selling",
"name": "Sales Order",
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.json b/erpnext/stock/doctype/delivery_note/delivery_note.json
index dbfeb4a10b..958189614f 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.json
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.json
@@ -515,7 +515,8 @@
{
"fieldname": "scan_barcode",
"fieldtype": "Data",
- "label": "Scan Barcode"
+ "label": "Scan Barcode",
+ "options": "Barcode"
},
{
"allow_bulk_edit": 1,
@@ -1305,7 +1306,7 @@
"idx": 146,
"is_submittable": 1,
"links": [],
- "modified": "2021-07-08 21:37:20.802652",
+ "modified": "2021-08-17 20:15:50.574966",
"modified_by": "Administrator",
"module": "Stock",
"name": "Delivery Note",
diff --git a/erpnext/stock/doctype/material_request/material_request.json b/erpnext/stock/doctype/material_request/material_request.json
index 4e2d9e6170..cb46a6c368 100644
--- a/erpnext/stock/doctype/material_request/material_request.json
+++ b/erpnext/stock/doctype/material_request/material_request.json
@@ -133,7 +133,8 @@
{
"fieldname": "scan_barcode",
"fieldtype": "Data",
- "label": "Scan Barcode"
+ "label": "Scan Barcode",
+ "options": "Barcode"
},
{
"allow_bulk_edit": 1,
@@ -181,7 +182,7 @@
"no_copy": 1,
"oldfieldname": "status",
"oldfieldtype": "Select",
- "options": "\nDraft\nSubmitted\nStopped\nCancelled\nPending\nPartially Ordered\nPartially Received\nOrdered\nIssued\nTransferred\nReceived",
+ "options": "\nDraft\nSubmitted\nStopped\nCancelled\nPending\nPartially Ordered\nOrdered\nIssued\nTransferred\nReceived",
"print_hide": 1,
"print_width": "100px",
"read_only": 1,
@@ -314,7 +315,7 @@
"idx": 70,
"is_submittable": 1,
"links": [],
- "modified": "2021-03-31 23:52:55.392512",
+ "modified": "2021-08-17 20:16:12.737743",
"modified_by": "Administrator",
"module": "Stock",
"name": "Material Request",
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json
index 44fb736304..1a597343c0 100755
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json
@@ -1098,7 +1098,8 @@
{
"fieldname": "scan_barcode",
"fieldtype": "Data",
- "label": "Scan Barcode"
+ "label": "Scan Barcode",
+ "options": "Barcode"
},
{
"fieldname": "billing_address",
@@ -1148,7 +1149,7 @@
"idx": 261,
"is_submittable": 1,
"links": [],
- "modified": "2021-05-25 00:15:12.239017",
+ "modified": "2021-08-17 20:16:40.849885",
"modified_by": "Administrator",
"module": "Stock",
"name": "Purchase Receipt",
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.json b/erpnext/stock/doctype/stock_entry/stock_entry.json
index 523d332b8f..e6ce3c851f 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.json
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.json
@@ -355,6 +355,7 @@
},
{
"fieldname": "scan_barcode",
+ "options": "Barcode",
"fieldtype": "Data",
"label": "Scan Barcode"
},
@@ -629,7 +630,7 @@
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
- "modified": "2021-05-26 17:07:58.015737",
+ "modified": "2021-08-17 20:16:12.737743",
"modified_by": "Administrator",
"module": "Stock",
"name": "Stock Entry",
From c335962827e4927f7ada084e9ba4ab2db15e3eb6 Mon Sep 17 00:00:00 2001
From: Saqib
Date: Fri, 20 Aug 2021 11:10:46 +0530
Subject: [PATCH 382/386] refactor!: drop e-invoicing integration from erpnext
(#26940)
---
.../doctype/sales_invoice/regional/india.js | 2 -
.../sales_invoice/regional/india_list.js | 135 ---
.../doctype/sales_invoice/sales_invoice.py | 2 -
.../sales_invoice/test_sales_invoice.py | 48 -
.../gst_e_invoice/gst_e_invoice.html | 162 ---
.../gst_e_invoice/gst_e_invoice.json | 24 -
erpnext/controllers/accounts_controller.py | 9 -
erpnext/hooks.py | 1 -
erpnext/patches.txt | 9 +-
.../add_company_link_to_einvoice_settings.py | 16 -
.../v12_0/add_einvoice_status_field.py | 69 --
...add_einvoice_summary_report_permissions.py | 18 -
.../v12_0/add_ewaybill_validity_field.py | 16 -
.../patches/v12_0/setup_einvoice_fields.py | 56 -
.../show_einvoice_irn_cancelled_field.py | 12 -
.../v13_0/einvoicing_deprecation_warning.py | 9 +
.../v14_0}/__init__.py | 0
.../v14_0/delete_einvoicing_doctypes.py | 9 +
.../doctype/e_invoice_request_log/__init__.py | 0
.../e_invoice_request_log.js | 8 -
.../e_invoice_request_log.json | 102 --
.../e_invoice_request_log.py | 10 -
.../test_e_invoice_request_log.py | 10 -
.../doctype/e_invoice_settings/__init__.py | 0
.../e_invoice_settings/e_invoice_settings.js | 11 -
.../e_invoice_settings.json | 73 --
.../e_invoice_settings/e_invoice_settings.py | 13 -
.../test_e_invoice_settings.py | 10 -
.../doctype/e_invoice_user/__init__.py | 0
.../e_invoice_user/e_invoice_user.json | 57 --
.../doctype/e_invoice_user/e_invoice_user.py | 10 -
erpnext/regional/india/e_invoice/__init__.py | 0
.../india/e_invoice/einv_item_template.json | 31 -
.../india/e_invoice/einv_template.json | 110 --
.../india/e_invoice/einv_validation.json | 957 ------------------
erpnext/regional/india/e_invoice/einvoice.js | 292 ------
erpnext/regional/india/setup.py | 50 +-
.../report/e_invoice_summary/__init__.py | 0
.../e_invoice_summary/e_invoice_summary.js | 55 -
.../e_invoice_summary/e_invoice_summary.json | 28 -
.../e_invoice_summary/e_invoice_summary.py | 106 --
41 files changed, 24 insertions(+), 2506 deletions(-)
delete mode 100644 erpnext/accounts/print_format/gst_e_invoice/gst_e_invoice.html
delete mode 100644 erpnext/accounts/print_format/gst_e_invoice/gst_e_invoice.json
delete mode 100644 erpnext/patches/v12_0/add_company_link_to_einvoice_settings.py
delete mode 100644 erpnext/patches/v12_0/add_einvoice_status_field.py
delete mode 100644 erpnext/patches/v12_0/add_einvoice_summary_report_permissions.py
delete mode 100644 erpnext/patches/v12_0/add_ewaybill_validity_field.py
delete mode 100644 erpnext/patches/v12_0/setup_einvoice_fields.py
delete mode 100644 erpnext/patches/v12_0/show_einvoice_irn_cancelled_field.py
create mode 100644 erpnext/patches/v13_0/einvoicing_deprecation_warning.py
rename erpnext/{accounts/print_format/gst_e_invoice => patches/v14_0}/__init__.py (100%)
create mode 100644 erpnext/patches/v14_0/delete_einvoicing_doctypes.py
delete mode 100644 erpnext/regional/doctype/e_invoice_request_log/__init__.py
delete mode 100644 erpnext/regional/doctype/e_invoice_request_log/e_invoice_request_log.js
delete mode 100644 erpnext/regional/doctype/e_invoice_request_log/e_invoice_request_log.json
delete mode 100644 erpnext/regional/doctype/e_invoice_request_log/e_invoice_request_log.py
delete mode 100644 erpnext/regional/doctype/e_invoice_request_log/test_e_invoice_request_log.py
delete mode 100644 erpnext/regional/doctype/e_invoice_settings/__init__.py
delete mode 100644 erpnext/regional/doctype/e_invoice_settings/e_invoice_settings.js
delete mode 100644 erpnext/regional/doctype/e_invoice_settings/e_invoice_settings.json
delete mode 100644 erpnext/regional/doctype/e_invoice_settings/e_invoice_settings.py
delete mode 100644 erpnext/regional/doctype/e_invoice_settings/test_e_invoice_settings.py
delete mode 100644 erpnext/regional/doctype/e_invoice_user/__init__.py
delete mode 100644 erpnext/regional/doctype/e_invoice_user/e_invoice_user.json
delete mode 100644 erpnext/regional/doctype/e_invoice_user/e_invoice_user.py
delete mode 100644 erpnext/regional/india/e_invoice/__init__.py
delete mode 100644 erpnext/regional/india/e_invoice/einv_item_template.json
delete mode 100644 erpnext/regional/india/e_invoice/einv_template.json
delete mode 100644 erpnext/regional/india/e_invoice/einv_validation.json
delete mode 100644 erpnext/regional/india/e_invoice/einvoice.js
delete mode 100644 erpnext/regional/report/e_invoice_summary/__init__.py
delete mode 100644 erpnext/regional/report/e_invoice_summary/e_invoice_summary.js
delete mode 100644 erpnext/regional/report/e_invoice_summary/e_invoice_summary.json
delete mode 100644 erpnext/regional/report/e_invoice_summary/e_invoice_summary.py
diff --git a/erpnext/accounts/doctype/sales_invoice/regional/india.js b/erpnext/accounts/doctype/sales_invoice/regional/india.js
index f54bce8aac..6336db16eb 100644
--- a/erpnext/accounts/doctype/sales_invoice/regional/india.js
+++ b/erpnext/accounts/doctype/sales_invoice/regional/india.js
@@ -1,8 +1,6 @@
{% include "erpnext/regional/india/taxes.js" %}
-{% include "erpnext/regional/india/e_invoice/einvoice.js" %}
erpnext.setup_auto_gst_taxation('Sales Invoice');
-erpnext.setup_einvoice_actions('Sales Invoice')
frappe.ui.form.on("Sales Invoice", {
setup: function(frm) {
diff --git a/erpnext/accounts/doctype/sales_invoice/regional/india_list.js b/erpnext/accounts/doctype/sales_invoice/regional/india_list.js
index f01325d80b..d9d6634c39 100644
--- a/erpnext/accounts/doctype/sales_invoice/regional/india_list.js
+++ b/erpnext/accounts/doctype/sales_invoice/regional/india_list.js
@@ -36,139 +36,4 @@ frappe.listview_settings['Sales Invoice'].onload = function (list_view) {
};
list_view.page.add_actions_menu_item(__('Generate E-Way Bill JSON'), action, false);
-
- const generate_irns = () => {
- const docnames = list_view.get_checked_items(true);
- if (docnames && docnames.length) {
- frappe.call({
- method: 'erpnext.regional.india.e_invoice.utils.generate_einvoices',
- args: { docnames },
- freeze: true,
- freeze_message: __('Generating E-Invoices...')
- });
- } else {
- frappe.msgprint({
- message: __('Please select at least one sales invoice to generate IRN'),
- title: __('No Invoice Selected'),
- indicator: 'red'
- });
- }
- };
-
- const cancel_irns = () => {
- const docnames = list_view.get_checked_items(true);
-
- const fields = [
- {
- "label": "Reason",
- "fieldname": "reason",
- "fieldtype": "Select",
- "reqd": 1,
- "default": "1-Duplicate",
- "options": ["1-Duplicate", "2-Data Entry Error", "3-Order Cancelled", "4-Other"]
- },
- {
- "label": "Remark",
- "fieldname": "remark",
- "fieldtype": "Data",
- "reqd": 1
- }
- ];
-
- const d = new frappe.ui.Dialog({
- title: __("Cancel IRN"),
- fields: fields,
- primary_action: function() {
- const data = d.get_values();
- frappe.call({
- method: 'erpnext.regional.india.e_invoice.utils.cancel_irns',
- args: {
- doctype: list_view.doctype,
- docnames,
- reason: data.reason.split('-')[0],
- remark: data.remark
- },
- freeze: true,
- freeze_message: __('Cancelling E-Invoices...'),
- });
- d.hide();
- },
- primary_action_label: __('Submit')
- });
- d.show();
- };
-
- let einvoicing_enabled = false;
- frappe.db.get_single_value("E Invoice Settings", "enable").then(enabled => {
- einvoicing_enabled = enabled;
- });
-
- list_view.$result.on("change", "input[type=checkbox]", () => {
- if (einvoicing_enabled) {
- const docnames = list_view.get_checked_items(true);
- // show/hide e-invoicing actions when no sales invoices are checked
- if (docnames && docnames.length) {
- // prevent adding actions twice if e-invoicing action group already exists
- if (list_view.page.get_inner_group_button(__('E-Invoicing')).length == 0) {
- list_view.page.add_inner_button(__('Generate IRNs'), generate_irns, __('E-Invoicing'));
- list_view.page.add_inner_button(__('Cancel IRNs'), cancel_irns, __('E-Invoicing'));
- }
- } else {
- list_view.page.remove_inner_button(__('Generate IRNs'), __('E-Invoicing'));
- list_view.page.remove_inner_button(__('Cancel IRNs'), __('E-Invoicing'));
- }
- }
- });
-
- frappe.realtime.on("bulk_einvoice_generation_complete", (data) => {
- const { failures, user, invoices } = data;
-
- if (invoices.length != failures.length) {
- frappe.msgprint({
- message: __('{0} e-invoices generated successfully', [invoices.length]),
- title: __('Bulk E-Invoice Generation Complete'),
- indicator: 'orange'
- });
- }
-
- if (failures && failures.length && user == frappe.session.user) {
- let message = `
- Failed to generate IRNs for following ${failures.length} sales invoices:
-
- ${failures.map(d => `${d.docname} `).join('')}
-
- `;
- frappe.msgprint({
- message: message,
- title: __('Bulk E-Invoice Generation Complete'),
- indicator: 'orange'
- });
- }
- });
-
- frappe.realtime.on("bulk_einvoice_cancellation_complete", (data) => {
- const { failures, user, invoices } = data;
-
- if (invoices.length != failures.length) {
- frappe.msgprint({
- message: __('{0} e-invoices cancelled successfully', [invoices.length]),
- title: __('Bulk E-Invoice Cancellation Complete'),
- indicator: 'orange'
- });
- }
-
- if (failures && failures.length && user == frappe.session.user) {
- let message = `
- Failed to cancel IRNs for following ${failures.length} sales invoices:
-
- ${failures.map(d => `${d.docname} `).join('')}
-
- `;
- frappe.msgprint({
- message: message,
- title: __('Bulk E-Invoice Cancellation Complete'),
- indicator: 'orange'
- });
- }
- });
};
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index 5fa622856b..1cf0df00db 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -285,8 +285,6 @@ class SalesInvoice(SellingController):
def before_cancel(self):
self.check_if_consolidated_invoice()
-
- super(SalesInvoice, self).before_cancel()
self.update_time_sheet(None)
def on_cancel(self):
diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
index 4d1e0c3e06..984a652248 100644
--- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
@@ -2027,54 +2027,6 @@ class TestSalesInvoice(unittest.TestCase):
self.assertEqual(data['billLists'][0]['actualFromStateCode'],7)
self.assertEqual(data['billLists'][0]['fromStateCode'],27)
- def test_einvoice_submission_without_irn(self):
- # init
- einvoice_settings = frappe.get_doc('E Invoice Settings')
- einvoice_settings.enable = 1
- einvoice_settings.applicable_from = nowdate()
- einvoice_settings.append('credentials', {
- 'company': '_Test Company',
- 'gstin': '27AAECE4835E1ZR',
- 'username': 'test',
- 'password': 'test'
- })
- einvoice_settings.save()
-
- country = frappe.flags.country
- frappe.flags.country = 'India'
-
- si = make_sales_invoice_for_ewaybill()
- self.assertRaises(frappe.ValidationError, si.submit)
-
- si.irn = 'test_irn'
- si.submit()
-
- # reset
- einvoice_settings = frappe.get_doc('E Invoice Settings')
- einvoice_settings.enable = 0
- frappe.flags.country = country
-
- def test_einvoice_json(self):
- from erpnext.regional.india.e_invoice.utils import make_einvoice, validate_totals
-
- si = get_sales_invoice_for_e_invoice()
- si.discount_amount = 100
- si.save()
-
- einvoice = make_einvoice(si)
- self.assertTrue(einvoice['EwbDtls'])
- validate_totals(einvoice)
-
- si.apply_discount_on = 'Net Total'
- si.save()
- einvoice = make_einvoice(si)
- validate_totals(einvoice)
-
- [d.set('included_in_print_rate', 1) for d in si.taxes]
- si.save()
- einvoice = make_einvoice(si)
- validate_totals(einvoice)
-
def test_item_tax_net_range(self):
item = create_item("T Shirt")
diff --git a/erpnext/accounts/print_format/gst_e_invoice/gst_e_invoice.html b/erpnext/accounts/print_format/gst_e_invoice/gst_e_invoice.html
deleted file mode 100644
index 7643eca763..0000000000
--- a/erpnext/accounts/print_format/gst_e_invoice/gst_e_invoice.html
+++ /dev/null
@@ -1,162 +0,0 @@
-{%- from "templates/print_formats/standard_macros.html" import add_header, render_field, print_value -%}
-{%- set einvoice = json.loads(doc.signed_einvoice) -%}
-
-
-
- {% if print_settings.repeat_header_footer %}
-
- {% endif %}
-
1. Transaction Details
-
-
-
-
IRN
-
{{ einvoice.Irn }}
-
-
-
Ack. No
-
{{ einvoice.AckNo }}
-
-
-
Ack. Date
-
{{ frappe.utils.format_datetime(einvoice.AckDt, "dd/MM/yyyy hh:mm:ss") }}
-
-
-
Category
-
{{ einvoice.TranDtls.SupTyp }}
-
-
-
Document Type
-
{{ einvoice.DocDtls.Typ }}
-
-
-
Document No
-
{{ einvoice.DocDtls.No }}
-
-
-
-
-
-
-
2. Party Details
-
- {%- set seller = einvoice.SellerDtls -%}
-
-
Seller
-
{{ seller.Gstin }}
-
{{ seller.LglNm }}
-
{{ seller.Addr1 }}
- {%- if seller.Addr2 -%}
{{ seller.Addr2 }}
{% endif %}
-
{{ seller.Loc }}
-
{{ frappe.db.get_value("Address", doc.company_address, "gst_state") }} - {{ seller.Pin }}
-
- {%- if einvoice.ShipDtls -%}
- {%- set shipping = einvoice.ShipDtls -%}
-
Shipping
-
{{ shipping.Gstin }}
-
{{ shipping.LglNm }}
-
{{ shipping.Addr1 }}
- {%- if shipping.Addr2 -%}
{{ shipping.Addr2 }}
{% endif %}
-
{{ shipping.Loc }}
-
{{ frappe.db.get_value("Address", doc.shipping_address_name, "gst_state") }} - {{ shipping.Pin }}
- {% endif %}
-
- {%- set buyer = einvoice.BuyerDtls -%}
-
-
Buyer
-
{{ buyer.Gstin }}
-
{{ buyer.LglNm }}
-
{{ buyer.Addr1 }}
- {%- if buyer.Addr2 -%}
{{ buyer.Addr2 }}
{% endif %}
-
{{ buyer.Loc }}
-
{{ frappe.db.get_value("Address", doc.customer_address, "gst_state") }} - {{ buyer.Pin }}
-
-
-
-
3. Item Details
-
-
-
- Sr. No.
- Item
- HSN Code
- Qty
- UOM
- Rate
- Discount
- Taxable Amount
- Tax Rate
- Other Charges
- Total
-
-
-
- {% for item in einvoice.ItemList %}
-
- {{ item.SlNo }}
- {{ item.PrdDesc }}
- {{ item.HsnCd }}
- {{ item.Qty }}
- {{ item.Unit }}
- {{ frappe.utils.fmt_money(item.UnitPrice, None, "INR") }}
- {{ frappe.utils.fmt_money(item.Discount, None, "INR") }}
- {{ frappe.utils.fmt_money(item.AssAmt, None, "INR") }}
- {{ item.GstRt + item.CesRt }} %
- {{ frappe.utils.fmt_money(0, None, "INR") }}
- {{ frappe.utils.fmt_money(item.TotItemVal, None, "INR") }}
-
- {% endfor %}
-
-
-
-
-
4. Value Details
-
-
-
- Taxable Amount
- CGST
- SGST
- IGST
- CESS
- State CESS
- Discount
- Other Charges
- Round Off
- Total Value
-
-
-
- {%- set value_details = einvoice.ValDtls -%}
-
- {{ frappe.utils.fmt_money(value_details.AssVal, None, "INR") }}
- {{ frappe.utils.fmt_money(value_details.CgstVal, None, "INR") }}
- {{ frappe.utils.fmt_money(value_details.SgstVal, None, "INR") }}
- {{ frappe.utils.fmt_money(value_details.IgstVal, None, "INR") }}
- {{ frappe.utils.fmt_money(value_details.CesVal, None, "INR") }}
- {{ frappe.utils.fmt_money(0, None, "INR") }}
- {{ frappe.utils.fmt_money(value_details.Discount, None, "INR") }}
- {{ frappe.utils.fmt_money(value_details.OthChrg, None, "INR") }}
- {{ frappe.utils.fmt_money(value_details.RndOffAmt, None, "INR") }}
- {{ frappe.utils.fmt_money(value_details.TotInvVal, None, "INR") }}
-
-
-
-
-
diff --git a/erpnext/accounts/print_format/gst_e_invoice/gst_e_invoice.json b/erpnext/accounts/print_format/gst_e_invoice/gst_e_invoice.json
deleted file mode 100644
index 1001199a09..0000000000
--- a/erpnext/accounts/print_format/gst_e_invoice/gst_e_invoice.json
+++ /dev/null
@@ -1,24 +0,0 @@
-{
- "align_labels_right": 1,
- "creation": "2020-10-10 18:01:21.032914",
- "custom_format": 0,
- "default_print_language": "en-US",
- "disabled": 1,
- "doc_type": "Sales Invoice",
- "docstatus": 0,
- "doctype": "Print Format",
- "font": "Default",
- "html": "",
- "idx": 0,
- "line_breaks": 1,
- "modified": "2020-10-23 19:54:40.634936",
- "modified_by": "Administrator",
- "module": "Accounts",
- "name": "GST E-Invoice",
- "owner": "Administrator",
- "print_format_builder": 0,
- "print_format_type": "Jinja",
- "raw_printing": 0,
- "show_section_headings": 1,
- "standard": "Yes"
-}
\ No newline at end of file
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index 4c243d0cc4..8addbeb98f 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -135,14 +135,9 @@ class AccountsController(TransactionBase):
validate_regional(self)
- validate_einvoice_fields(self)
-
if self.doctype != 'Material Request':
apply_pricing_rule_on_transaction(self)
- def before_cancel(self):
- validate_einvoice_fields(self)
-
def on_trash(self):
# delete sl and gl entries on deletion of transaction
if frappe.db.get_single_value('Accounts Settings', 'delete_linked_ledger_entries'):
@@ -1975,7 +1970,3 @@ def update_child_qty_rate(parent_doctype, trans_items, parent_doctype_name, chil
@erpnext.allow_regional
def validate_regional(doc):
pass
-
-@erpnext.allow_regional
-def validate_einvoice_fields(doc):
- pass
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index 1aaf4ccd33..73831bf9af 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -436,7 +436,6 @@ regional_overrides = {
'erpnext.controllers.taxes_and_totals.get_regional_round_off_accounts': 'erpnext.regional.india.utils.get_regional_round_off_accounts',
'erpnext.hr.utils.calculate_annual_eligible_hra_exemption': 'erpnext.regional.india.utils.calculate_annual_eligible_hra_exemption',
'erpnext.hr.utils.calculate_hra_exemption_for_period': 'erpnext.regional.india.utils.calculate_hra_exemption_for_period',
- 'erpnext.controllers.accounts_controller.validate_einvoice_fields': 'erpnext.regional.india.e_invoice.utils.validate_einvoice_fields',
'erpnext.assets.doctype.asset.asset.get_depreciation_amount': 'erpnext.regional.india.utils.get_depreciation_amount',
'erpnext.stock.doctype.item.item.set_item_tax_from_hsn_code': 'erpnext.regional.india.utils.set_item_tax_from_hsn_code'
},
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 776b41dcc2..b86c236a7f 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -214,7 +214,6 @@ erpnext.patches.v13_0.delete_old_sales_reports
execute:frappe.delete_doc_if_exists("DocType", "Bank Reconciliation")
erpnext.patches.v13_0.move_doctype_reports_and_notification_from_hr_to_payroll #22-06-2020
erpnext.patches.v13_0.move_payroll_setting_separately_from_hr_settings #22-06-2020
-execute:frappe.reload_doc("regional", "doctype", "e_invoice_settings")
erpnext.patches.v13_0.check_is_income_tax_component #22-06-2020
erpnext.patches.v13_0.loyalty_points_entry_for_pos_invoice #22-07-2020
erpnext.patches.v12_0.add_taxjar_integration_field
@@ -237,7 +236,6 @@ erpnext.patches.v13_0.set_app_name
erpnext.patches.v13_0.print_uom_after_quantity_patch
erpnext.patches.v13_0.set_payment_channel_in_payment_gateway_account
erpnext.patches.v13_0.create_healthcare_custom_fields_in_stock_entry_detail
-erpnext.patches.v12_0.setup_einvoice_fields #2020-12-02
erpnext.patches.v13_0.updates_for_multi_currency_payroll
erpnext.patches.v13_0.update_reason_for_resignation_in_employee
execute:frappe.delete_doc("Report", "Quoted Item Comparison")
@@ -259,14 +257,11 @@ erpnext.patches.v12_0.add_state_code_for_ladakh
erpnext.patches.v13_0.item_reposting_for_incorrect_sl_and_gl
erpnext.patches.v13_0.delete_old_bank_reconciliation_doctypes
erpnext.patches.v12_0.update_vehicle_no_reqd_condition
-erpnext.patches.v12_0.add_einvoice_status_field #2021-03-17
-erpnext.patches.v12_0.add_einvoice_summary_report_permissions
erpnext.patches.v13_0.setup_fields_for_80g_certificate_and_donation
erpnext.patches.v13_0.rename_membership_settings_to_non_profit_settings
erpnext.patches.v13_0.setup_gratuity_rule_for_india_and_uae
erpnext.patches.v13_0.setup_uae_vat_fields
execute:frappe.db.set_value('System Settings', None, 'app_name', 'ERPNext')
-erpnext.patches.v12_0.add_company_link_to_einvoice_settings
erpnext.patches.v13_0.rename_discharge_date_in_ip_record
erpnext.patches.v12_0.create_taxable_value_field
erpnext.patches.v12_0.add_gst_category_in_delivery_note
@@ -277,7 +272,6 @@ erpnext.patches.v12_0.add_document_type_field_for_italy_einvoicing
erpnext.patches.v13_0.make_non_standard_user_type #13-04-2021
erpnext.patches.v13_0.update_shipment_status
erpnext.patches.v13_0.remove_attribute_field_from_item_variant_setting
-erpnext.patches.v12_0.add_ewaybill_validity_field
erpnext.patches.v13_0.germany_make_custom_fields
erpnext.patches.v13_0.germany_fill_debtor_creditor_number
erpnext.patches.v13_0.set_pos_closing_as_failed
@@ -294,10 +288,11 @@ erpnext.patches.v13_0.update_level_in_bom #1234sswef
erpnext.patches.v13_0.add_missing_fg_item_for_stock_entry
erpnext.patches.v13_0.update_subscription_status_in_memberships
erpnext.patches.v13_0.update_amt_in_work_order_required_items
-erpnext.patches.v12_0.show_einvoice_irn_cancelled_field
erpnext.patches.v13_0.delete_orphaned_tables
erpnext.patches.v13_0.update_export_type_for_gst #2021-08-16
erpnext.patches.v13_0.update_tds_check_field #3
erpnext.patches.v13_0.add_custom_field_for_south_africa #2
erpnext.patches.v13_0.update_recipient_email_digest
erpnext.patches.v13_0.shopify_deprecation_warning
+erpnext.patches.v13_0.einvoicing_deprecation_warning
+erpnext.patches.v14_0.delete_einvoicing_doctypes
diff --git a/erpnext/patches/v12_0/add_company_link_to_einvoice_settings.py b/erpnext/patches/v12_0/add_company_link_to_einvoice_settings.py
deleted file mode 100644
index c2ed6c288f..0000000000
--- a/erpnext/patches/v12_0/add_company_link_to_einvoice_settings.py
+++ /dev/null
@@ -1,16 +0,0 @@
-from __future__ import unicode_literals
-import frappe
-
-def execute():
- company = frappe.get_all('Company', filters = {'country': 'India'})
- if not company or not frappe.db.count('E Invoice User'):
- return
-
- frappe.reload_doc("regional", "doctype", "e_invoice_user")
- for creds in frappe.db.get_all('E Invoice User', fields=['name', 'gstin']):
- company_name = frappe.db.sql("""
- select dl.link_name from `tabAddress` a, `tabDynamic Link` dl
- where a.gstin = %s and dl.parent = a.name and dl.link_doctype = 'Company'
- """, (creds.get('gstin')))
- if company_name and len(company_name) > 0:
- frappe.db.set_value('E Invoice User', creds.get('name'), 'company', company_name[0][0])
diff --git a/erpnext/patches/v12_0/add_einvoice_status_field.py b/erpnext/patches/v12_0/add_einvoice_status_field.py
deleted file mode 100644
index 2dfd30714c..0000000000
--- a/erpnext/patches/v12_0/add_einvoice_status_field.py
+++ /dev/null
@@ -1,69 +0,0 @@
-from __future__ import unicode_literals
-import json
-import frappe
-from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
-
-def execute():
- company = frappe.get_all('Company', filters = {'country': 'India'})
- if not company:
- return
-
- # move hidden einvoice fields to a different section
- custom_fields = {
- 'Sales Invoice': [
- dict(fieldname='einvoice_section', label='E-Invoice Fields', fieldtype='Section Break', insert_after='gst_vehicle_type',
- print_hide=1, hidden=1),
-
- dict(fieldname='ack_no', label='Ack. No.', fieldtype='Data', read_only=1, hidden=1, insert_after='einvoice_section',
- no_copy=1, print_hide=1),
-
- dict(fieldname='ack_date', label='Ack. Date', fieldtype='Data', read_only=1, hidden=1, insert_after='ack_no', no_copy=1, print_hide=1),
-
- dict(fieldname='irn_cancel_date', label='Cancel Date', fieldtype='Data', read_only=1, hidden=1, insert_after='ack_date',
- no_copy=1, print_hide=1),
-
- dict(fieldname='signed_einvoice', label='Signed E-Invoice', fieldtype='Code', options='JSON', hidden=1, insert_after='irn_cancel_date',
- no_copy=1, print_hide=1, read_only=1),
-
- dict(fieldname='signed_qr_code', label='Signed QRCode', fieldtype='Code', options='JSON', hidden=1, insert_after='signed_einvoice',
- no_copy=1, print_hide=1, read_only=1),
-
- dict(fieldname='qrcode_image', label='QRCode', fieldtype='Attach Image', hidden=1, insert_after='signed_qr_code',
- no_copy=1, print_hide=1, read_only=1),
-
- dict(fieldname='einvoice_status', label='E-Invoice Status', fieldtype='Select', insert_after='qrcode_image',
- options='\nPending\nGenerated\nCancelled\nFailed', default=None, hidden=1, no_copy=1, print_hide=1, read_only=1),
-
- dict(fieldname='failure_description', label='E-Invoice Failure Description', fieldtype='Code', options='JSON',
- hidden=1, insert_after='einvoice_status', no_copy=1, print_hide=1, read_only=1)
- ]
- }
- create_custom_fields(custom_fields, update=True)
-
- if frappe.db.exists('E Invoice Settings') and frappe.db.get_single_value('E Invoice Settings', 'enable'):
- frappe.db.sql('''
- UPDATE `tabSales Invoice` SET einvoice_status = 'Pending'
- WHERE
- posting_date >= '2021-04-01'
- AND ifnull(irn, '') = ''
- AND ifnull(`billing_address_gstin`, '') != ifnull(`company_gstin`, '')
- AND ifnull(gst_category, '') in ('Registered Regular', 'SEZ', 'Overseas', 'Deemed Export')
- ''')
-
- # set appropriate statuses
- frappe.db.sql('''UPDATE `tabSales Invoice` SET einvoice_status = 'Generated'
- WHERE ifnull(irn, '') != '' AND ifnull(irn_cancelled, 0) = 0''')
-
- frappe.db.sql('''UPDATE `tabSales Invoice` SET einvoice_status = 'Cancelled'
- WHERE ifnull(irn_cancelled, 0) = 1''')
-
- # set correct acknowledgement in e-invoices
- einvoices = frappe.get_all('Sales Invoice', {'irn': ['is', 'set']}, ['name', 'signed_einvoice'])
-
- if einvoices:
- for inv in einvoices:
- signed_einvoice = inv.get('signed_einvoice')
- if signed_einvoice:
- signed_einvoice = json.loads(signed_einvoice)
- frappe.db.set_value('Sales Invoice', inv.get('name'), 'ack_no', signed_einvoice.get('AckNo'), update_modified=False)
- frappe.db.set_value('Sales Invoice', inv.get('name'), 'ack_date', signed_einvoice.get('AckDt'), update_modified=False)
diff --git a/erpnext/patches/v12_0/add_einvoice_summary_report_permissions.py b/erpnext/patches/v12_0/add_einvoice_summary_report_permissions.py
deleted file mode 100644
index c1c11e2600..0000000000
--- a/erpnext/patches/v12_0/add_einvoice_summary_report_permissions.py
+++ /dev/null
@@ -1,18 +0,0 @@
-from __future__ import unicode_literals
-import frappe
-
-def execute():
- company = frappe.get_all('Company', filters = {'country': 'India'})
- if not company:
- return
-
- if frappe.db.exists('Report', 'E-Invoice Summary') and \
- not frappe.db.get_value('Custom Role', dict(report='E-Invoice Summary')):
- frappe.get_doc(dict(
- doctype='Custom Role',
- report='E-Invoice Summary',
- roles= [
- dict(role='Accounts User'),
- dict(role='Accounts Manager')
- ]
- )).insert()
diff --git a/erpnext/patches/v12_0/add_ewaybill_validity_field.py b/erpnext/patches/v12_0/add_ewaybill_validity_field.py
deleted file mode 100644
index f29b71437e..0000000000
--- a/erpnext/patches/v12_0/add_ewaybill_validity_field.py
+++ /dev/null
@@ -1,16 +0,0 @@
-from __future__ import unicode_literals
-import frappe
-from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
-
-def execute():
- company = frappe.get_all('Company', filters = {'country': 'India'})
- if not company:
- return
-
- custom_fields = {
- 'Sales Invoice': [
- dict(fieldname='eway_bill_validity', label='E-Way Bill Validity', fieldtype='Data', no_copy=1, print_hide=1,
- depends_on='ewaybill', read_only=1, allow_on_submit=1, insert_after='ewaybill')
- ]
- }
- create_custom_fields(custom_fields, update=True)
diff --git a/erpnext/patches/v12_0/setup_einvoice_fields.py b/erpnext/patches/v12_0/setup_einvoice_fields.py
deleted file mode 100644
index 82b14fc9d6..0000000000
--- a/erpnext/patches/v12_0/setup_einvoice_fields.py
+++ /dev/null
@@ -1,56 +0,0 @@
-from __future__ import unicode_literals
-import frappe
-from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
-from erpnext.regional.india.setup import add_permissions, add_print_formats
-
-def execute():
- company = frappe.get_all('Company', filters = {'country': 'India'})
- if not company:
- return
-
- frappe.reload_doc("custom", "doctype", "custom_field")
- frappe.reload_doc("regional", "doctype", "e_invoice_settings")
- custom_fields = {
- 'Sales Invoice': [
- dict(fieldname='irn', label='IRN', fieldtype='Data', read_only=1, insert_after='customer', no_copy=1, print_hide=1,
- depends_on='eval:in_list(["Registered Regular", "SEZ", "Overseas", "Deemed Export"], doc.gst_category) && doc.irn_cancelled === 0'),
-
- dict(fieldname='ack_no', label='Ack. No.', fieldtype='Data', read_only=1, hidden=1, insert_after='irn', no_copy=1, print_hide=1),
-
- dict(fieldname='ack_date', label='Ack. Date', fieldtype='Data', read_only=1, hidden=1, insert_after='ack_no', no_copy=1, print_hide=1),
-
- dict(fieldname='irn_cancelled', label='IRN Cancelled', fieldtype='Check', no_copy=1, print_hide=1,
- depends_on='eval:(doc.irn_cancelled === 1)', read_only=1, allow_on_submit=1, insert_after='customer'),
-
- dict(fieldname='eway_bill_cancelled', label='E-Way Bill Cancelled', fieldtype='Check', no_copy=1, print_hide=1,
- depends_on='eval:(doc.eway_bill_cancelled === 1)', read_only=1, allow_on_submit=1, insert_after='customer'),
-
- dict(fieldname='signed_einvoice', fieldtype='Code', options='JSON', hidden=1, no_copy=1, print_hide=1, read_only=1),
-
- dict(fieldname='signed_qr_code', fieldtype='Code', options='JSON', hidden=1, no_copy=1, print_hide=1, read_only=1),
-
- dict(fieldname='qrcode_image', label='QRCode', fieldtype='Attach Image', hidden=1, no_copy=1, print_hide=1, read_only=1)
- ]
- }
- create_custom_fields(custom_fields, update=True)
- add_permissions()
- add_print_formats()
-
- einvoice_cond = 'in_list(["Registered Regular", "SEZ", "Overseas", "Deemed Export"], doc.gst_category)'
- t = {
- 'mode_of_transport': [{'default': None}],
- 'distance': [{'mandatory_depends_on': f'eval:{einvoice_cond} && doc.transporter'}],
- 'gst_vehicle_type': [{'mandatory_depends_on': f'eval:{einvoice_cond} && doc.mode_of_transport == "Road"'}],
- 'lr_date': [{'mandatory_depends_on': f'eval:{einvoice_cond} && in_list(["Air", "Ship", "Rail"], doc.mode_of_transport)'}],
- 'lr_no': [{'mandatory_depends_on': f'eval:{einvoice_cond} && in_list(["Air", "Ship", "Rail"], doc.mode_of_transport)'}],
- 'vehicle_no': [{'mandatory_depends_on': f'eval:{einvoice_cond} && doc.mode_of_transport == "Road"'}],
- 'ewaybill': [
- {'read_only_depends_on': 'eval:doc.irn && doc.ewaybill'},
- {'depends_on': 'eval:((doc.docstatus === 1 || doc.ewaybill) && doc.eway_bill_cancelled === 0)'}
- ]
- }
-
- for field, conditions in t.items():
- for c in conditions:
- [(prop, value)] = c.items()
- frappe.db.set_value('Custom Field', { 'fieldname': field }, prop, value)
diff --git a/erpnext/patches/v12_0/show_einvoice_irn_cancelled_field.py b/erpnext/patches/v12_0/show_einvoice_irn_cancelled_field.py
deleted file mode 100644
index 2319c17b34..0000000000
--- a/erpnext/patches/v12_0/show_einvoice_irn_cancelled_field.py
+++ /dev/null
@@ -1,12 +0,0 @@
-from __future__ import unicode_literals
-import frappe
-
-def execute():
- company = frappe.get_all('Company', filters = {'country': 'India'})
- if not company:
- return
-
- irn_cancelled_field = frappe.db.exists('Custom Field', {'dt': 'Sales Invoice', 'fieldname': 'irn_cancelled'})
- if irn_cancelled_field:
- frappe.db.set_value('Custom Field', irn_cancelled_field, 'depends_on', 'eval: doc.irn')
- frappe.db.set_value('Custom Field', irn_cancelled_field, 'read_only', 0)
diff --git a/erpnext/patches/v13_0/einvoicing_deprecation_warning.py b/erpnext/patches/v13_0/einvoicing_deprecation_warning.py
new file mode 100644
index 0000000000..e123a55f5a
--- /dev/null
+++ b/erpnext/patches/v13_0/einvoicing_deprecation_warning.py
@@ -0,0 +1,9 @@
+import click
+
+
+def execute():
+ click.secho(
+ "Indian E-Invoicing integration is moved to a separate app and will be removed from ERPNext in version-14.\n"
+ "Please install the app to continue using the integration: https://github.com/frappe/erpnext_gst_compliance",
+ fg="yellow",
+ )
diff --git a/erpnext/accounts/print_format/gst_e_invoice/__init__.py b/erpnext/patches/v14_0/__init__.py
similarity index 100%
rename from erpnext/accounts/print_format/gst_e_invoice/__init__.py
rename to erpnext/patches/v14_0/__init__.py
diff --git a/erpnext/patches/v14_0/delete_einvoicing_doctypes.py b/erpnext/patches/v14_0/delete_einvoicing_doctypes.py
new file mode 100644
index 0000000000..b77d2440eb
--- /dev/null
+++ b/erpnext/patches/v14_0/delete_einvoicing_doctypes.py
@@ -0,0 +1,9 @@
+import frappe
+
+def execute():
+ frappe.delete_doc('DocType', 'E Invoice Settings', ignore_missing=True)
+ frappe.delete_doc('DocType', 'E Invoice User', ignore_missing=True)
+ frappe.delete_doc('Report', 'E-Invoice Summary', ignore_missing=True)
+ frappe.delete_doc('Print Format', 'GST E-Invoice', ignore_missing=True)
+ frappe.delete_doc('Custom Field', 'Sales Invoice-eway_bill_cancelled', ignore_missing=True)
+ frappe.delete_doc('Custom Field', 'Sales Invoice-irn_cancelled', ignore_missing=True)
\ No newline at end of file
diff --git a/erpnext/regional/doctype/e_invoice_request_log/__init__.py b/erpnext/regional/doctype/e_invoice_request_log/__init__.py
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/erpnext/regional/doctype/e_invoice_request_log/e_invoice_request_log.js b/erpnext/regional/doctype/e_invoice_request_log/e_invoice_request_log.js
deleted file mode 100644
index 7b7ba964e5..0000000000
--- a/erpnext/regional/doctype/e_invoice_request_log/e_invoice_request_log.js
+++ /dev/null
@@ -1,8 +0,0 @@
-// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
-// For license information, please see license.txt
-
-frappe.ui.form.on('E Invoice Request Log', {
- // refresh: function(frm) {
-
- // }
-});
diff --git a/erpnext/regional/doctype/e_invoice_request_log/e_invoice_request_log.json b/erpnext/regional/doctype/e_invoice_request_log/e_invoice_request_log.json
deleted file mode 100644
index 3034370fea..0000000000
--- a/erpnext/regional/doctype/e_invoice_request_log/e_invoice_request_log.json
+++ /dev/null
@@ -1,102 +0,0 @@
-{
- "actions": [],
- "autoname": "EINV-REQ-.#####",
- "creation": "2020-12-08 12:54:08.175992",
- "doctype": "DocType",
- "editable_grid": 1,
- "engine": "InnoDB",
- "field_order": [
- "user",
- "url",
- "headers",
- "response",
- "column_break_7",
- "timestamp",
- "reference_invoice",
- "data"
- ],
- "fields": [
- {
- "fieldname": "user",
- "fieldtype": "Link",
- "label": "User",
- "options": "User"
- },
- {
- "fieldname": "reference_invoice",
- "fieldtype": "Data",
- "label": "Reference Invoice"
- },
- {
- "fieldname": "headers",
- "fieldtype": "Code",
- "label": "Headers",
- "options": "JSON"
- },
- {
- "fieldname": "data",
- "fieldtype": "Code",
- "label": "Data",
- "options": "JSON"
- },
- {
- "default": "Now",
- "fieldname": "timestamp",
- "fieldtype": "Datetime",
- "label": "Timestamp"
- },
- {
- "fieldname": "response",
- "fieldtype": "Code",
- "label": "Response",
- "options": "JSON"
- },
- {
- "fieldname": "url",
- "fieldtype": "Data",
- "label": "URL"
- },
- {
- "fieldname": "column_break_7",
- "fieldtype": "Column Break"
- }
- ],
- "index_web_pages_for_search": 1,
- "links": [],
- "modified": "2021-01-13 12:06:57.253111",
- "modified_by": "Administrator",
- "module": "Regional",
- "name": "E Invoice Request Log",
- "owner": "Administrator",
- "permissions": [
- {
- "email": 1,
- "export": 1,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "System Manager",
- "share": 1
- },
- {
- "email": 1,
- "export": 1,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Accounts User",
- "share": 1
- },
- {
- "email": 1,
- "export": 1,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Accounts Manager",
- "share": 1
- }
- ],
- "sort_field": "modified",
- "sort_order": "DESC"
-}
\ No newline at end of file
diff --git a/erpnext/regional/doctype/e_invoice_request_log/e_invoice_request_log.py b/erpnext/regional/doctype/e_invoice_request_log/e_invoice_request_log.py
deleted file mode 100644
index 9150bdd926..0000000000
--- a/erpnext/regional/doctype/e_invoice_request_log/e_invoice_request_log.py
+++ /dev/null
@@ -1,10 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
-# For license information, please see license.txt
-
-from __future__ import unicode_literals
-# import frappe
-from frappe.model.document import Document
-
-class EInvoiceRequestLog(Document):
- pass
diff --git a/erpnext/regional/doctype/e_invoice_request_log/test_e_invoice_request_log.py b/erpnext/regional/doctype/e_invoice_request_log/test_e_invoice_request_log.py
deleted file mode 100644
index c84e9a249b..0000000000
--- a/erpnext/regional/doctype/e_invoice_request_log/test_e_invoice_request_log.py
+++ /dev/null
@@ -1,10 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
-# See license.txt
-from __future__ import unicode_literals
-
-# import frappe
-import unittest
-
-class TestEInvoiceRequestLog(unittest.TestCase):
- pass
diff --git a/erpnext/regional/doctype/e_invoice_settings/__init__.py b/erpnext/regional/doctype/e_invoice_settings/__init__.py
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/erpnext/regional/doctype/e_invoice_settings/e_invoice_settings.js b/erpnext/regional/doctype/e_invoice_settings/e_invoice_settings.js
deleted file mode 100644
index 54e488610d..0000000000
--- a/erpnext/regional/doctype/e_invoice_settings/e_invoice_settings.js
+++ /dev/null
@@ -1,11 +0,0 @@
-// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
-// For license information, please see license.txt
-
-frappe.ui.form.on('E Invoice Settings', {
- refresh(frm) {
- const docs_link = 'https://docs.erpnext.com/docs/v13/user/manual/en/regional/india/setup-e-invoicing';
- frm.dashboard.set_headline(
- __("Read {0} for more information on E Invoicing features.", [`documentation `])
- );
- }
-});
diff --git a/erpnext/regional/doctype/e_invoice_settings/e_invoice_settings.json b/erpnext/regional/doctype/e_invoice_settings/e_invoice_settings.json
deleted file mode 100644
index 68ed3391d0..0000000000
--- a/erpnext/regional/doctype/e_invoice_settings/e_invoice_settings.json
+++ /dev/null
@@ -1,73 +0,0 @@
-{
- "actions": [],
- "creation": "2020-09-24 16:23:16.235722",
- "doctype": "DocType",
- "editable_grid": 1,
- "engine": "InnoDB",
- "field_order": [
- "enable",
- "section_break_2",
- "sandbox_mode",
- "applicable_from",
- "credentials",
- "auth_token",
- "token_expiry"
- ],
- "fields": [
- {
- "default": "0",
- "fieldname": "enable",
- "fieldtype": "Check",
- "label": "Enable"
- },
- {
- "depends_on": "enable",
- "fieldname": "section_break_2",
- "fieldtype": "Section Break"
- },
- {
- "fieldname": "auth_token",
- "fieldtype": "Data",
- "hidden": 1,
- "read_only": 1
- },
- {
- "fieldname": "token_expiry",
- "fieldtype": "Datetime",
- "hidden": 1,
- "read_only": 1
- },
- {
- "fieldname": "credentials",
- "fieldtype": "Table",
- "label": "Credentials",
- "mandatory_depends_on": "enable",
- "options": "E Invoice User"
- },
- {
- "default": "0",
- "fieldname": "sandbox_mode",
- "fieldtype": "Check",
- "label": "Sandbox Mode"
- },
- {
- "fieldname": "applicable_from",
- "fieldtype": "Date",
- "in_list_view": 1,
- "label": "Applicable From",
- "reqd": 1
- }
- ],
- "index_web_pages_for_search": 1,
- "issingle": 1,
- "links": [],
- "modified": "2021-03-30 12:26:25.538294",
- "modified_by": "Administrator",
- "module": "Regional",
- "name": "E Invoice Settings",
- "owner": "Administrator",
- "permissions": [],
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1
-}
\ No newline at end of file
diff --git a/erpnext/regional/doctype/e_invoice_settings/e_invoice_settings.py b/erpnext/regional/doctype/e_invoice_settings/e_invoice_settings.py
deleted file mode 100644
index 4f6b3eca7a..0000000000
--- a/erpnext/regional/doctype/e_invoice_settings/e_invoice_settings.py
+++ /dev/null
@@ -1,13 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
-# For license information, please see license.txt
-from __future__ import unicode_literals
-
-import frappe
-from frappe import _
-from frappe.model.document import Document
-
-class EInvoiceSettings(Document):
- def validate(self):
- if self.enable and not self.credentials:
- frappe.throw(_('You must add atleast one credentials to be able to use E Invoicing.'))
diff --git a/erpnext/regional/doctype/e_invoice_settings/test_e_invoice_settings.py b/erpnext/regional/doctype/e_invoice_settings/test_e_invoice_settings.py
deleted file mode 100644
index a11ce63ee6..0000000000
--- a/erpnext/regional/doctype/e_invoice_settings/test_e_invoice_settings.py
+++ /dev/null
@@ -1,10 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
-# See license.txt
-from __future__ import unicode_literals
-
-# import frappe
-import unittest
-
-class TestEInvoiceSettings(unittest.TestCase):
- pass
diff --git a/erpnext/regional/doctype/e_invoice_user/__init__.py b/erpnext/regional/doctype/e_invoice_user/__init__.py
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/erpnext/regional/doctype/e_invoice_user/e_invoice_user.json b/erpnext/regional/doctype/e_invoice_user/e_invoice_user.json
deleted file mode 100644
index a65b1ca7ca..0000000000
--- a/erpnext/regional/doctype/e_invoice_user/e_invoice_user.json
+++ /dev/null
@@ -1,57 +0,0 @@
-{
- "actions": [],
- "creation": "2020-12-22 15:02:46.229474",
- "doctype": "DocType",
- "editable_grid": 1,
- "engine": "InnoDB",
- "field_order": [
- "company",
- "gstin",
- "username",
- "password"
- ],
- "fields": [
- {
- "fieldname": "gstin",
- "fieldtype": "Data",
- "in_list_view": 1,
- "label": "GSTIN",
- "reqd": 1
- },
- {
- "fieldname": "username",
- "fieldtype": "Data",
- "in_list_view": 1,
- "label": "Username",
- "reqd": 1
- },
- {
- "fieldname": "password",
- "fieldtype": "Password",
- "in_list_view": 1,
- "label": "Password",
- "reqd": 1
- },
- {
- "fieldname": "company",
- "fieldtype": "Link",
- "in_list_view": 1,
- "label": "Company",
- "options": "Company",
- "reqd": 1
- }
- ],
- "index_web_pages_for_search": 1,
- "istable": 1,
- "links": [],
- "modified": "2021-03-22 12:16:56.365616",
- "modified_by": "Administrator",
- "module": "Regional",
- "name": "E Invoice User",
- "owner": "Administrator",
- "permissions": [],
- "quick_entry": 1,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1
-}
\ No newline at end of file
diff --git a/erpnext/regional/doctype/e_invoice_user/e_invoice_user.py b/erpnext/regional/doctype/e_invoice_user/e_invoice_user.py
deleted file mode 100644
index 056c54f069..0000000000
--- a/erpnext/regional/doctype/e_invoice_user/e_invoice_user.py
+++ /dev/null
@@ -1,10 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
-# For license information, please see license.txt
-
-from __future__ import unicode_literals
-# import frappe
-from frappe.model.document import Document
-
-class EInvoiceUser(Document):
- pass
diff --git a/erpnext/regional/india/e_invoice/__init__.py b/erpnext/regional/india/e_invoice/__init__.py
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/erpnext/regional/india/e_invoice/einv_item_template.json b/erpnext/regional/india/e_invoice/einv_item_template.json
deleted file mode 100644
index 78e56518df..0000000000
--- a/erpnext/regional/india/e_invoice/einv_item_template.json
+++ /dev/null
@@ -1,31 +0,0 @@
-{{
- "SlNo": "{item.sr_no}",
- "PrdDesc": "{item.description}",
- "IsServc": "{item.is_service_item}",
- "HsnCd": "{item.gst_hsn_code}",
- "Barcde": "{item.barcode}",
- "Unit": "{item.uom}",
- "Qty": "{item.qty}",
- "FreeQty": "{item.free_qty}",
- "UnitPrice": "{item.unit_rate}",
- "TotAmt": "{item.gross_amount}",
- "Discount": "{item.discount_amount}",
- "AssAmt": "{item.taxable_value}",
- "PrdSlNo": "{item.serial_no}",
- "GstRt": "{item.tax_rate}",
- "IgstAmt": "{item.igst_amount}",
- "CgstAmt": "{item.cgst_amount}",
- "SgstAmt": "{item.sgst_amount}",
- "CesRt": "{item.cess_rate}",
- "CesAmt": "{item.cess_amount}",
- "CesNonAdvlAmt": "{item.cess_nadv_amount}",
- "StateCesRt": "{item.state_cess_rate}",
- "StateCesAmt": "{item.state_cess_amount}",
- "StateCesNonAdvlAmt": "{item.state_cess_nadv_amount}",
- "OthChrg": "{item.other_charges}",
- "TotItemVal": "{item.total_value}",
- "BchDtls": {{
- "Nm": "{item.batch_no}",
- "ExpDt": "{item.batch_expiry_date}"
- }}
-}}
\ No newline at end of file
diff --git a/erpnext/regional/india/e_invoice/einv_template.json b/erpnext/regional/india/e_invoice/einv_template.json
deleted file mode 100644
index 60f490d616..0000000000
--- a/erpnext/regional/india/e_invoice/einv_template.json
+++ /dev/null
@@ -1,110 +0,0 @@
-{{
- "Version": "1.1",
- "TranDtls": {{
- "TaxSch": "{transaction_details.tax_scheme}",
- "SupTyp": "{transaction_details.supply_type}",
- "RegRev": "{transaction_details.reverse_charge}",
- "EcmGstin": "{transaction_details.ecom_gstin}",
- "IgstOnIntra": "{transaction_details.igst_on_intra}"
- }},
- "DocDtls": {{
- "Typ": "{doc_details.invoice_type}",
- "No": "{doc_details.invoice_name}",
- "Dt": "{doc_details.invoice_date}"
- }},
- "SellerDtls": {{
- "Gstin": "{seller_details.gstin}",
- "LglNm": "{seller_details.legal_name}",
- "TrdNm": "{seller_details.trade_name}",
- "Loc": "{seller_details.location}",
- "Pin": "{seller_details.pincode}",
- "Stcd": "{seller_details.state_code}",
- "Addr1": "{seller_details.address_line1}",
- "Addr2": "{seller_details.address_line2}",
- "Ph": "{seller_details.phone}",
- "Em": "{seller_details.email}"
- }},
- "BuyerDtls": {{
- "Gstin": "{buyer_details.gstin}",
- "LglNm": "{buyer_details.legal_name}",
- "TrdNm": "{buyer_details.trade_name}",
- "Addr1": "{buyer_details.address_line1}",
- "Addr2": "{buyer_details.address_line2}",
- "Loc": "{buyer_details.location}",
- "Pin": "{buyer_details.pincode}",
- "Stcd": "{buyer_details.state_code}",
- "Ph": "{buyer_details.phone}",
- "Em": "{buyer_details.email}",
- "Pos": "{buyer_details.place_of_supply}"
- }},
- "DispDtls": {{
- "Nm": "{dispatch_details.company_name}",
- "Addr1": "{dispatch_details.address_line1}",
- "Addr2": "{dispatch_details.address_line2}",
- "Loc": "{dispatch_details.location}",
- "Pin": "{dispatch_details.pincode}",
- "Stcd": "{dispatch_details.state_code}"
- }},
- "ShipDtls": {{
- "Gstin": "{shipping_details.gstin}",
- "LglNm": "{shipping_details.legal_name}",
- "TrdNm": "{shipping_details.trader_name}",
- "Addr1": "{shipping_details.address_line1}",
- "Addr2": "{shipping_details.address_line2}",
- "Loc": "{shipping_details.location}",
- "Pin": "{shipping_details.pincode}",
- "Stcd": "{shipping_details.state_code}"
- }},
- "ItemList": [
- {item_list}
- ],
- "ValDtls": {{
- "AssVal": "{invoice_value_details.base_total}",
- "CgstVal": "{invoice_value_details.total_cgst_amt}",
- "SgstVal": "{invoice_value_details.total_sgst_amt}",
- "IgstVal": "{invoice_value_details.total_igst_amt}",
- "CesVal": "{invoice_value_details.total_cess_amt}",
- "Discount": "{invoice_value_details.invoice_discount_amt}",
- "RndOffAmt": "{invoice_value_details.round_off}",
- "OthChrg": "{invoice_value_details.total_other_charges}",
- "TotInvVal": "{invoice_value_details.base_grand_total}",
- "TotInvValFc": "{invoice_value_details.grand_total}"
- }},
- "PayDtls": {{
- "Nm": "{payment_details.payee_name}",
- "AccDet": "{payment_details.account_no}",
- "Mode": "{payment_details.mode_of_payment}",
- "FinInsBr": "{payment_details.ifsc_code}",
- "PayTerm": "{payment_details.terms}",
- "PaidAmt": "{payment_details.paid_amount}",
- "PaymtDue": "{payment_details.outstanding_amount}"
- }},
- "RefDtls": {{
- "DocPerdDtls": {{
- "InvStDt": "{period_details.start_date}",
- "InvEndDt": "{period_details.end_date}"
- }},
- "PrecDocDtls": [{{
- "InvNo": "{prev_doc_details.invoice_name}",
- "InvDt": "{prev_doc_details.invoice_date}"
- }}]
- }},
- "ExpDtls": {{
- "ShipBNo": "{export_details.bill_no}",
- "ShipBDt": "{export_details.bill_date}",
- "Port": "{export_details.port}",
- "ForCur": "{export_details.foreign_curr_code}",
- "CntCode": "{export_details.country_code}",
- "ExpDuty": "{export_details.export_duty}"
- }},
- "EwbDtls": {{
- "TransId": "{eway_bill_details.gstin}",
- "TransName": "{eway_bill_details.name}",
- "TransMode": "{eway_bill_details.mode_of_transport}",
- "Distance": "{eway_bill_details.distance}",
- "TransDocNo": "{eway_bill_details.document_name}",
- "TransDocDt": "{eway_bill_details.document_date}",
- "VehNo": "{eway_bill_details.vehicle_no}",
- "VehType": "{eway_bill_details.vehicle_type}"
- }}
-}}
\ No newline at end of file
diff --git a/erpnext/regional/india/e_invoice/einv_validation.json b/erpnext/regional/india/e_invoice/einv_validation.json
deleted file mode 100644
index f4a3542a60..0000000000
--- a/erpnext/regional/india/e_invoice/einv_validation.json
+++ /dev/null
@@ -1,957 +0,0 @@
-{
- "Version": {
- "type": "string",
- "minLength": 1,
- "maxLength": 6,
- "description": "Version of the schema"
- },
- "Irn": {
- "type": "string",
- "minLength": 64,
- "maxLength": 64,
- "description": "Invoice Reference Number"
- },
- "TranDtls": {
- "type": "object",
- "properties": {
- "TaxSch": {
- "type": "string",
- "minLength": 3,
- "maxLength": 10,
- "enum": ["GST"],
- "description": "GST- Goods and Services Tax Scheme"
- },
- "SupTyp": {
- "type": "string",
- "minLength": 3,
- "maxLength": 10,
- "enum": ["B2B", "SEZWP", "SEZWOP", "EXPWP", "EXPWOP", "DEXP"],
- "description": "Type of Supply: B2B-Business to Business, SEZWP - SEZ with payment, SEZWOP - SEZ without payment, EXPWP - Export with Payment, EXPWOP - Export without payment,DEXP - Deemed Export"
- },
- "RegRev": {
- "type": "string",
- "minLength": 1,
- "maxLength": 1,
- "enum": ["Y", "N"],
- "description": "Y- whether the tax liability is payable under reverse charge"
- },
- "EcmGstin": {
- "type": "string",
- "minLength": 15,
- "maxLength": 15,
- "pattern": "([0-9]{2}[0-9A-Z]{13})",
- "description": "E-Commerce GSTIN",
- "validationMsg": "E-Commerce GSTIN is invalid"
- },
- "IgstOnIntra": {
- "type": "string",
- "minLength": 1,
- "maxLength": 1,
- "enum": ["Y", "N"],
- "description": "Y- indicates the supply is intra state but chargeable to IGST"
- }
- },
- "required": ["TaxSch", "SupTyp"]
- },
- "DocDtls": {
- "type": "object",
- "properties": {
- "Typ": {
- "type": "string",
- "minLength": 3,
- "maxLength": 3,
- "enum": ["INV", "CRN", "DBN"],
- "description": "Document Type"
- },
- "No": {
- "type": "string",
- "minLength": 1,
- "maxLength": 16,
- "pattern": "^([A-Z1-9]{1}[A-Z0-9/-]{0,15})$",
- "description": "Document Number",
- "validationMsg": "Document Number should not be starting with 0, / and -"
- },
- "Dt": {
- "type": "string",
- "minLength": 10,
- "maxLength": 10,
- "pattern": "[0-3][0-9]/[0-1][0-9]/[2][0][1-2][0-9]",
- "description": "Document Date"
- }
- },
- "required": ["Typ", "No", "Dt"]
- },
- "SellerDtls": {
- "type": "object",
- "properties": {
- "Gstin": {
- "type": "string",
- "minLength": 15,
- "maxLength": 15,
- "pattern": "([0-9]{2}[0-9A-Z]{13})",
- "description": "Supplier GSTIN",
- "validationMsg": "Company GSTIN is invalid"
- },
- "LglNm": {
- "type": "string",
- "minLength": 3,
- "maxLength": 100,
- "description": "Legal Name"
- },
- "TrdNm": {
- "type": "string",
- "minLength": 3,
- "maxLength": 100,
- "description": "Tradename"
- },
- "Addr1": {
- "type": "string",
- "minLength": 1,
- "maxLength": 100,
- "description": "Address Line 1"
- },
- "Addr2": {
- "type": "string",
- "minLength": 3,
- "maxLength": 100,
- "description": "Address Line 2"
- },
- "Loc": {
- "type": "string",
- "minLength": 3,
- "maxLength": 50,
- "description": "Location"
- },
- "Pin": {
- "type": "number",
- "minimum": 100000,
- "maximum": 999999,
- "description": "Pincode"
- },
- "Stcd": {
- "type": "string",
- "minLength": 1,
- "maxLength": 2,
- "description": "Supplier State Code"
- },
- "Ph": {
- "type": "string",
- "minLength": 6,
- "maxLength": 12,
- "description": "Phone"
- },
- "Em": {
- "type": "string",
- "minLength": 6,
- "maxLength": 100,
- "description": "Email-Id"
- }
- },
- "required": ["Gstin", "LglNm", "Addr1", "Loc", "Pin", "Stcd"]
- },
- "BuyerDtls": {
- "type": "object",
- "properties": {
- "Gstin": {
- "type": "string",
- "minLength": 3,
- "maxLength": 15,
- "pattern": "^(([0-9]{2}[0-9A-Z]{13})|URP)$",
- "description": "Buyer GSTIN",
- "validationMsg": "Customer GSTIN is invalid"
- },
- "LglNm": {
- "type": "string",
- "minLength": 3,
- "maxLength": 100,
- "description": "Legal Name"
- },
- "TrdNm": {
- "type": "string",
- "minLength": 3,
- "maxLength": 100,
- "description": "Trade Name"
- },
- "Pos": {
- "type": "string",
- "minLength": 1,
- "maxLength": 2,
- "description": "Place of Supply State code"
- },
- "Addr1": {
- "type": "string",
- "minLength": 1,
- "maxLength": 100,
- "description": "Address Line 1"
- },
- "Addr2": {
- "type": "string",
- "minLength": 3,
- "maxLength": 100,
- "description": "Address Line 2"
- },
- "Loc": {
- "type": "string",
- "minLength": 3,
- "maxLength": 100,
- "description": "Location"
- },
- "Pin": {
- "type": "number",
- "minimum": 100000,
- "maximum": 999999,
- "description": "Pincode"
- },
- "Stcd": {
- "type": "string",
- "minLength": 1,
- "maxLength": 2,
- "description": "Buyer State Code"
- },
- "Ph": {
- "type": "string",
- "minLength": 6,
- "maxLength": 12,
- "description": "Phone"
- },
- "Em": {
- "type": "string",
- "minLength": 6,
- "maxLength": 100,
- "description": "Email-Id"
- }
- },
- "required": ["Gstin", "LglNm", "Pos", "Addr1", "Loc", "Stcd"]
- },
- "DispDtls": {
- "type": "object",
- "properties": {
- "Nm": {
- "type": "string",
- "minLength": 3,
- "maxLength": 100,
- "description": "Dispatch Address Name"
- },
- "Addr1": {
- "type": "string",
- "minLength": 1,
- "maxLength": 100,
- "description": "Address Line 1"
- },
- "Addr2": {
- "type": "string",
- "minLength": 3,
- "maxLength": 100,
- "description": "Address Line 2"
- },
- "Loc": {
- "type": "string",
- "minLength": 3,
- "maxLength": 100,
- "description": "Location"
- },
- "Pin": {
- "type": "number",
- "minimum": 100000,
- "maximum": 999999,
- "description": "Pincode"
- },
- "Stcd": {
- "type": "string",
- "minLength": 1,
- "maxLength": 2,
- "description": "State Code"
- }
- },
- "required": ["Nm", "Addr1", "Loc", "Pin", "Stcd"]
- },
- "ShipDtls": {
- "type": "object",
- "properties": {
- "Gstin": {
- "type": "string",
- "maxLength": 15,
- "minLength": 3,
- "pattern": "^(([0-9]{2}[0-9A-Z]{13})|URP)$",
- "description": "Shipping Address GSTIN",
- "validationMsg": "Shipping Address GSTIN is invalid"
- },
- "LglNm": {
- "type": "string",
- "minLength": 3,
- "maxLength": 100,
- "description": "Legal Name"
- },
- "TrdNm": {
- "type": "string",
- "minLength": 3,
- "maxLength": 100,
- "description": "Trade Name"
- },
- "Addr1": {
- "type": "string",
- "minLength": 1,
- "maxLength": 100,
- "description": "Address Line 1"
- },
- "Addr2": {
- "type": "string",
- "minLength": 3,
- "maxLength": 100,
- "description": "Address Line 2"
- },
- "Loc": {
- "type": "string",
- "minLength": 3,
- "maxLength": 100,
- "description": "Location"
- },
- "Pin": {
- "type": "number",
- "minimum": 100000,
- "maximum": 999999,
- "description": "Pincode"
- },
- "Stcd": {
- "type": "string",
- "minLength": 1,
- "maxLength": 2,
- "description": "State Code"
- }
- },
- "required": ["LglNm", "Addr1", "Loc", "Pin", "Stcd"]
- },
- "ItemList": {
- "type": "Array",
- "properties": {
- "SlNo": {
- "type": "string",
- "minLength": 1,
- "maxLength": 6,
- "description": "Serial No. of Item"
- },
- "PrdDesc": {
- "type": "string",
- "minLength": 3,
- "maxLength": 300,
- "description": "Item Name"
- },
- "IsServc": {
- "type": "string",
- "minLength": 1,
- "maxLength": 1,
- "enum": ["Y", "N"],
- "description": "Is Service Item"
- },
- "HsnCd": {
- "type": "string",
- "minLength": 4,
- "maxLength": 8,
- "description": "HSN Code"
- },
- "Barcde": {
- "type": "string",
- "minLength": 3,
- "maxLength": 30,
- "description": "Barcode"
- },
- "Qty": {
- "type": "number",
- "minimum": 0,
- "maximum": 9999999999.999,
- "description": "Quantity"
- },
- "FreeQty": {
- "type": "number",
- "minimum": 0,
- "maximum": 9999999999.999,
- "description": "Free Quantity"
- },
- "Unit": {
- "type": "string",
- "minLength": 3,
- "maxLength": 8,
- "description": "UOM"
- },
- "UnitPrice": {
- "type": "number",
- "minimum": 0,
- "maximum": 999999999999.999,
- "description": "Rate"
- },
- "TotAmt": {
- "type": "number",
- "minimum": 0,
- "maximum": 999999999999.99,
- "description": "Gross Amount"
- },
- "Discount": {
- "type": "number",
- "minimum": 0,
- "maximum": 999999999999.99,
- "description": "Discount"
- },
- "PreTaxVal": {
- "type": "number",
- "minimum": 0,
- "maximum": 999999999999.99,
- "description": "Pre tax value"
- },
- "AssAmt": {
- "type": "number",
- "minimum": 0,
- "maximum": 999999999999.99,
- "description": "Taxable Value"
- },
- "GstRt": {
- "type": "number",
- "minimum": 0,
- "maximum": 999.999,
- "description": "GST Rate"
- },
- "IgstAmt": {
- "type": "number",
- "minimum": 0,
- "maximum": 999999999999.99,
- "description": "IGST Amount"
- },
- "CgstAmt": {
- "type": "number",
- "minimum": 0,
- "maximum": 999999999999.99,
- "description": "CGST Amount"
- },
- "SgstAmt": {
- "type": "number",
- "minimum": 0,
- "maximum": 999999999999.99,
- "description": "SGST Amount"
- },
- "CesRt": {
- "type": "number",
- "minimum": 0,
- "maximum": 999.999,
- "description": "Cess Rate"
- },
- "CesAmt": {
- "type": "number",
- "minimum": 0,
- "maximum": 999999999999.99,
- "description": "Cess Amount (Advalorem)"
- },
- "CesNonAdvlAmt": {
- "type": "number",
- "minimum": 0,
- "maximum": 999999999999.99,
- "description": "Cess Amount (Non-Advalorem)"
- },
- "StateCesRt": {
- "type": "number",
- "minimum": 0,
- "maximum": 999.999,
- "description": "State CESS Rate"
- },
- "StateCesAmt": {
- "type": "number",
- "minimum": 0,
- "maximum": 999999999999.99,
- "description": "State CESS Amount"
- },
- "StateCesNonAdvlAmt": {
- "type": "number",
- "minimum": 0,
- "maximum": 999999999999.99,
- "description": "State CESS Amount (Non Advalorem)"
- },
- "OthChrg": {
- "type": "number",
- "minimum": 0,
- "maximum": 999999999999.99,
- "description": "Other Charges"
- },
- "TotItemVal": {
- "type": "number",
- "minimum": 0,
- "maximum": 999999999999.99,
- "description": "Total Item Value"
- },
- "OrdLineRef": {
- "type": "string",
- "minLength": 1,
- "maxLength": 50,
- "description": "Order line reference"
- },
- "OrgCntry": {
- "type": "string",
- "minLength": 2,
- "maxLength": 2,
- "description": "Origin Country"
- },
- "PrdSlNo": {
- "type": "string",
- "minLength": 1,
- "maxLength": 20,
- "description": "Serial number"
- },
- "BchDtls": {
- "type": "object",
- "properties": {
- "Nm": {
- "type": "string",
- "minLength": 3,
- "maxLength": 20,
- "description": "Batch number"
- },
- "ExpDt": {
- "type": "string",
- "maxLength": 10,
- "minLength": 10,
- "pattern": "[0-3][0-9]/[0-1][0-9]/[2][0][1-2][0-9]",
- "description": "Batch Expiry Date"
- },
- "WrDt": {
- "type": "string",
- "maxLength": 10,
- "minLength": 10,
- "pattern": "[0-3][0-9]/[0-1][0-9]/[2][0][1-2][0-9]",
- "description": "Warranty Date"
- }
- },
- "required": ["Nm"]
- },
- "AttribDtls": {
- "type": "Array",
- "Attribute": {
- "type": "object",
- "properties": {
- "Nm": {
- "type": "string",
- "minLength": 1,
- "maxLength": 100,
- "description": "Attribute name of the item"
- },
- "Val": {
- "type": "string",
- "minLength": 1,
- "maxLength": 100,
- "description": "Attribute value of the item"
- }
- }
- }
- }
- },
- "required": [
- "SlNo",
- "IsServc",
- "HsnCd",
- "UnitPrice",
- "TotAmt",
- "AssAmt",
- "GstRt",
- "TotItemVal"
- ]
- },
- "ValDtls": {
- "type": "object",
- "properties": {
- "AssVal": {
- "type": "number",
- "minimum": 0,
- "maximum": 99999999999999.99,
- "description": "Total Assessable value of all items"
- },
- "CgstVal": {
- "type": "number",
- "maximum": 99999999999999.99,
- "minimum": 0,
- "description": "Total CGST value of all items"
- },
- "SgstVal": {
- "type": "number",
- "minimum": 0,
- "maximum": 99999999999999.99,
- "description": "Total SGST value of all items"
- },
- "IgstVal": {
- "type": "number",
- "minimum": 0,
- "maximum": 99999999999999.99,
- "description": "Total IGST value of all items"
- },
- "CesVal": {
- "type": "number",
- "minimum": 0,
- "maximum": 99999999999999.99,
- "description": "Total CESS value of all items"
- },
- "StCesVal": {
- "type": "number",
- "minimum": 0,
- "maximum": 99999999999999.99,
- "description": "Total State CESS value of all items"
- },
- "Discount": {
- "type": "number",
- "minimum": 0,
- "maximum": 99999999999999.99,
- "description": "Invoice Discount"
- },
- "OthChrg": {
- "type": "number",
- "minimum": 0,
- "maximum": 99999999999999.99,
- "description": "Other Charges"
- },
- "RndOffAmt": {
- "type": "number",
- "minimum": -99.99,
- "maximum": 99.99,
- "description": "Rounded off Amount"
- },
- "TotInvVal": {
- "type": "number",
- "minimum": 0,
- "maximum": 99999999999999.99,
- "description": "Final Invoice Value "
- },
- "TotInvValFc": {
- "type": "number",
- "minimum": 0,
- "maximum": 99999999999999.99,
- "description": "Final Invoice value in Foreign Currency"
- }
- },
- "required": ["AssVal", "TotInvVal"]
- },
- "PayDtls": {
- "type": "object",
- "properties": {
- "Nm": {
- "type": "string",
- "minLength": 1,
- "maxLength": 100,
- "description": "Payee Name"
- },
- "AccDet": {
- "type": "string",
- "minLength": 1,
- "maxLength": 18,
- "description": "Bank Account Number of Payee"
- },
- "Mode": {
- "type": "string",
- "minLength": 1,
- "maxLength": 18,
- "description": "Mode of Payment"
- },
- "FinInsBr": {
- "type": "string",
- "minLength": 1,
- "maxLength": 11,
- "description": "Branch or IFSC code"
- },
- "PayTerm": {
- "type": "string",
- "minLength": 1,
- "maxLength": 100,
- "description": "Terms of Payment"
- },
- "PayInstr": {
- "type": "string",
- "minLength": 1,
- "maxLength": 100,
- "description": "Payment Instruction"
- },
- "CrTrn": {
- "type": "string",
- "minLength": 1,
- "maxLength": 100,
- "description": "Credit Transfer"
- },
- "DirDr": {
- "type": "string",
- "minLength": 1,
- "maxLength": 100,
- "description": "Direct Debit"
- },
- "CrDay": {
- "type": "number",
- "minimum": 0,
- "maximum": 9999,
- "description": "Credit Days"
- },
- "PaidAmt": {
- "type": "number",
- "minimum": 0,
- "maximum": 99999999999999.99,
- "description": "Advance Amount"
- },
- "PaymtDue": {
- "type": "number",
- "minimum": 0,
- "maximum": 99999999999999.99,
- "description": "Outstanding Amount"
- }
- }
- },
- "RefDtls": {
- "type": "object",
- "properties": {
- "InvRm": {
- "type": "string",
- "maxLength": 100,
- "minLength": 3,
- "pattern": "^[0-9A-Za-z/-]{3,100}$",
- "description": "Remarks/Note"
- },
- "DocPerdDtls": {
- "type": "object",
- "properties": {
- "InvStDt": {
- "type": "string",
- "maxLength": 10,
- "minLength": 10,
- "pattern": "[0-3][0-9]/[0-1][0-9]/[2][0][1-2][0-9]",
- "description": "Invoice Period Start Date"
- },
- "InvEndDt": {
- "type": "string",
- "maxLength": 10,
- "minLength": 10,
- "pattern": "[0-3][0-9]/[0-1][0-9]/[2][0][1-2][0-9]",
- "description": "Invoice Period End Date"
- }
- },
- "required": ["InvStDt ", "InvEndDt "]
- },
- "PrecDocDtls": {
- "type": "object",
- "properties": {
- "InvNo": {
- "type": "string",
- "minLength": 1,
- "maxLength": 16,
- "pattern": "^[1-9A-Z]{1}[0-9A-Z/-]{1,15}$",
- "description": "Reference of Original Invoice"
- },
- "InvDt": {
- "type": "string",
- "maxLength": 10,
- "minLength": 10,
- "pattern": "[0-3][0-9]/[0-1][0-9]/[2][0][1-2][0-9]",
- "description": "Date of Orginal Invoice"
- },
- "OthRefNo": {
- "type": "string",
- "minLength": 1,
- "maxLength": 20,
- "description": "Other Reference"
- }
- }
- },
- "required": ["InvNo", "InvDt"],
- "ContrDtls": {
- "type": "object",
- "properties": {
- "RecAdvRefr": {
- "type": "string",
- "minLength": 1,
- "maxLength": 20,
- "pattern": "^([0-9A-Za-z/-]){1,20}$",
- "description": "Receipt Advice No."
- },
- "RecAdvDt": {
- "type": "string",
- "minLength": 10,
- "maxLength": 10,
- "pattern": "[0-3][0-9]/[0-1][0-9]/[2][0][1-2][0-9]",
- "description": "Date of receipt advice"
- },
- "TendRefr": {
- "type": "string",
- "minLength": 1,
- "maxLength": 20,
- "pattern": "^([0-9A-Za-z/-]){1,20}$",
- "description": "Lot/Batch Reference No."
- },
- "ContrRefr": {
- "type": "string",
- "minLength": 1,
- "maxLength": 20,
- "pattern": "^([0-9A-Za-z/-]){1,20}$",
- "description": "Contract Reference Number"
- },
- "ExtRefr": {
- "type": "string",
- "minLength": 1,
- "maxLength": 20,
- "pattern": "^([0-9A-Za-z/-]){1,20}$",
- "description": "Any other reference"
- },
- "ProjRefr": {
- "type": "string",
- "minLength": 1,
- "maxLength": 20,
- "pattern": "^([0-9A-Za-z/-]){1,20}$",
- "description": "Project Reference Number"
- },
- "PORefr": {
- "type": "string",
- "minLength": 1,
- "maxLength": 16,
- "pattern": "^([0-9A-Za-z/-]){1,16}$",
- "description": "PO Reference Number"
- },
- "PORefDt": {
- "type": "string",
- "minLength": 10,
- "maxLength": 10,
- "pattern": "[0-3][0-9]/[0-1][0-9]/[2][0][1-2][0-9]",
- "description": "PO Reference date"
- }
- }
- }
- }
- },
- "AddlDocDtls": {
- "type": "Array",
- "properties": {
- "Url": {
- "type": "string",
- "minLength": 3,
- "maxLength": 100,
- "description": "Supporting document URL"
- },
- "Docs": {
- "type": "string",
- "minLength": 3,
- "maxLength": 1000,
- "description": "Supporting document in Base64 Format"
- },
- "Info": {
- "type": "string",
- "minLength": 3,
- "maxLength": 1000,
- "description": "Any additional information"
- }
- }
- },
-
- "ExpDtls": {
- "type": "object",
- "properties": {
- "ShipBNo": {
- "type": "string",
- "minLength": 1,
- "maxLength": 20,
- "description": "Shipping Bill No."
- },
- "ShipBDt": {
- "type": "string",
- "minLength": 10,
- "maxLength": 10,
- "pattern": "[0-3][0-9]/[0-1][0-9]/[2][0][1-2][0-9]",
- "description": "Shipping Bill Date"
- },
- "Port": {
- "type": "string",
- "minLength": 2,
- "maxLength": 10,
- "pattern": "^[0-9A-Za-z]{2,10}$",
- "description": "Port Code. Refer the master"
- },
- "RefClm": {
- "type": "string",
- "minLength": 1,
- "maxLength": 1,
- "description": "Claiming Refund. Y/N"
- },
- "ForCur": {
- "type": "string",
- "minLength": 3,
- "maxLength": 16,
- "description": "Additional Currency Code. Refer the master"
- },
- "CntCode": {
- "type": "string",
- "minLength": 2,
- "maxLength": 2,
- "description": "Country Code. Refer the master"
- },
- "ExpDuty": {
- "type": "number",
- "minimum": 0,
- "maximum": 999999999999.99,
- "description": "Export Duty"
- }
- }
- },
- "EwbDtls": {
- "type": "object",
- "properties": {
- "TransId": {
- "type": "string",
- "minLength": 15,
- "maxLength": 15,
- "description": "Transporter GSTIN"
- },
- "TransName": {
- "type": "string",
- "minLength": 3,
- "maxLength": 100,
- "description": "Transporter Name"
- },
- "TransMode": {
- "type": "string",
- "maxLength": 1,
- "minLength": 1,
- "enum": ["1", "2", "3", "4"],
- "description": "Mode of Transport"
- },
- "Distance": {
- "type": "number",
- "minimum": 1,
- "maximum": 9999,
- "description": "Distance"
- },
- "TransDocNo": {
- "type": "string",
- "minLength": 1,
- "maxLength": 15,
- "pattern": "^([0-9A-Z/-]){1,15}$",
- "description": "Tranport Document Number",
- "validationMsg": "Transport Receipt No is invalid"
- },
- "TransDocDt": {
- "type": "string",
- "minLength": 10,
- "maxLength": 10,
- "pattern": "[0-3][0-9]/[0-1][0-9]/[2][0][1-2][0-9]",
- "description": "Transport Document Date"
- },
- "VehNo": {
- "type": "string",
- "minLength": 4,
- "maxLength": 20,
- "description": "Vehicle Number"
- },
- "VehType": {
- "type": "string",
- "minLength": 1,
- "maxLength": 1,
- "enum": ["O", "R"],
- "description": "Vehicle Type"
- }
- },
- "required": ["Distance"]
- },
- "required": [
- "Version",
- "TranDtls",
- "DocDtls",
- "SellerDtls",
- "BuyerDtls",
- "ItemList",
- "ValDtls"
- ]
-}
diff --git a/erpnext/regional/india/e_invoice/einvoice.js b/erpnext/regional/india/e_invoice/einvoice.js
deleted file mode 100644
index 348f0c6fee..0000000000
--- a/erpnext/regional/india/e_invoice/einvoice.js
+++ /dev/null
@@ -1,292 +0,0 @@
-erpnext.setup_einvoice_actions = (doctype) => {
- frappe.ui.form.on(doctype, {
- async refresh(frm) {
- if (frm.doc.docstatus == 2) return;
-
- const res = await frappe.call({
- method: 'erpnext.regional.india.e_invoice.utils.validate_eligibility',
- args: { doc: frm.doc }
- });
- const invoice_eligible = res.message;
-
- if (!invoice_eligible) return;
-
- const { doctype, irn, irn_cancelled, ewaybill, eway_bill_cancelled, name, __unsaved } = frm.doc;
-
- const add_custom_button = (label, action) => {
- if (!frm.custom_buttons[label]) {
- frm.add_custom_button(label, action, __('E Invoicing'));
- }
- };
-
- if (!irn && !__unsaved) {
- const action = () => {
- if (frm.doc.__unsaved) {
- frappe.throw(__('Please save the document to generate IRN.'));
- }
- frappe.call({
- method: 'erpnext.regional.india.e_invoice.utils.get_einvoice',
- args: { doctype, docname: name },
- freeze: true,
- callback: (res) => {
- const einvoice = res.message;
- show_einvoice_preview(frm, einvoice);
- }
- });
- };
-
- add_custom_button(__("Generate IRN"), action);
- }
-
- if (irn && !irn_cancelled && !ewaybill) {
- const fields = [
- {
- "label": "Reason",
- "fieldname": "reason",
- "fieldtype": "Select",
- "reqd": 1,
- "default": "1-Duplicate",
- "options": ["1-Duplicate", "2-Data Entry Error", "3-Order Cancelled", "4-Other"]
- },
- {
- "label": "Remark",
- "fieldname": "remark",
- "fieldtype": "Data",
- "reqd": 1
- }
- ];
- const action = () => {
- const d = new frappe.ui.Dialog({
- title: __("Cancel IRN"),
- fields: fields,
- primary_action: function() {
- const data = d.get_values();
- frappe.call({
- method: 'erpnext.regional.india.e_invoice.utils.cancel_irn',
- args: {
- doctype,
- docname: name,
- irn: irn,
- reason: data.reason.split('-')[0],
- remark: data.remark
- },
- freeze: true,
- callback: () => frm.reload_doc() || d.hide(),
- error: () => d.hide()
- });
- },
- primary_action_label: __('Submit')
- });
- d.show();
- };
- add_custom_button(__("Cancel IRN"), action);
- }
-
- if (irn && !irn_cancelled && !ewaybill) {
- const action = () => {
- const d = new frappe.ui.Dialog({
- title: __('Generate E-Way Bill'),
- size: "large",
- fields: get_ewaybill_fields(frm),
- primary_action: function() {
- const data = d.get_values();
- frappe.call({
- method: 'erpnext.regional.india.e_invoice.utils.generate_eway_bill',
- args: {
- doctype,
- docname: name,
- irn,
- ...data
- },
- freeze: true,
- callback: () => frm.reload_doc() || d.hide(),
- error: () => d.hide()
- });
- },
- primary_action_label: __('Submit')
- });
- d.show();
- };
-
- add_custom_button(__("Generate E-Way Bill"), action);
- }
-
- if (irn && ewaybill && !irn_cancelled && !eway_bill_cancelled) {
- const action = () => {
- let message = __('Cancellation of e-way bill is currently not supported.') + ' ';
- message += ' ';
- message += __('You must first use the portal to cancel the e-way bill and then update the cancelled status in the ERPNext system.');
-
- const dialog = frappe.msgprint({
- title: __('Update E-Way Bill Cancelled Status?'),
- message: message,
- indicator: 'orange',
- primary_action: {
- action: function() {
- frappe.call({
- method: 'erpnext.regional.india.e_invoice.utils.cancel_eway_bill',
- args: { doctype, docname: name },
- freeze: true,
- callback: () => frm.reload_doc() || dialog.hide()
- });
- }
- },
- primary_action_label: __('Yes')
- });
- };
- add_custom_button(__("Cancel E-Way Bill"), action);
- }
- }
- });
-};
-
-const get_ewaybill_fields = (frm) => {
- return [
- {
- 'fieldname': 'transporter',
- 'label': 'Transporter',
- 'fieldtype': 'Link',
- 'options': 'Supplier',
- 'default': frm.doc.transporter
- },
- {
- 'fieldname': 'gst_transporter_id',
- 'label': 'GST Transporter ID',
- 'fieldtype': 'Data',
- 'fetch_from': 'transporter.gst_transporter_id',
- 'default': frm.doc.gst_transporter_id
- },
- {
- 'fieldname': 'driver',
- 'label': 'Driver',
- 'fieldtype': 'Link',
- 'options': 'Driver',
- 'default': frm.doc.driver
- },
- {
- 'fieldname': 'lr_no',
- 'label': 'Transport Receipt No',
- 'fieldtype': 'Data',
- 'default': frm.doc.lr_no
- },
- {
- 'fieldname': 'vehicle_no',
- 'label': 'Vehicle No',
- 'fieldtype': 'Data',
- 'default': frm.doc.vehicle_no
- },
- {
- 'fieldname': 'distance',
- 'label': 'Distance (in km)',
- 'fieldtype': 'Float',
- 'default': frm.doc.distance
- },
- {
- 'fieldname': 'transporter_col_break',
- 'fieldtype': 'Column Break',
- },
- {
- 'fieldname': 'transporter_name',
- 'label': 'Transporter Name',
- 'fieldtype': 'Data',
- 'fetch_from': 'transporter.name',
- 'read_only': 1,
- 'default': frm.doc.transporter_name
- },
- {
- 'fieldname': 'mode_of_transport',
- 'label': 'Mode of Transport',
- 'fieldtype': 'Select',
- 'options': `\nRoad\nAir\nRail\nShip`,
- 'default': frm.doc.mode_of_transport
- },
- {
- 'fieldname': 'driver_name',
- 'label': 'Driver Name',
- 'fieldtype': 'Data',
- 'fetch_from': 'driver.full_name',
- 'read_only': 1,
- 'default': frm.doc.driver_name
- },
- {
- 'fieldname': 'lr_date',
- 'label': 'Transport Receipt Date',
- 'fieldtype': 'Date',
- 'default': frm.doc.lr_date
- },
- {
- 'fieldname': 'gst_vehicle_type',
- 'label': 'GST Vehicle Type',
- 'fieldtype': 'Select',
- 'options': `Regular\nOver Dimensional Cargo (ODC)`,
- 'depends_on': 'eval:(doc.mode_of_transport === "Road")',
- 'default': frm.doc.gst_vehicle_type
- }
- ];
-};
-
-const request_irn_generation = (frm) => {
- frappe.call({
- method: 'erpnext.regional.india.e_invoice.utils.generate_irn',
- args: { doctype: frm.doc.doctype, docname: frm.doc.name },
- freeze: true,
- callback: () => frm.reload_doc()
- });
-};
-
-const get_preview_dialog = (frm, action) => {
- const dialog = new frappe.ui.Dialog({
- title: __("Preview"),
- size: "large",
- fields: [
- {
- "label": "Preview",
- "fieldname": "preview_html",
- "fieldtype": "HTML"
- }
- ],
- primary_action: () => action(frm) || dialog.hide(),
- primary_action_label: __('Generate IRN')
- });
- return dialog;
-};
-
-const show_einvoice_preview = (frm, einvoice) => {
- const preview_dialog = get_preview_dialog(frm, request_irn_generation);
-
- // initialize e-invoice fields
- einvoice["Irn"] = einvoice["AckNo"] = ''; einvoice["AckDt"] = frappe.datetime.nowdate();
- frm.doc.signed_einvoice = JSON.stringify(einvoice);
-
- // initialize preview wrapper
- const $preview_wrapper = preview_dialog.get_field("preview_html").$wrapper;
- $preview_wrapper.html(
- ``
- );
-
- frappe.call({
- method: "frappe.www.printview.get_html_and_style",
- args: {
- doc: frm.doc,
- print_format: "GST E-Invoice",
- no_letterhead: 1
- },
- callback: function (r) {
- if (!r.exc) {
- $preview_wrapper.find(".print-format").html(r.message.html);
- const style = `
- .print-format { box-shadow: 0px 0px 5px rgba(0,0,0,0.2); padding: 0.30in; min-height: 80vh; }
- .print-preview { min-height: 0px; }
- .modal-dialog { width: 720px; }`;
-
- frappe.dom.set_style(style, "custom-print-style");
- preview_dialog.show();
- }
- }
- });
-};
diff --git a/erpnext/regional/india/setup.py b/erpnext/regional/india/setup.py
index 2d6b913390..a6ab6aba77 100644
--- a/erpnext/regional/india/setup.py
+++ b/erpnext/regional/india/setup.py
@@ -61,7 +61,7 @@ def create_hsn_codes(data, code_field):
def add_custom_roles_for_reports():
for report_name in ('GST Sales Register', 'GST Purchase Register',
- 'GST Itemised Sales Register', 'GST Itemised Purchase Register', 'Eway Bill', 'E-Invoice Summary'):
+ 'GST Itemised Sales Register', 'GST Itemised Purchase Register', 'Eway Bill'):
if not frappe.db.get_value('Custom Role', dict(report=report_name)):
frappe.get_doc(dict(
@@ -100,7 +100,7 @@ def add_custom_roles_for_reports():
)).insert()
def add_permissions():
- for doctype in ('GST HSN Code', 'GST Settings', 'GSTR 3B Report', 'Lower Deduction Certificate', 'E Invoice Settings'):
+ for doctype in ('GST HSN Code', 'GST Settings', 'GSTR 3B Report', 'Lower Deduction Certificate'):
add_permission(doctype, 'All', 0)
for role in ('Accounts Manager', 'Accounts User', 'System Manager'):
add_permission(doctype, role, 0)
@@ -116,11 +116,9 @@ def add_permissions():
def add_print_formats():
frappe.reload_doc("regional", "print_format", "gst_tax_invoice")
frappe.reload_doc("accounts", "print_format", "gst_pos_invoice")
- frappe.reload_doc("accounts", "print_format", "GST E-Invoice")
frappe.db.set_value("Print Format", "GST POS Invoice", "disabled", 0)
frappe.db.set_value("Print Format", "GST Tax Invoice", "disabled", 0)
- frappe.db.set_value("Print Format", "GST E-Invoice", "disabled", 0)
def make_property_setters(patch=False):
# GST rules do not allow for an invoice no. bigger than 16 characters
@@ -445,53 +443,13 @@ def make_custom_fields(update=True):
'fieldname': 'ewaybill',
'label': 'E-Way Bill No.',
'fieldtype': 'Data',
- 'depends_on': 'eval:((doc.docstatus === 1 || doc.ewaybill) && doc.eway_bill_cancelled === 0)',
+ 'depends_on': 'eval:(doc.docstatus === 1)',
'allow_on_submit': 1,
'insert_after': 'tax_id',
'translatable': 0
}
]
- si_einvoice_fields = [
- dict(fieldname='irn', label='IRN', fieldtype='Data', read_only=1, insert_after='customer', no_copy=1, print_hide=1,
- depends_on='eval:in_list(["Registered Regular", "SEZ", "Overseas", "Deemed Export"], doc.gst_category) && doc.irn_cancelled === 0'),
-
- dict(fieldname='irn_cancelled', label='IRN Cancelled', fieldtype='Check', no_copy=1, print_hide=1,
- depends_on='eval: doc.irn', allow_on_submit=1, insert_after='customer'),
-
- dict(fieldname='eway_bill_validity', label='E-Way Bill Validity', fieldtype='Data', no_copy=1, print_hide=1,
- depends_on='ewaybill', read_only=1, allow_on_submit=1, insert_after='ewaybill'),
-
- dict(fieldname='eway_bill_cancelled', label='E-Way Bill Cancelled', fieldtype='Check', no_copy=1, print_hide=1,
- depends_on='eval:(doc.eway_bill_cancelled === 1)', read_only=1, allow_on_submit=1, insert_after='customer'),
-
- dict(fieldname='einvoice_section', label='E-Invoice Fields', fieldtype='Section Break', insert_after='gst_vehicle_type',
- print_hide=1, hidden=1),
-
- dict(fieldname='ack_no', label='Ack. No.', fieldtype='Data', read_only=1, hidden=1, insert_after='einvoice_section',
- no_copy=1, print_hide=1),
-
- dict(fieldname='ack_date', label='Ack. Date', fieldtype='Data', read_only=1, hidden=1, insert_after='ack_no', no_copy=1, print_hide=1),
-
- dict(fieldname='irn_cancel_date', label='Cancel Date', fieldtype='Data', read_only=1, hidden=1, insert_after='ack_date',
- no_copy=1, print_hide=1),
-
- dict(fieldname='signed_einvoice', label='Signed E-Invoice', fieldtype='Code', options='JSON', hidden=1, insert_after='irn_cancel_date',
- no_copy=1, print_hide=1, read_only=1),
-
- dict(fieldname='signed_qr_code', label='Signed QRCode', fieldtype='Code', options='JSON', hidden=1, insert_after='signed_einvoice',
- no_copy=1, print_hide=1, read_only=1),
-
- dict(fieldname='qrcode_image', label='QRCode', fieldtype='Attach Image', hidden=1, insert_after='signed_qr_code',
- no_copy=1, print_hide=1, read_only=1),
-
- dict(fieldname='einvoice_status', label='E-Invoice Status', fieldtype='Select', insert_after='qrcode_image',
- options='\nPending\nGenerated\nCancelled\nFailed', default=None, hidden=1, no_copy=1, print_hide=1, read_only=1),
-
- dict(fieldname='failure_description', label='E-Invoice Failure Description', fieldtype='Code', options='JSON',
- hidden=1, insert_after='einvoice_status', no_copy=1, print_hide=1, read_only=1)
- ]
-
custom_fields = {
'Address': [
dict(fieldname='gstin', label='Party GSTIN', fieldtype='Data',
@@ -504,7 +462,7 @@ def make_custom_fields(update=True):
'Purchase Invoice': purchase_invoice_gst_category + invoice_gst_fields + purchase_invoice_itc_fields + purchase_invoice_gst_fields,
'Purchase Order': purchase_invoice_gst_fields,
'Purchase Receipt': purchase_invoice_gst_fields,
- 'Sales Invoice': sales_invoice_gst_category + invoice_gst_fields + sales_invoice_shipping_fields + sales_invoice_gst_fields + si_ewaybill_fields + si_einvoice_fields,
+ 'Sales Invoice': sales_invoice_gst_category + invoice_gst_fields + sales_invoice_shipping_fields + sales_invoice_gst_fields + si_ewaybill_fields,
'Delivery Note': sales_invoice_gst_fields + ewaybill_fields + sales_invoice_shipping_fields + delivery_note_gst_category,
'Journal Entry': journal_entry_fields,
'Sales Order': sales_invoice_gst_fields,
diff --git a/erpnext/regional/report/e_invoice_summary/__init__.py b/erpnext/regional/report/e_invoice_summary/__init__.py
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/erpnext/regional/report/e_invoice_summary/e_invoice_summary.js b/erpnext/regional/report/e_invoice_summary/e_invoice_summary.js
deleted file mode 100644
index 4713217d83..0000000000
--- a/erpnext/regional/report/e_invoice_summary/e_invoice_summary.js
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
-// For license information, please see license.txt
-/* eslint-disable */
-
-frappe.query_reports["E-Invoice Summary"] = {
- "filters": [
- {
- "fieldtype": "Link",
- "options": "Company",
- "reqd": 1,
- "fieldname": "company",
- "label": __("Company"),
- "default": frappe.defaults.get_user_default("Company"),
- },
- {
- "fieldtype": "Link",
- "options": "Customer",
- "fieldname": "customer",
- "label": __("Customer")
- },
- {
- "fieldtype": "Date",
- "reqd": 1,
- "fieldname": "from_date",
- "label": __("From Date"),
- "default": frappe.datetime.add_months(frappe.datetime.get_today(), -1),
- },
- {
- "fieldtype": "Date",
- "reqd": 1,
- "fieldname": "to_date",
- "label": __("To Date"),
- "default": frappe.datetime.get_today(),
- },
- {
- "fieldtype": "Select",
- "fieldname": "status",
- "label": __("Status"),
- "options": "\nPending\nGenerated\nCancelled\nFailed"
- }
- ],
-
- "formatter": function (value, row, column, data, default_formatter) {
- value = default_formatter(value, row, column, data);
-
- if (column.fieldname == "einvoice_status" && value) {
- if (value == 'Pending') value = `${value} `;
- else if (value == 'Generated') value = `${value} `;
- else if (value == 'Cancelled') value = `${value} `;
- else if (value == 'Failed') value = `${value} `;
- }
-
- return value;
- }
-};
diff --git a/erpnext/regional/report/e_invoice_summary/e_invoice_summary.json b/erpnext/regional/report/e_invoice_summary/e_invoice_summary.json
deleted file mode 100644
index d0000ad50d..0000000000
--- a/erpnext/regional/report/e_invoice_summary/e_invoice_summary.json
+++ /dev/null
@@ -1,28 +0,0 @@
-{
- "add_total_row": 0,
- "columns": [],
- "creation": "2021-03-12 11:23:37.312294",
- "disable_prepared_report": 0,
- "disabled": 0,
- "docstatus": 0,
- "doctype": "Report",
- "filters": [],
- "idx": 0,
- "is_standard": "Yes",
- "json": "{}",
- "letter_head": "Logo",
- "modified": "2021-03-13 12:36:48.689413",
- "modified_by": "Administrator",
- "module": "Regional",
- "name": "E-Invoice Summary",
- "owner": "Administrator",
- "prepared_report": 0,
- "ref_doctype": "Sales Invoice",
- "report_name": "E-Invoice Summary",
- "report_type": "Script Report",
- "roles": [
- {
- "role": "Administrator"
- }
- ]
-}
\ No newline at end of file
diff --git a/erpnext/regional/report/e_invoice_summary/e_invoice_summary.py b/erpnext/regional/report/e_invoice_summary/e_invoice_summary.py
deleted file mode 100644
index 66ffceae53..0000000000
--- a/erpnext/regional/report/e_invoice_summary/e_invoice_summary.py
+++ /dev/null
@@ -1,106 +0,0 @@
-# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
-# For license information, please see license.txt
-
-from __future__ import unicode_literals
-import frappe
-from frappe import _
-
-def execute(filters=None):
- validate_filters(filters)
-
- columns = get_columns()
- data = get_data(filters)
-
- return columns, data
-
-def validate_filters(filters={}):
- filters = frappe._dict(filters)
-
- if not filters.company:
- frappe.throw(_('{} is mandatory for generating E-Invoice Summary Report').format(_('Company')), title=_('Invalid Filter'))
- if filters.company:
- # validate if company has e-invoicing enabled
- pass
- if not filters.from_date or not filters.to_date:
- frappe.throw(_('From Date & To Date is mandatory for generating E-Invoice Summary Report'), title=_('Invalid Filter'))
- if filters.from_date > filters.to_date:
- frappe.throw(_('From Date must be before To Date'), title=_('Invalid Filter'))
-
-def get_data(filters={}):
- query_filters = {
- 'posting_date': ['between', [filters.from_date, filters.to_date]],
- 'einvoice_status': ['is', 'set'],
- 'company': filters.company
- }
- if filters.customer:
- query_filters['customer'] = filters.customer
- if filters.status:
- query_filters['einvoice_status'] = filters.status
-
- data = frappe.get_all(
- 'Sales Invoice',
- filters=query_filters,
- fields=[d.get('fieldname') for d in get_columns()]
- )
-
- return data
-
-def get_columns():
- return [
- {
- "fieldtype": "Date",
- "fieldname": "posting_date",
- "label": _("Posting Date"),
- "width": 0
- },
- {
- "fieldtype": "Link",
- "fieldname": "name",
- "label": _("Sales Invoice"),
- "options": "Sales Invoice",
- "width": 140
- },
- {
- "fieldtype": "Data",
- "fieldname": "einvoice_status",
- "label": _("Status"),
- "width": 100
- },
- {
- "fieldtype": "Link",
- "fieldname": "customer",
- "options": "Customer",
- "label": _("Customer")
- },
- {
- "fieldtype": "Check",
- "fieldname": "is_return",
- "label": _("Is Return"),
- "width": 85
- },
- {
- "fieldtype": "Data",
- "fieldname": "ack_no",
- "label": "Ack. No.",
- "width": 145
- },
- {
- "fieldtype": "Data",
- "fieldname": "ack_date",
- "label": "Ack. Date",
- "width": 165
- },
- {
- "fieldtype": "Data",
- "fieldname": "irn",
- "label": _("IRN No."),
- "width": 250
- },
- {
- "fieldtype": "Currency",
- "options": "Company:company:default_currency",
- "fieldname": "base_grand_total",
- "label": _("Grand Total"),
- "width": 120
- }
- ]
From 2b2572b9b997eaeaae86e23f8b74803db85daf5a Mon Sep 17 00:00:00 2001
From: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com>
Date: Fri, 20 Aug 2021 14:40:12 +0530
Subject: [PATCH 383/386] fix: Cascade deletion for Company (#26923)
* fix: Cascade deletion for Company
---
erpnext/hooks.py | 3 +++
erpnext/regional/india/utils.py | 17 +++++++++++++++++
erpnext/setup/doctype/company/company.py | 4 ++++
3 files changed, 24 insertions(+)
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index 73831bf9af..74977cd8bc 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -308,6 +308,9 @@ doc_events = {
},
('Quotation', 'Sales Order', 'Sales Invoice'): {
'validate': ["erpnext.erpnext_integrations.taxjar_integration.set_sales_tax"]
+ },
+ "Company": {
+ "on_trash": "erpnext.regional.india.utils.delete_gst_settings_for_company"
}
}
diff --git a/erpnext/regional/india/utils.py b/erpnext/regional/india/utils.py
index 949733e0ad..4e4dcf8585 100644
--- a/erpnext/regional/india/utils.py
+++ b/erpnext/regional/india/utils.py
@@ -871,3 +871,20 @@ def set_item_tax_from_hsn_code(item):
'tax_category': tax.tax_category,
'valid_from': tax.valid_from
})
+
+def delete_gst_settings_for_company(doc, method):
+ if doc.country != 'India':
+ return
+
+ gst_settings = frappe.get_doc("GST Settings")
+ records_to_delete = []
+
+ for d in reversed(gst_settings.get('gst_accounts')):
+ if d.company == doc.name:
+ records_to_delete.append(d)
+
+ for d in records_to_delete:
+ gst_settings.remove(d)
+
+ gst_settings.save()
+
diff --git a/erpnext/setup/doctype/company/company.py b/erpnext/setup/doctype/company/company.py
index 54c67538ae..45d5ce0c1c 100644
--- a/erpnext/setup/doctype/company/company.py
+++ b/erpnext/setup/doctype/company/company.py
@@ -393,6 +393,10 @@ class Company(NestedSet):
frappe.db.sql("delete from `tabPurchase Taxes and Charges Template` where company=%s", self.name)
frappe.db.sql("delete from `tabItem Tax Template` where company=%s", self.name)
+ # delete Process Deferred Accounts if no GL Entry found
+ if not frappe.db.get_value('GL Entry', {'company': self.name}):
+ frappe.db.sql("delete from `tabProcess Deferred Accounting` where company=%s", self.name)
+
@frappe.whitelist()
def enqueue_replace_abbr(company, old, new):
kwargs = dict(queue="long", company=company, old=old, new=new)
From 62c590261c5c7cc96d1cad29bc44615229a0f83a Mon Sep 17 00:00:00 2001
From: Alan <2.alan.tom@gmail.com>
Date: Fri, 20 Aug 2021 18:21:09 +0530
Subject: [PATCH 384/386] refactor: rectify typo (#27057)
[skip ci]
---
erpnext/manufacturing/doctype/work_order/work_order.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/erpnext/manufacturing/doctype/work_order/work_order.py b/erpnext/manufacturing/doctype/work_order/work_order.py
index 69a4b95c9a..5fe9fec2af 100644
--- a/erpnext/manufacturing/doctype/work_order/work_order.py
+++ b/erpnext/manufacturing/doctype/work_order/work_order.py
@@ -602,7 +602,7 @@ class WorkOrder(Document):
if self.docstatus==1:
# calculate transferred qty based on submitted stock entries
- self.update_transaferred_qty_for_required_items()
+ self.update_transferred_qty_for_required_items()
# update in bin
self.update_reserved_qty_for_production()
@@ -671,7 +671,7 @@ class WorkOrder(Document):
self.set_available_qty()
- def update_transaferred_qty_for_required_items(self):
+ def update_transferred_qty_for_required_items(self):
'''update transferred qty from submitted stock entries for that item against
the work order'''
From ec258551bf48c93ce7190397ec34adee6eee66e6 Mon Sep 17 00:00:00 2001
From: Saqib
Date: Fri, 20 Aug 2021 19:09:31 +0530
Subject: [PATCH 385/386] fix: flaky test for SLA (#27051)
---
.../test_service_level_agreement.py | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/erpnext/support/doctype/service_level_agreement/test_service_level_agreement.py b/erpnext/support/doctype/service_level_agreement/test_service_level_agreement.py
index a81516ec11..d9c671e9a2 100644
--- a/erpnext/support/doctype/service_level_agreement/test_service_level_agreement.py
+++ b/erpnext/support/doctype/service_level_agreement/test_service_level_agreement.py
@@ -267,11 +267,15 @@ class TestServiceLevelAgreement(unittest.TestCase):
)
creation = datetime.datetime(2019, 3, 4, 12, 0)
lead = make_lead(creation=creation, index=4)
- self.assertFalse(lead.service_level_agreement)
+ applied_sla = frappe.db.get_value('Lead', lead.name, 'service_level_agreement')
+ self.assertFalse(applied_sla)
+ source = frappe.get_doc(doctype='Lead Source', source_name='Test Source')
+ source.insert(ignore_if_duplicate=True)
lead.source = "Test Source"
lead.save()
- self.assertEqual(lead.service_level_agreement, lead_sla.name)
+ applied_sla = frappe.db.get_value('Lead', lead.name, 'service_level_agreement')
+ self.assertEqual(applied_sla, lead_sla.name)
def tearDown(self):
for d in frappe.get_all("Service Level Agreement"):
From 57e326e7d0ad1a1053ac2d987aacd540353ef47d Mon Sep 17 00:00:00 2001
From: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com>
Date: Sat, 21 Aug 2021 17:59:11 +0530
Subject: [PATCH 386/386] fix: Consolidated balance sheet showing incorrect
values (#26975)
---
.../consolidated_financial_statement.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
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 56a67bb098..fc4212733a 100644
--- a/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py
+++ b/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py
@@ -210,10 +210,10 @@ 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
+ start_date = fiscal_year.year_start_date if filters.report != 'Balance Sheet' else None
end_date = fiscal_year.year_end_date
else:
- start_date = filters.period_start_date
+ start_date = filters.period_start_date if filters.report != 'Balance Sheet' else None
end_date = filters.period_end_date
gl_entries_by_account = {}