From e1dc6980d09266b3db115546403d8bbdc0946b1e Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Mon, 5 Jul 2021 14:58:32 +0530 Subject: [PATCH 01/81] 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 703e93c0757..676c6a8b479 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 02/81] 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 8e6952a93c4..b65903bf5e8 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 03/81] 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 6d1f6249c13..04c789d30a6 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 04/81] 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 f813425e6b5..dc0d9da97b6 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 05/81] 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 6fed9efa63f..f1c413e00a0 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 06/81] 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 cf52803fca8..bf082f89be7 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 07/81] 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 ac4a2d6f16d..9e33eb395b7 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 08/81] 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 676c6a8b479..49a2afee85f 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 09/81] 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 dc0d9da97b6..17228a3c283 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 10/81] 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 17228a3c283..2b48d66dca9 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 11/81] 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 f1c413e00a0..f662bbd1c79 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 96b5dfdc8f7..bc171604f43 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 bf082f89be7..cadb4aa97b1 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 12/81] 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 264baeaa472..2fee57f2d1b 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 13/81] 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 8a55ff87e39..922b567d152 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 14/81] 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 9e33eb395b7..d1abdba3792 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 15/81] 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 dc9094c3e91..81e3aaa8a58 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 16/81] 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 81e3aaa8a58..a1ee5d0076e 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 17/81] 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 f7992797ed4..78d1ee972f0 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 04c789d30a6..15fae84b799 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 4c313c43a72..0a115825086 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 18/81] 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 ca4d009956d..bd7ded269c6 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 dbc7f8632fc..d03a874c286 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 19/81] 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 e7dd6b8a606..5c09b71cf35 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 20/81] 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 2b48d66dca9..fab0e113240 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 21/81] 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 d1abdba3792..053f061acc7 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 22/81] 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 0a115825086..8fc4023f2e2 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 23/81] 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 2fee57f2d1b..45666183856 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 24/81] 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 bd7ded269c6..36fbc7e3513 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 d03a874c286..2ddfad9c310 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 25/81] 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 00ef7d5c184..96ae828f464 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 26/81] 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 a1ee5d0076e..4ed31cc2272 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 27/81] 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 78d1ee972f0..006f5bb0e86 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 15fae84b799..ee9b59e769d 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 8fc4023f2e2..f4593c2a762 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 28/81] 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 053f061acc7..24b0ec4d4a8 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 29/81] 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 fab0e113240..a5341df2e38 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 30/81] 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 2ddfad9c310..1e2e92f6093 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 31/81] 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 f4593c2a762..aa2fe29bc69 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 32/81] 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 36fbc7e3513..4eb71f8e704 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 33/81] 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 aa2fe29bc69..65dbe17ec1d 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 34/81] 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 65dbe17ec1d..2aac4968a28 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 35/81] 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 2aac4968a28..9b3336cde50 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 36/81] 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 a5341df2e38..02562278863 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 37/81] 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 4ed31cc2272..bf78c028c81 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 38/81] 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 006f5bb0e86..feae213d92d 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 ee9b59e769d..52c2a9c42c3 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 9b3336cde50..59879e0df58 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 39/81] 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 24b0ec4d4a8..a3a32d5e975 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 40/81] 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 4eb71f8e704..0487ef64443 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 1e2e92f6093..9f7d18bdb4a 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 41/81] 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 a3a32d5e975..55449132928 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 42/81] 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 02562278863..56f11650ffa 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 43/81] 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 52c2a9c42c3..2539de7b124 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 59879e0df58..3d048c36865 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 44/81] 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 0487ef64443..e20e385f63c 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 9f7d18bdb4a..1c0177d3d08 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 2ff0d3e0ebf5424ad8a50f65ad64b531a13f4b40 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Thu, 22 Jul 2021 10:43:16 +0530 Subject: [PATCH 45/81] 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 e20e385f63c..9d2acdc9779 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 1c0177d3d08..a7fbbdd5caa 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 1c9e516092e415ae27441b26e0a632427cd81f31 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Wed, 28 Jul 2021 11:38:44 +0530 Subject: [PATCH 46/81] 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 3d048c36865..8199b1040f0 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 1011c1b01acf5f606de2f9936bf9ea7411f1f53e Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Fri, 9 Jul 2021 01:44:34 +0530 Subject: [PATCH 47/81] 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 f7992797ed4..147785a0806 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 48/81] 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 147785a0806..28a9bddc420 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 eaa502ff7f0..a0bac51046f 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 cdd865ac4ac..f7ea77bae44 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 41f57a34d3d..a58c381df35 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 4808e948fc6..1628f930191 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 82c87a83a50..cf6cac273f0 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 def7cc6cb3584ce32e8351e8b7faeb49a955a052 Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Thu, 22 Jul 2021 05:57:42 +0530 Subject: [PATCH 50/81] 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 a0bac51046f..f68d81909a3 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 f7ea77bae44..2bf5c77e61c 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 a58c381df35..2b9d516e217 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 1628f930191..f99a01b8202 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 cf6cac273f0..b05cc7875cf 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 51/81] 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 974648d6d44..bf6925473ad 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 52/81] 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 f981aeb13bb..8b1245eb403 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 53/81] 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 8563b97ab74..11cf39e5e2d 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 54/81] 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 2eb8bfd5d2f..44e3e1e70e0 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 55/81] 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 11cf39e5e2d..474c9cf3df9 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 bf6925473ad..3fbe0afd10e 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 8b1245eb403..ca8d8b99d31 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 44e3e1e70e0..9a5064fcc71 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 56/81] 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 3fbe0afd10e..f4a089bcef2 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 57/81] 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 2bf5c77e61c..913e70b30c5 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 f99696b75d3819214b3849bdc29d43d16142e4ce Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Mon, 2 Aug 2021 23:15:44 +0530 Subject: [PATCH 58/81] 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 913e70b30c5..f475bc2fe2d 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 8328f4523021e2c187fa6ec17beae20ffe500f04 Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Wed, 4 Aug 2021 03:15:13 +0530 Subject: [PATCH 59/81] 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 474c9cf3df9..d7db27cb54c 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 60/81] 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 3ad9909ad07..026b85e26d2 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 2a9dcfb67ed..f75cb561385 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 61/81] 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 72a3a5e67c7..b4776ba2492 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 23c104555b33d35d381543adce7d6bf15be91460 Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Thu, 5 Aug 2021 00:28:42 +0530 Subject: [PATCH 62/81] 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 28a9bddc420..f7992797ed4 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 9a5064fcc71..fd6ac16fa31 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 63/81] 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 d7db27cb54c..0db54e42068 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 f4a089bcef2..5639ee8069e 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 ca8d8b99d31..756825e826d 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 fd6ac16fa31..34ea3257d57 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 64/81] 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 5639ee8069e..a226da75cd8 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 e4a07d8ff349907129eccd1fdad48efa4429900d Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Thu, 5 Aug 2021 21:42:09 +0530 Subject: [PATCH 65/81] 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 f475bc2fe2d..7f389cc32a3 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 66/81] 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 7f389cc32a3..78e4ad31add 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 67/81] 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 b97dc401e6a..19a394f7439 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 68/81] 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 19a394f7439..b97dc401e6a 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 0bba425fe300305c7d55a543dd42f98549d9b021 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Fri, 6 Aug 2021 23:53:16 +0530 Subject: [PATCH 69/81] 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 dc9094c3e91..299531d9f39 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 00ef7d5c184..f1bf595a394 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 e7dd6b8a606..23e8091761c 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 b97dc401e6a..329f9a97b86 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 f68d81909a3..94684bff1cd 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 78e4ad31add..00f40cda2c6 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 6a550e0e975..974ade35849 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 a79eadc7619..54df0d63cba 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 b05cc7875cf..d071f010478 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 70/81] 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 405216bf6fe..d967100806b 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 54df0d63cba..4d432e3d5cc 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 71/81] 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 94684bff1cd..a0b1e073cc6 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 0db54e42068..d06f9d20274 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 2b9d516e217..bba54018aef 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 72/81] 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 d06f9d20274..d668c76b6b9 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 ea83e2b45fb4219bf643e844ba85d682b6c44556 Mon Sep 17 00:00:00 2001 From: Frappe PR Bot Date: Mon, 9 Aug 2021 14:48:59 +0530 Subject: [PATCH 73/81] 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 428989aa965..0be41b40635 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 9b1a47eed6c..5de45cbcad9 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 74/81] 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 ca6e61fe6b0..b4abeff94f1 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 75/81] 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 a9b7efbe980..498f3cf0e97 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 76/81] 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 ae01496f02a..ada3badd7c7 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 00000000000..1d6eebe0398 --- /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 77/81] 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 46ce0939e4f..771611a7860 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 78/81] 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 feae213d92d..d0f4e965414 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 79/81] 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 d60f0a40b15..f0f5a58d153 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 af317db7124..12f03be2881 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 80/81] 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 d0f4e965414..d7d9a3886a5 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 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 81/81] 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 9c69deb6a48..e4c4af03651 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"):