From 0c0a9ed96d3b11741cf506c95f9e5e16fcdcfe68 Mon Sep 17 00:00:00 2001 From: ChillarAnand Date: Wed, 5 Jan 2022 09:17:46 +0530 Subject: [PATCH 01/75] refactor: Remove non-profit domain from ERPNext --- erpnext/domains/non_profit.py | 22 - erpnext/hooks.py | 16 - erpnext/modules.txt | 1 - erpnext/non_profit/__init__.py | 0 erpnext/non_profit/doctype/__init__.py | 0 .../certification_application/__init__.py | 0 .../certification_application.js | 8 - .../certification_application.json | 323 ------- .../certification_application.py | 9 - .../test_certification_application.py | 8 - .../doctype/certified_consultant/__init__.py | 0 .../certified_consultant.js | 8 - .../certified_consultant.json | 724 --------------- .../certified_consultant.py | 9 - .../test_certified_consultant.py | 8 - .../non_profit/doctype/chapter/__init__.py | 0 erpnext/non_profit/doctype/chapter/chapter.js | 8 - .../non_profit/doctype/chapter/chapter.json | 397 -------- erpnext/non_profit/doctype/chapter/chapter.py | 49 - .../doctype/chapter/templates/chapter.html | 79 -- .../chapter/templates/chapter_row.html | 25 - .../doctype/chapter/test_chapter.py | 8 - .../doctype/chapter_member/__init__.py | 0 .../chapter_member/chapter_member.json | 199 ---- .../doctype/chapter_member/chapter_member.py | 9 - .../non_profit/doctype/donation/__init__.py | 0 .../non_profit/doctype/donation/donation.js | 26 - .../non_profit/doctype/donation/donation.json | 156 ---- .../non_profit/doctype/donation/donation.py | 220 ----- .../doctype/donation/donation_dashboard.py | 16 - .../doctype/donation/test_donation.py | 77 -- erpnext/non_profit/doctype/donor/__init__.py | 0 erpnext/non_profit/doctype/donor/donor.js | 17 - erpnext/non_profit/doctype/donor/donor.json | 110 --- erpnext/non_profit/doctype/donor/donor.py | 17 - .../non_profit/doctype/donor/donor_list.js | 3 - .../non_profit/doctype/donor/test_donor.py | 8 - .../non_profit/doctype/donor_type/__init__.py | 0 .../doctype/donor_type/donor_type.js | 8 - .../doctype/donor_type/donor_type.json | 94 -- .../doctype/donor_type/donor_type.py | 9 - .../doctype/donor_type/test_donor_type.py | 8 - .../doctype/grant_application/__init__.py | 0 .../grant_application/grant_application.js | 27 - .../grant_application/grant_application.json | 851 ------------------ .../grant_application/grant_application.py | 58 -- .../templates/grant_application.html | 68 -- .../templates/grant_application_row.html | 11 - .../test_grant_application.py | 8 - erpnext/non_profit/doctype/member/__init__.py | 0 erpnext/non_profit/doctype/member/member.js | 64 -- erpnext/non_profit/doctype/member/member.json | 210 ----- erpnext/non_profit/doctype/member/member.py | 185 ---- .../doctype/member/member_dashboard.py | 22 - .../non_profit/doctype/member/member_list.js | 3 - .../non_profit/doctype/member/test_member.py | 8 - .../non_profit/doctype/membership/__init__.py | 0 .../doctype/membership/membership.js | 41 - .../doctype/membership/membership.json | 184 ---- .../doctype/membership/membership_list.js | 15 - .../doctype/membership/test_membership.py | 164 ---- .../doctype/membership_type/__init__.py | 0 .../membership_type/membership_type.js | 22 - .../membership_type/membership_type.json | 71 -- .../membership_type/membership_type.py | 18 - .../membership_type/test_membership_type.py | 8 - .../doctype/non_profit_settings/__init__.py | 0 .../non_profit_settings.js | 133 --- .../non_profit_settings.json | 273 ------ .../non_profit_settings.py | 38 - .../test_non_profit_settings.py | 9 - .../non_profit/doctype/volunteer/__init__.py | 0 .../doctype/volunteer/test_volunteer.py | 8 - .../non_profit/doctype/volunteer/volunteer.js | 17 - .../doctype/volunteer/volunteer.json | 148 --- .../non_profit/doctype/volunteer/volunteer.py | 12 - .../doctype/volunteer_skill/__init__.py | 0 .../volunteer_skill/volunteer_skill.json | 73 -- .../volunteer_skill/volunteer_skill.py | 9 - .../doctype/volunteer_type/__init__.py | 0 .../volunteer_type/test_volunteer_type.py | 8 - .../doctype/volunteer_type/volunteer_type.js | 8 - .../volunteer_type/volunteer_type.json | 94 -- .../doctype/volunteer_type/volunteer_type.py | 9 - erpnext/non_profit/report/__init__.py | 0 .../report/expiring_memberships/__init__.py | 0 .../expiring_memberships.js | 24 - .../expiring_memberships.json | 27 - .../expiring_memberships.py | 34 - erpnext/non_profit/utils.py | 12 - erpnext/non_profit/web_form/__init__.py | 0 .../certification_application/__init__.py | 0 .../certification_application.js | 16 - .../certification_application.json | 79 -- .../certification_application.py | 3 - .../certification_application_usd/__init__.py | 0 .../certification_application_usd.js | 16 - .../certification_application_usd.json | 80 -- .../certification_application_usd.py | 3 - .../web_form/grant_application/__init__.py | 0 .../grant_application/grant_application.js | 3 - .../grant_application/grant_application.json | 108 --- .../grant_application/grant_application.py | 4 - .../workspace/non_profit/non_profit.json | 272 ------ erpnext/patches.txt | 2 + .../v13_0/non_profit_deprecation_warning.py | 10 + .../v14_0/delete_non_profit_doctypes.py | 19 + erpnext/regional/india/setup.py | 8 - .../operations/install_fixtures.py | 1 - 109 files changed, 31 insertions(+), 6246 deletions(-) delete mode 100644 erpnext/domains/non_profit.py delete mode 100644 erpnext/non_profit/__init__.py delete mode 100644 erpnext/non_profit/doctype/__init__.py delete mode 100644 erpnext/non_profit/doctype/certification_application/__init__.py delete mode 100644 erpnext/non_profit/doctype/certification_application/certification_application.js delete mode 100644 erpnext/non_profit/doctype/certification_application/certification_application.json delete mode 100644 erpnext/non_profit/doctype/certification_application/certification_application.py delete mode 100644 erpnext/non_profit/doctype/certification_application/test_certification_application.py delete mode 100644 erpnext/non_profit/doctype/certified_consultant/__init__.py delete mode 100644 erpnext/non_profit/doctype/certified_consultant/certified_consultant.js delete mode 100644 erpnext/non_profit/doctype/certified_consultant/certified_consultant.json delete mode 100644 erpnext/non_profit/doctype/certified_consultant/certified_consultant.py delete mode 100644 erpnext/non_profit/doctype/certified_consultant/test_certified_consultant.py delete mode 100644 erpnext/non_profit/doctype/chapter/__init__.py delete mode 100644 erpnext/non_profit/doctype/chapter/chapter.js delete mode 100644 erpnext/non_profit/doctype/chapter/chapter.json delete mode 100644 erpnext/non_profit/doctype/chapter/chapter.py delete mode 100644 erpnext/non_profit/doctype/chapter/templates/chapter.html delete mode 100644 erpnext/non_profit/doctype/chapter/templates/chapter_row.html delete mode 100644 erpnext/non_profit/doctype/chapter/test_chapter.py delete mode 100644 erpnext/non_profit/doctype/chapter_member/__init__.py delete mode 100644 erpnext/non_profit/doctype/chapter_member/chapter_member.json delete mode 100644 erpnext/non_profit/doctype/chapter_member/chapter_member.py delete mode 100644 erpnext/non_profit/doctype/donation/__init__.py delete mode 100644 erpnext/non_profit/doctype/donation/donation.js delete mode 100644 erpnext/non_profit/doctype/donation/donation.json delete mode 100644 erpnext/non_profit/doctype/donation/donation.py delete mode 100644 erpnext/non_profit/doctype/donation/donation_dashboard.py delete mode 100644 erpnext/non_profit/doctype/donation/test_donation.py delete mode 100644 erpnext/non_profit/doctype/donor/__init__.py delete mode 100644 erpnext/non_profit/doctype/donor/donor.js delete mode 100644 erpnext/non_profit/doctype/donor/donor.json delete mode 100644 erpnext/non_profit/doctype/donor/donor.py delete mode 100644 erpnext/non_profit/doctype/donor/donor_list.js delete mode 100644 erpnext/non_profit/doctype/donor/test_donor.py delete mode 100644 erpnext/non_profit/doctype/donor_type/__init__.py delete mode 100644 erpnext/non_profit/doctype/donor_type/donor_type.js delete mode 100644 erpnext/non_profit/doctype/donor_type/donor_type.json delete mode 100644 erpnext/non_profit/doctype/donor_type/donor_type.py delete mode 100644 erpnext/non_profit/doctype/donor_type/test_donor_type.py delete mode 100644 erpnext/non_profit/doctype/grant_application/__init__.py delete mode 100644 erpnext/non_profit/doctype/grant_application/grant_application.js delete mode 100644 erpnext/non_profit/doctype/grant_application/grant_application.json delete mode 100644 erpnext/non_profit/doctype/grant_application/grant_application.py delete mode 100644 erpnext/non_profit/doctype/grant_application/templates/grant_application.html delete mode 100644 erpnext/non_profit/doctype/grant_application/templates/grant_application_row.html delete mode 100644 erpnext/non_profit/doctype/grant_application/test_grant_application.py delete mode 100644 erpnext/non_profit/doctype/member/__init__.py delete mode 100644 erpnext/non_profit/doctype/member/member.js delete mode 100644 erpnext/non_profit/doctype/member/member.json delete mode 100644 erpnext/non_profit/doctype/member/member.py delete mode 100644 erpnext/non_profit/doctype/member/member_dashboard.py delete mode 100644 erpnext/non_profit/doctype/member/member_list.js delete mode 100644 erpnext/non_profit/doctype/member/test_member.py delete mode 100644 erpnext/non_profit/doctype/membership/__init__.py delete mode 100644 erpnext/non_profit/doctype/membership/membership.js delete mode 100644 erpnext/non_profit/doctype/membership/membership.json delete mode 100644 erpnext/non_profit/doctype/membership/membership_list.js delete mode 100644 erpnext/non_profit/doctype/membership/test_membership.py delete mode 100644 erpnext/non_profit/doctype/membership_type/__init__.py delete mode 100644 erpnext/non_profit/doctype/membership_type/membership_type.js delete mode 100644 erpnext/non_profit/doctype/membership_type/membership_type.json delete mode 100644 erpnext/non_profit/doctype/membership_type/membership_type.py delete mode 100644 erpnext/non_profit/doctype/membership_type/test_membership_type.py delete mode 100644 erpnext/non_profit/doctype/non_profit_settings/__init__.py delete mode 100644 erpnext/non_profit/doctype/non_profit_settings/non_profit_settings.js delete mode 100644 erpnext/non_profit/doctype/non_profit_settings/non_profit_settings.json delete mode 100644 erpnext/non_profit/doctype/non_profit_settings/non_profit_settings.py delete mode 100644 erpnext/non_profit/doctype/non_profit_settings/test_non_profit_settings.py delete mode 100644 erpnext/non_profit/doctype/volunteer/__init__.py delete mode 100644 erpnext/non_profit/doctype/volunteer/test_volunteer.py delete mode 100644 erpnext/non_profit/doctype/volunteer/volunteer.js delete mode 100644 erpnext/non_profit/doctype/volunteer/volunteer.json delete mode 100644 erpnext/non_profit/doctype/volunteer/volunteer.py delete mode 100644 erpnext/non_profit/doctype/volunteer_skill/__init__.py delete mode 100644 erpnext/non_profit/doctype/volunteer_skill/volunteer_skill.json delete mode 100644 erpnext/non_profit/doctype/volunteer_skill/volunteer_skill.py delete mode 100644 erpnext/non_profit/doctype/volunteer_type/__init__.py delete mode 100644 erpnext/non_profit/doctype/volunteer_type/test_volunteer_type.py delete mode 100644 erpnext/non_profit/doctype/volunteer_type/volunteer_type.js delete mode 100644 erpnext/non_profit/doctype/volunteer_type/volunteer_type.json delete mode 100644 erpnext/non_profit/doctype/volunteer_type/volunteer_type.py delete mode 100644 erpnext/non_profit/report/__init__.py delete mode 100644 erpnext/non_profit/report/expiring_memberships/__init__.py delete mode 100644 erpnext/non_profit/report/expiring_memberships/expiring_memberships.js delete mode 100644 erpnext/non_profit/report/expiring_memberships/expiring_memberships.json delete mode 100644 erpnext/non_profit/report/expiring_memberships/expiring_memberships.py delete mode 100644 erpnext/non_profit/utils.py delete mode 100644 erpnext/non_profit/web_form/__init__.py delete mode 100644 erpnext/non_profit/web_form/certification_application/__init__.py delete mode 100644 erpnext/non_profit/web_form/certification_application/certification_application.js delete mode 100644 erpnext/non_profit/web_form/certification_application/certification_application.json delete mode 100644 erpnext/non_profit/web_form/certification_application/certification_application.py delete mode 100644 erpnext/non_profit/web_form/certification_application_usd/__init__.py delete mode 100644 erpnext/non_profit/web_form/certification_application_usd/certification_application_usd.js delete mode 100644 erpnext/non_profit/web_form/certification_application_usd/certification_application_usd.json delete mode 100644 erpnext/non_profit/web_form/certification_application_usd/certification_application_usd.py delete mode 100644 erpnext/non_profit/web_form/grant_application/__init__.py delete mode 100644 erpnext/non_profit/web_form/grant_application/grant_application.js delete mode 100644 erpnext/non_profit/web_form/grant_application/grant_application.json delete mode 100644 erpnext/non_profit/web_form/grant_application/grant_application.py delete mode 100644 erpnext/non_profit/workspace/non_profit/non_profit.json create mode 100644 erpnext/patches/v13_0/non_profit_deprecation_warning.py create mode 100644 erpnext/patches/v14_0/delete_non_profit_doctypes.py diff --git a/erpnext/domains/non_profit.py b/erpnext/domains/non_profit.py deleted file mode 100644 index d9fc5e5df01..00000000000 --- a/erpnext/domains/non_profit.py +++ /dev/null @@ -1,22 +0,0 @@ -data = { - 'desktop_icons': [ - 'Non Profit', - 'Member', - 'Donor', - 'Volunteer', - 'Grant Application', - 'Accounts', - 'Buying', - 'HR', - 'ToDo' - ], - 'restricted_roles': [ - 'Non Profit Manager', - 'Non Profit Member', - 'Non Profit Portal User' - ], - 'modules': [ - 'Non Profit' - ], - 'default_portal_role': 'Non Profit Manager' -} diff --git a/erpnext/hooks.py b/erpnext/hooks.py index f014b0e1e92..4502f2b97b1 100644 --- a/erpnext/hooks.py +++ b/erpnext/hooks.py @@ -69,7 +69,6 @@ domains = { 'Education': 'erpnext.domains.education', 'Hospitality': 'erpnext.domains.hospitality', 'Manufacturing': 'erpnext.domains.manufacturing', - 'Non Profit': 'erpnext.domains.non_profit', 'Retail': 'erpnext.domains.retail', 'Services': 'erpnext.domains.services', } @@ -176,7 +175,6 @@ standard_portal_menu_items = [ {"title": _("Fees"), "route": "/fees", "reference_doctype": "Fees", "role":"Student"}, {"title": _("Newsletter"), "route": "/newsletters", "reference_doctype": "Newsletter"}, {"title": _("Admission"), "route": "/admissions", "reference_doctype": "Student Admission", "role": "Student"}, - {"title": _("Certification"), "route": "/certification", "reference_doctype": "Certification Application", "role": "Non Profit Portal User"}, {"title": _("Material Request"), "route": "/material-requests", "reference_doctype": "Material Request", "role": "Customer"}, {"title": _("Appointment Booking"), "route": "/book_appointment"}, ] @@ -373,7 +371,6 @@ scheduler_events = { "erpnext.selling.doctype.quotation.quotation.set_expired_status", "erpnext.buying.doctype.supplier_quotation.supplier_quotation.set_expired_status", "erpnext.accounts.doctype.process_statement_of_accounts.process_statement_of_accounts.send_auto_email", - "erpnext.non_profit.doctype.membership.membership.set_expired_status", "erpnext.hr.doctype.interview.interview.send_daily_feedback_reminder" ], "daily_long": [ @@ -566,19 +563,6 @@ global_search_doctypes = { {'doctype': 'Assessment Code', 'index': 39}, {'doctype': 'Discussion', 'index': 40}, ], - "Non Profit": [ - {'doctype': 'Certified Consultant', 'index': 1}, - {'doctype': 'Certification Application', 'index': 2}, - {'doctype': 'Volunteer', 'index': 3}, - {'doctype': 'Membership', 'index': 4}, - {'doctype': 'Member', 'index': 5}, - {'doctype': 'Donor', 'index': 6}, - {'doctype': 'Chapter', 'index': 7}, - {'doctype': 'Grant Application', 'index': 8}, - {'doctype': 'Volunteer Type', 'index': 9}, - {'doctype': 'Donor Type', 'index': 10}, - {'doctype': 'Membership Type', 'index': 11} - ], "Hospitality": [ {'doctype': 'Hotel Room', 'index': 0}, {'doctype': 'Hotel Room Reservation', 'index': 1}, diff --git a/erpnext/modules.txt b/erpnext/modules.txt index ae0bb2d5c98..cd1586c290b 100644 --- a/erpnext/modules.txt +++ b/erpnext/modules.txt @@ -17,7 +17,6 @@ Education Regional Restaurant ERPNext Integrations -Non Profit Hotels Quality Management Communication diff --git a/erpnext/non_profit/__init__.py b/erpnext/non_profit/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/non_profit/doctype/__init__.py b/erpnext/non_profit/doctype/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/non_profit/doctype/certification_application/__init__.py b/erpnext/non_profit/doctype/certification_application/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/non_profit/doctype/certification_application/certification_application.js b/erpnext/non_profit/doctype/certification_application/certification_application.js deleted file mode 100644 index 1e6a9a4b01e..00000000000 --- a/erpnext/non_profit/doctype/certification_application/certification_application.js +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Certification Application', { - refresh: function(frm) { - - } -}); diff --git a/erpnext/non_profit/doctype/certification_application/certification_application.json b/erpnext/non_profit/doctype/certification_application/certification_application.json deleted file mode 100644 index f562fa67343..00000000000 --- a/erpnext/non_profit/doctype/certification_application/certification_application.json +++ /dev/null @@ -1,323 +0,0 @@ -{ - "allow_copy": 0, - "allow_events_in_timeline": 0, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, - "autoname": "NPO-CAPP-.YYYY.-.#####", - "beta": 0, - "creation": "2018-06-08 16:12:42.091729", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "", - "editable_grid": 1, - "engine": "InnoDB", - "fields": [ - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "name_of_applicant", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Name of Applicant", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "email", - "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": "Email", - "length": 0, - "no_copy": 0, - "options": "User", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break_1", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "certification_status", - "fieldtype": "Select", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Certification Status", - "length": 0, - "no_copy": 0, - "options": "Yet to appear\nCertified\nNot Certified", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "payment_details", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Payment Details", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "paid", - "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Paid", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "currency", - "fieldtype": "Select", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Currency", - "length": 0, - "no_copy": 0, - "options": "USD\nINR", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "amount", - "fieldtype": "Float", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Amount", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 0, - "max_attachments": 0, - "modified": "2018-11-04 03:36:35.337403", - "modified_by": "Administrator", - "module": "Non Profit", - "name": "Certification Application", - "name_case": "", - "owner": "Administrator", - "permissions": [ - { - "amend": 0, - "cancel": 0, - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "System Manager", - "set_user_permissions": 0, - "share": 1, - "submit": 0, - "write": 1 - } - ], - "quick_entry": 0, - "read_only": 0, - "read_only_onload": 0, - "restrict_to_domain": "Non Profit", - "show_name_in_global_search": 0, - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1, - "track_seen": 0, - "track_views": 0 -} \ No newline at end of file diff --git a/erpnext/non_profit/doctype/certification_application/certification_application.py b/erpnext/non_profit/doctype/certification_application/certification_application.py deleted file mode 100644 index cbbe191fbac..00000000000 --- a/erpnext/non_profit/doctype/certification_application/certification_application.py +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - - -from frappe.model.document import Document - - -class CertificationApplication(Document): - pass diff --git a/erpnext/non_profit/doctype/certification_application/test_certification_application.py b/erpnext/non_profit/doctype/certification_application/test_certification_application.py deleted file mode 100644 index 8687b4daf4b..00000000000 --- a/erpnext/non_profit/doctype/certification_application/test_certification_application.py +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors -# See license.txt - -import unittest - - -class TestCertificationApplication(unittest.TestCase): - pass diff --git a/erpnext/non_profit/doctype/certified_consultant/__init__.py b/erpnext/non_profit/doctype/certified_consultant/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/non_profit/doctype/certified_consultant/certified_consultant.js b/erpnext/non_profit/doctype/certified_consultant/certified_consultant.js deleted file mode 100644 index cd004c3489f..00000000000 --- a/erpnext/non_profit/doctype/certified_consultant/certified_consultant.js +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Certified Consultant', { - refresh: function(frm) { - - } -}); diff --git a/erpnext/non_profit/doctype/certified_consultant/certified_consultant.json b/erpnext/non_profit/doctype/certified_consultant/certified_consultant.json deleted file mode 100644 index d77f1b25694..00000000000 --- a/erpnext/non_profit/doctype/certified_consultant/certified_consultant.json +++ /dev/null @@ -1,724 +0,0 @@ -{ - "allow_copy": 0, - "allow_events_in_timeline": 0, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, - "autoname": "NPO-CONS-.YYYY.-.#####", - "beta": 0, - "creation": "2018-06-13 17:27:19.838334", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "", - "editable_grid": 1, - "engine": "InnoDB", - "fields": [ - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "name_of_consultant", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Name of Consultant", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "country", - "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": "Country", - "length": 0, - "no_copy": 0, - "options": "Country", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "email", - "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": "Email", - "length": 0, - "no_copy": 0, - "options": "User", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "phone", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Phone", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "website_url", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Website", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "address", - "fieldtype": "Small Text", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Address", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break1", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "image", - "fieldtype": "Attach Image", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Image", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "certification_application", - "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": "Certification Application", - "length": 0, - "no_copy": 0, - "options": "Certification Application", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "section_break1", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Certification Validity", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "from_date", - "fieldtype": "Date", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "From", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_beak2", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "to_date", - "fieldtype": "Date", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "To", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "section_break2", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "introduction", - "fieldtype": "Small Text", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Introduction", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "details", - "fieldtype": "Text Editor", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Details", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "section_break3", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "discuss_id", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Discuss ID", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "github_id", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "GitHub ID", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "show_in_website", - "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Show in Website", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 0, - "max_attachments": 0, - "modified": "2018-11-04 03:36:47.386618", - "modified_by": "Administrator", - "module": "Non Profit", - "name": "Certified Consultant", - "name_case": "", - "owner": "Administrator", - "permissions": [ - { - "amend": 0, - "cancel": 0, - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "System Manager", - "set_user_permissions": 0, - "share": 1, - "submit": 0, - "write": 1 - }, - { - "amend": 0, - "cancel": 0, - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Non Profit Manager", - "set_user_permissions": 0, - "share": 1, - "submit": 0, - "write": 1 - } - ], - "quick_entry": 0, - "read_only": 0, - "read_only_onload": 0, - "restrict_to_domain": "Non Profit", - "show_name_in_global_search": 0, - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1, - "track_seen": 0, - "track_views": 0 -} \ No newline at end of file diff --git a/erpnext/non_profit/doctype/certified_consultant/certified_consultant.py b/erpnext/non_profit/doctype/certified_consultant/certified_consultant.py deleted file mode 100644 index 47361cc39ea..00000000000 --- a/erpnext/non_profit/doctype/certified_consultant/certified_consultant.py +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - - -from frappe.model.document import Document - - -class CertifiedConsultant(Document): - pass diff --git a/erpnext/non_profit/doctype/certified_consultant/test_certified_consultant.py b/erpnext/non_profit/doctype/certified_consultant/test_certified_consultant.py deleted file mode 100644 index d10353c1e47..00000000000 --- a/erpnext/non_profit/doctype/certified_consultant/test_certified_consultant.py +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors -# See license.txt - -import unittest - - -class TestCertifiedConsultant(unittest.TestCase): - pass diff --git a/erpnext/non_profit/doctype/chapter/__init__.py b/erpnext/non_profit/doctype/chapter/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/non_profit/doctype/chapter/chapter.js b/erpnext/non_profit/doctype/chapter/chapter.js deleted file mode 100644 index c8b6d4a6446..00000000000 --- a/erpnext/non_profit/doctype/chapter/chapter.js +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Chapter', { - refresh: function() { - - } -}); diff --git a/erpnext/non_profit/doctype/chapter/chapter.json b/erpnext/non_profit/doctype/chapter/chapter.json deleted file mode 100644 index 86cba9a1788..00000000000 --- a/erpnext/non_profit/doctype/chapter/chapter.json +++ /dev/null @@ -1,397 +0,0 @@ -{ - "allow_copy": 0, - "allow_guest_to_view": 1, - "allow_import": 0, - "allow_rename": 1, - "autoname": "prompt", - "beta": 0, - "creation": "2017-09-14 13:36:03.904702", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "", - "editable_grid": 1, - "engine": "InnoDB", - "fields": [ - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "chapter_head", - "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": "Chapter Head", - "length": 0, - "no_copy": 0, - "options": "Member", - "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, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break_3", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "region", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Region", - "length": 0, - "no_copy": 0, - "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, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "section_break_5", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "introduction", - "fieldtype": "Text Editor", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Introduction", - "length": 0, - "no_copy": 0, - "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, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "meetup_embed_html", - "fieldtype": "Code", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Meetup Embed HTML", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "address", - "fieldtype": "Text", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Address", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "description": "chapters/chapter_name\nleave blank automatically set after saving chapter.", - "fieldname": "route", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Route", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "published", - "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Published", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 1, - "columns": 0, - "fieldname": "chapter_members", - "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": "Chapter Members", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "members", - "fieldtype": "Table", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Members", - "length": 0, - "no_copy": 0, - "options": "Chapter Member", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - } - ], - "has_web_view": 1, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, - "is_published_field": "published", - "is_submittable": 0, - "issingle": 0, - "istable": 0, - "max_attachments": 0, - "modified": "2017-12-14 12:59:31.424240", - "modified_by": "Administrator", - "module": "Non Profit", - "name": "Chapter", - "name_case": "Title Case", - "owner": "Administrator", - "permissions": [ - { - "amend": 0, - "apply_user_permissions": 0, - "cancel": 0, - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Non Profit Manager", - "set_user_permissions": 0, - "share": 1, - "submit": 0, - "write": 1 - } - ], - "quick_entry": 1, - "read_only": 0, - "read_only_onload": 0, - "restrict_to_domain": "Non Profit", - "route": "chapters", - "show_name_in_global_search": 0, - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1, - "track_seen": 0 -} \ No newline at end of file diff --git a/erpnext/non_profit/doctype/chapter/chapter.py b/erpnext/non_profit/doctype/chapter/chapter.py deleted file mode 100644 index c01b1ef3e42..00000000000 --- a/erpnext/non_profit/doctype/chapter/chapter.py +++ /dev/null @@ -1,49 +0,0 @@ -# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - - -import frappe -from frappe.website.website_generator import WebsiteGenerator - - -class Chapter(WebsiteGenerator): - _website = frappe._dict( - condition_field = "published", - ) - - def get_context(self, context): - context.no_cache = True - context.show_sidebar = True - context.parents = [dict(label='View All Chapters', - route='chapters', title='View Chapters')] - - def validate(self): - if not self.route: #pylint: disable=E0203 - self.route = 'chapters/' + self.scrub(self.name) - - def enable(self): - chapter = frappe.get_doc('Chapter', frappe.form_dict.name) - chapter.append('members', dict(enable=self.value)) - chapter.save(ignore_permissions=1) - frappe.db.commit() - - -def get_list_context(context): - context.allow_guest = True - context.no_cache = True - context.show_sidebar = True - context.title = 'All Chapters' - context.no_breadcrumbs = True - context.order_by = 'creation desc' - - -@frappe.whitelist() -def leave(title, user_id, leave_reason): - chapter = frappe.get_doc("Chapter", title) - for member in chapter.members: - if member.user == user_id: - member.enabled = 0 - member.leave_reason = leave_reason - chapter.save(ignore_permissions=1) - frappe.db.commit() - return "Thank you for Feedback" diff --git a/erpnext/non_profit/doctype/chapter/templates/chapter.html b/erpnext/non_profit/doctype/chapter/templates/chapter.html deleted file mode 100644 index 321828f73f1..00000000000 --- a/erpnext/non_profit/doctype/chapter/templates/chapter.html +++ /dev/null @@ -1,79 +0,0 @@ -{% extends "templates/web.html" %} - -{% block page_content %} -

{{ title }}

-

{{ introduction }}

-{% if meetup_embed_html %} - {{ meetup_embed_html }} -{% endif %} -

Member Details

- -{% if members %} - - {% set index = [1] %} - {% for user in members %} - {% if user.enabled == 1 %} - - - - {% set __ = index.append(1) %} - {% endif %} - {% endfor %} -
-
-
-
-
- {{ index|length }}. {{ frappe.db.get_value('User', user.user, 'full_name') }}
-
-
- {% if user.website_url %} - {{ user.website_url | truncate (50) or '' }} - {% endif %} -
-
-
-

-
- {% if user.introduction %} - {{ user.introduction }} - {% endif %} -
-
- -
-{% else %} -

No member yet.

-{% endif %} - -

Chapter Head

-
- - - {% set doc = frappe.get_doc('Member',chapter_head) %} - - - - - - - - - - - - -
Name{{ doc.member_name }}
Email{{ frappe.db.get_value('User', doc.email, 'email') or '' }}
Phone{{ frappe.db.get_value('User', doc.email, 'phone') or '' }}
-
- -{% if address %} -

Address

-
-

{{ address or ''}}

-
-{% endif %} - -

Join this Chapter

-

Leave this Chapter

- -{% endblock %} diff --git a/erpnext/non_profit/doctype/chapter/templates/chapter_row.html b/erpnext/non_profit/doctype/chapter/templates/chapter_row.html deleted file mode 100644 index cad34fa5bed..00000000000 --- a/erpnext/non_profit/doctype/chapter/templates/chapter_row.html +++ /dev/null @@ -1,25 +0,0 @@ -{% if doc.published %} -
- -

{{ doc.name }}

-

- Chapter Head : {{ frappe.db.get_value('User', chapter_head, 'full_name') }} - - {% if members %} - {% set index = [] %} - {% for user in members %} - {% if user.enabled == 1 %} - {% set __ = index.append(1) %} - {% endif %} - {% endfor %} - Members: {{ index|length }} - {% else %} - Members: 0 - {% endif %} - - -

-

{{ html2text(doc.introduction) | truncate (200) }}

-
-
-{% endif %} diff --git a/erpnext/non_profit/doctype/chapter/test_chapter.py b/erpnext/non_profit/doctype/chapter/test_chapter.py deleted file mode 100644 index 98601efcf23..00000000000 --- a/erpnext/non_profit/doctype/chapter/test_chapter.py +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors -# See license.txt - -import unittest - - -class TestChapter(unittest.TestCase): - pass diff --git a/erpnext/non_profit/doctype/chapter_member/__init__.py b/erpnext/non_profit/doctype/chapter_member/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/non_profit/doctype/chapter_member/chapter_member.json b/erpnext/non_profit/doctype/chapter_member/chapter_member.json deleted file mode 100644 index 478bfd9331d..00000000000 --- a/erpnext/non_profit/doctype/chapter_member/chapter_member.json +++ /dev/null @@ -1,199 +0,0 @@ -{ - "allow_copy": 0, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, - "beta": 0, - "creation": "2017-09-14 13:38:04.296375", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "", - "editable_grid": 1, - "engine": "InnoDB", - "fields": [ - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "user", - "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": "User", - "length": 0, - "no_copy": 0, - "options": "User", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "introduction", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Introduction", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "website_url", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Website URL", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 2, - "default": "1", - "fieldname": "enabled", - "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Enabled", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "leave_reason", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Leave Reason", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 1, - "max_attachments": 0, - "modified": "2018-03-07 05:36:51.664816", - "modified_by": "Administrator", - "module": "Non Profit", - "name": "Chapter Member", - "name_case": "", - "owner": "Administrator", - "permissions": [], - "quick_entry": 1, - "read_only": 0, - "read_only_onload": 0, - "restrict_to_domain": "Non Profit", - "show_name_in_global_search": 0, - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1, - "track_seen": 0 -} \ No newline at end of file diff --git a/erpnext/non_profit/doctype/chapter_member/chapter_member.py b/erpnext/non_profit/doctype/chapter_member/chapter_member.py deleted file mode 100644 index 80c0446ee5a..00000000000 --- a/erpnext/non_profit/doctype/chapter_member/chapter_member.py +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - - -from frappe.model.document import Document - - -class ChapterMember(Document): - pass diff --git a/erpnext/non_profit/doctype/donation/__init__.py b/erpnext/non_profit/doctype/donation/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/non_profit/doctype/donation/donation.js b/erpnext/non_profit/doctype/donation/donation.js deleted file mode 100644 index 10e82201440..00000000000 --- a/erpnext/non_profit/doctype/donation/donation.js +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Donation', { - refresh: function(frm) { - if (frm.doc.docstatus === 1 && !frm.doc.paid) { - frm.add_custom_button(__('Create Payment Entry'), function() { - frm.events.make_payment_entry(frm); - }); - } - }, - - make_payment_entry: function(frm) { - return frappe.call({ - method: 'erpnext.accounts.doctype.payment_entry.payment_entry.get_payment_entry', - args: { - 'dt': frm.doc.doctype, - 'dn': frm.doc.name - }, - callback: function(r) { - var doc = frappe.model.sync(r.message); - frappe.set_route('Form', doc[0].doctype, doc[0].name); - } - }); - }, -}); diff --git a/erpnext/non_profit/doctype/donation/donation.json b/erpnext/non_profit/doctype/donation/donation.json deleted file mode 100644 index 6759569d54d..00000000000 --- a/erpnext/non_profit/doctype/donation/donation.json +++ /dev/null @@ -1,156 +0,0 @@ -{ - "actions": [], - "autoname": "naming_series:", - "creation": "2021-02-17 10:28:52.645731", - "doctype": "DocType", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "naming_series", - "donor", - "donor_name", - "email", - "column_break_4", - "company", - "date", - "payment_details_section", - "paid", - "amount", - "mode_of_payment", - "razorpay_payment_id", - "amended_from" - ], - "fields": [ - { - "fieldname": "donor", - "fieldtype": "Link", - "label": "Donor", - "options": "Donor", - "reqd": 1 - }, - { - "fetch_from": "donor.donor_name", - "fieldname": "donor_name", - "fieldtype": "Data", - "in_list_view": 1, - "in_standard_filter": 1, - "label": "Donor Name", - "read_only": 1 - }, - { - "fetch_from": "donor.email", - "fieldname": "email", - "fieldtype": "Data", - "in_list_view": 1, - "in_standard_filter": 1, - "label": "Email", - "read_only": 1 - }, - { - "fieldname": "column_break_4", - "fieldtype": "Column Break" - }, - { - "fieldname": "date", - "fieldtype": "Date", - "label": "Date", - "reqd": 1 - }, - { - "fieldname": "payment_details_section", - "fieldtype": "Section Break", - "label": "Payment Details" - }, - { - "fieldname": "amount", - "fieldtype": "Currency", - "label": "Amount", - "reqd": 1 - }, - { - "fieldname": "mode_of_payment", - "fieldtype": "Link", - "label": "Mode of Payment", - "options": "Mode of Payment" - }, - { - "fieldname": "razorpay_payment_id", - "fieldtype": "Data", - "label": "Razorpay Payment ID", - "read_only": 1 - }, - { - "fieldname": "naming_series", - "fieldtype": "Select", - "label": "Naming Series", - "options": "NPO-DTN-.YYYY.-" - }, - { - "default": "0", - "fieldname": "paid", - "fieldtype": "Check", - "in_list_view": 1, - "in_standard_filter": 1, - "label": "Paid" - }, - { - "fieldname": "company", - "fieldtype": "Link", - "label": "Company", - "options": "Company", - "reqd": 1 - }, - { - "fieldname": "amended_from", - "fieldtype": "Link", - "label": "Amended From", - "no_copy": 1, - "options": "Donation", - "print_hide": 1, - "read_only": 1 - } - ], - "index_web_pages_for_search": 1, - "is_submittable": 1, - "links": [], - "modified": "2021-03-11 10:53:11.269005", - "modified_by": "Administrator", - "module": "Non Profit", - "name": "Donation", - "owner": "Administrator", - "permissions": [ - { - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "System Manager", - "select": 1, - "share": 1, - "submit": 1, - "write": 1 - }, - { - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "Non Profit Manager", - "select": 1, - "share": 1, - "submit": 1, - "write": 1 - } - ], - "search_fields": "donor_name, email", - "sort_field": "modified", - "sort_order": "DESC", - "title_field": "donor_name", - "track_changes": 1 -} \ No newline at end of file diff --git a/erpnext/non_profit/doctype/donation/donation.py b/erpnext/non_profit/doctype/donation/donation.py deleted file mode 100644 index 54bc94b755c..00000000000 --- a/erpnext/non_profit/doctype/donation/donation.py +++ /dev/null @@ -1,220 +0,0 @@ -# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - - -import json - -import frappe -from frappe import _ -from frappe.email import sendmail_to_system_managers -from frappe.model.document import Document -from frappe.utils import flt, get_link_to_form, getdate - -from erpnext.non_profit.doctype.membership.membership import verify_signature - - -class Donation(Document): - def validate(self): - if not self.donor or not frappe.db.exists('Donor', self.donor): - # for web forms - user_type = frappe.db.get_value('User', frappe.session.user, 'user_type') - if user_type == 'Website User': - self.create_donor_for_website_user() - else: - frappe.throw(_('Please select a Member')) - - def create_donor_for_website_user(self): - donor_name = frappe.get_value('Donor', dict(email=frappe.session.user)) - - if not donor_name: - user = frappe.get_doc('User', frappe.session.user) - donor = frappe.get_doc(dict( - doctype='Donor', - donor_type=self.get('donor_type'), - email=frappe.session.user, - member_name=user.get_fullname() - )).insert(ignore_permissions=True) - donor_name = donor.name - - if self.get('__islocal'): - self.donor = donor_name - - def on_payment_authorized(self, *args, **kwargs): - self.load_from_db() - self.create_payment_entry() - - def create_payment_entry(self, date=None): - settings = frappe.get_doc('Non Profit Settings') - if not settings.automate_donation_payment_entries: - return - - if not settings.donation_payment_account: - frappe.throw(_('You need to set Payment Account for Donation in {0}').format( - get_link_to_form('Non Profit Settings', 'Non Profit Settings'))) - - from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry - - frappe.flags.ignore_account_permission = True - pe = get_payment_entry(dt=self.doctype, dn=self.name) - frappe.flags.ignore_account_permission = False - pe.paid_from = settings.donation_debit_account - pe.paid_to = settings.donation_payment_account - pe.posting_date = date or getdate() - pe.reference_no = self.name - pe.reference_date = date or getdate() - pe.flags.ignore_mandatory = True - pe.insert() - pe.submit() - - -@frappe.whitelist(allow_guest=True) -def capture_razorpay_donations(*args, **kwargs): - """ - Creates Donation from Razorpay Webhook Request Data on payment.captured event - Creates Donor from email if not found - """ - data = frappe.request.get_data(as_text=True) - - try: - verify_signature(data, endpoint='Donation') - except Exception as e: - log = frappe.log_error(e, 'Donation Webhook Verification Error') - notify_failure(log) - return { 'status': 'Failed', 'reason': e } - - if isinstance(data, str): - data = json.loads(data) - data = frappe._dict(data) - - payment = data.payload.get('payment', {}).get('entity', {}) - payment = frappe._dict(payment) - - try: - if not data.event == 'payment.captured': - return - - # to avoid capturing subscription payments as donations - if payment.description and 'subscription' in str(payment.description).lower(): - return - - donor = get_donor(payment.email) - if not donor: - donor = create_donor(payment) - - donation = create_donation(donor, payment) - donation.run_method('create_payment_entry') - - except Exception as e: - message = '{0}\n\n{1}\n\n{2}: {3}'.format(e, frappe.get_traceback(), _('Payment ID'), payment.id) - log = frappe.log_error(message, _('Error creating donation entry for {0}').format(donor.name)) - notify_failure(log) - return { 'status': 'Failed', 'reason': e } - - return { 'status': 'Success' } - - -def create_donation(donor, payment): - if not frappe.db.exists('Mode of Payment', payment.method): - create_mode_of_payment(payment.method) - - company = get_company_for_donations() - donation = frappe.get_doc({ - 'doctype': 'Donation', - 'company': company, - 'donor': donor.name, - 'donor_name': donor.donor_name, - 'email': donor.email, - 'date': getdate(), - 'amount': flt(payment.amount) / 100, # Convert to rupees from paise - 'mode_of_payment': payment.method, - 'razorpay_payment_id': payment.id - }).insert(ignore_mandatory=True) - - donation.submit() - return donation - - -def get_donor(email): - donors = frappe.get_all('Donor', - filters={'email': email}, - order_by='creation desc') - - try: - return frappe.get_doc('Donor', donors[0]['name']) - except Exception: - return None - - -@frappe.whitelist() -def create_donor(payment): - donor_details = frappe._dict(payment) - donor_type = frappe.db.get_single_value('Non Profit Settings', 'default_donor_type') - - donor = frappe.new_doc('Donor') - donor.update({ - 'donor_name': donor_details.email, - 'donor_type': donor_type, - 'email': donor_details.email, - 'contact': donor_details.contact - }) - - if donor_details.get('notes'): - donor = get_additional_notes(donor, donor_details) - - donor.insert(ignore_mandatory=True) - return donor - - -def get_company_for_donations(): - company = frappe.db.get_single_value('Non Profit Settings', 'donation_company') - if not company: - from erpnext.non_profit.utils import get_company - company = get_company() - return company - - -def get_additional_notes(donor, donor_details): - if type(donor_details.notes) == dict: - for k, v in donor_details.notes.items(): - notes = '\n'.join('{}: {}'.format(k, v)) - - # extract donor name from notes - if 'name' in k.lower(): - donor.update({ - 'donor_name': donor_details.notes.get(k) - }) - - # extract pan from notes - if 'pan' in k.lower(): - donor.update({ - 'pan_number': donor_details.notes.get(k) - }) - - donor.add_comment('Comment', notes) - - elif type(donor_details.notes) == str: - donor.add_comment('Comment', donor_details.notes) - - return donor - - -def create_mode_of_payment(method): - frappe.get_doc({ - 'doctype': 'Mode of Payment', - 'mode_of_payment': method - }).insert(ignore_mandatory=True) - - -def notify_failure(log): - try: - content = ''' - Dear System Manager, - Razorpay webhook for creating donation failed due to some reason. - Please check the error log linked below - Error Log: {0} - Regards, Administrator - '''.format(get_link_to_form('Error Log', log.name)) - - sendmail_to_system_managers(_('[Important] [ERPNext] Razorpay donation webhook failed, please check.'), content) - except Exception: - pass diff --git a/erpnext/non_profit/doctype/donation/donation_dashboard.py b/erpnext/non_profit/doctype/donation/donation_dashboard.py deleted file mode 100644 index 492ad621718..00000000000 --- a/erpnext/non_profit/doctype/donation/donation_dashboard.py +++ /dev/null @@ -1,16 +0,0 @@ -from frappe import _ - - -def get_data(): - return { - 'fieldname': 'donation', - 'non_standard_fieldnames': { - 'Payment Entry': 'reference_name' - }, - 'transactions': [ - { - 'label': _('Payment'), - 'items': ['Payment Entry'] - } - ] - } diff --git a/erpnext/non_profit/doctype/donation/test_donation.py b/erpnext/non_profit/doctype/donation/test_donation.py deleted file mode 100644 index 5fa731a6aa3..00000000000 --- a/erpnext/non_profit/doctype/donation/test_donation.py +++ /dev/null @@ -1,77 +0,0 @@ -# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors -# See license.txt - -import unittest - -import frappe - -from erpnext.non_profit.doctype.donation.donation import create_donation - - -class TestDonation(unittest.TestCase): - def setUp(self): - create_donor_type() - settings = frappe.get_doc('Non Profit Settings') - settings.company = '_Test Company' - settings.donation_company = '_Test Company' - settings.default_donor_type = '_Test Donor' - settings.automate_donation_payment_entries = 1 - settings.donation_debit_account = 'Debtors - _TC' - settings.donation_payment_account = 'Cash - _TC' - settings.creation_user = 'Administrator' - settings.flags.ignore_permissions = True - settings.save() - - def test_payment_entry_for_donations(self): - donor = create_donor() - create_mode_of_payment() - payment = frappe._dict({ - 'amount': 100, - 'method': 'Debit Card', - 'id': 'pay_MeXAmsgeKOhq7O' - }) - donation = create_donation(donor, payment) - - self.assertTrue(donation.name) - - # Naive test to check if at all payment entry is generated - # This method is actually triggered from Payment Gateway - # In any case if details were missing, this would throw an error - donation.on_payment_authorized() - donation.reload() - - self.assertEqual(donation.paid, 1) - self.assertTrue(frappe.db.exists('Payment Entry', {'reference_no': donation.name})) - - -def create_donor_type(): - if not frappe.db.exists('Donor Type', '_Test Donor'): - frappe.get_doc({ - 'doctype': 'Donor Type', - 'donor_type': '_Test Donor' - }).insert() - - -def create_donor(): - donor = frappe.db.exists('Donor', 'donor@test.com') - if donor: - return frappe.get_doc('Donor', 'donor@test.com') - else: - return frappe.get_doc({ - 'doctype': 'Donor', - 'donor_name': '_Test Donor', - 'donor_type': '_Test Donor', - 'email': 'donor@test.com' - }).insert() - - -def create_mode_of_payment(): - if not frappe.db.exists('Mode of Payment', 'Debit Card'): - frappe.get_doc({ - 'doctype': 'Mode of Payment', - 'mode_of_payment': 'Debit Card', - 'accounts': [{ - 'company': '_Test Company', - 'default_account': 'Cash - _TC' - }] - }).insert() diff --git a/erpnext/non_profit/doctype/donor/__init__.py b/erpnext/non_profit/doctype/donor/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/non_profit/doctype/donor/donor.js b/erpnext/non_profit/doctype/donor/donor.js deleted file mode 100644 index 090d5af32ef..00000000000 --- a/erpnext/non_profit/doctype/donor/donor.js +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Donor', { - refresh: function(frm) { - frappe.dynamic_link = {doc: frm.doc, fieldname: 'name', doctype: 'Donor'}; - - frm.toggle_display(['address_html','contact_html'], !frm.doc.__islocal); - - if(!frm.doc.__islocal) { - frappe.contacts.render_address_and_contact(frm); - } else { - frappe.contacts.clear_address_and_contact(frm); - } - - } -}); diff --git a/erpnext/non_profit/doctype/donor/donor.json b/erpnext/non_profit/doctype/donor/donor.json deleted file mode 100644 index 72f24ef9226..00000000000 --- a/erpnext/non_profit/doctype/donor/donor.json +++ /dev/null @@ -1,110 +0,0 @@ -{ - "actions": [], - "allow_rename": 1, - "autoname": "field:email", - "creation": "2017-09-19 16:20:27.510196", - "doctype": "DocType", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "donor_name", - "column_break_5", - "donor_type", - "email", - "image", - "address_contacts", - "address_html", - "column_break_9", - "contact_html" - ], - "fields": [ - { - "fieldname": "donor_name", - "fieldtype": "Data", - "in_list_view": 1, - "label": "Donor Name", - "reqd": 1 - }, - { - "fieldname": "column_break_5", - "fieldtype": "Column Break" - }, - { - "fieldname": "donor_type", - "fieldtype": "Link", - "in_list_view": 1, - "label": "Donor Type", - "options": "Donor Type", - "reqd": 1 - }, - { - "fieldname": "email", - "fieldtype": "Data", - "in_list_view": 1, - "label": "Email", - "reqd": 1, - "unique": 1 - }, - { - "fieldname": "image", - "fieldtype": "Attach Image", - "hidden": 1, - "label": "Image", - "no_copy": 1, - "print_hide": 1 - }, - { - "depends_on": "eval:!doc.__islocal;", - "fieldname": "address_contacts", - "fieldtype": "Section Break", - "label": "Address and Contact", - "options": "fa fa-map-marker" - }, - { - "fieldname": "address_html", - "fieldtype": "HTML", - "label": "Address HTML" - }, - { - "fieldname": "column_break_9", - "fieldtype": "Column Break" - }, - { - "fieldname": "contact_html", - "fieldtype": "HTML", - "label": "Contact HTML" - } - ], - "image_field": "image", - "links": [ - { - "link_doctype": "Donation", - "link_fieldname": "donor" - } - ], - "modified": "2021-02-17 16:36:33.470731", - "modified_by": "Administrator", - "module": "Non Profit", - "name": "Donor", - "owner": "Administrator", - "permissions": [ - { - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "Non Profit Manager", - "share": 1, - "write": 1 - } - ], - "quick_entry": 1, - "restrict_to_domain": "Non Profit", - "sort_field": "modified", - "sort_order": "DESC", - "title_field": "donor_name", - "track_changes": 1 -} \ No newline at end of file diff --git a/erpnext/non_profit/doctype/donor/donor.py b/erpnext/non_profit/doctype/donor/donor.py deleted file mode 100644 index 058321b1591..00000000000 --- a/erpnext/non_profit/doctype/donor/donor.py +++ /dev/null @@ -1,17 +0,0 @@ -# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - - -from frappe.contacts.address_and_contact import load_address_and_contact -from frappe.model.document import Document - - -class Donor(Document): - def onload(self): - """Load address and contacts in `__onload`""" - load_address_and_contact(self) - - def validate(self): - from frappe.utils import validate_email_address - if self.email: - validate_email_address(self.email.strip(), True) diff --git a/erpnext/non_profit/doctype/donor/donor_list.js b/erpnext/non_profit/doctype/donor/donor_list.js deleted file mode 100644 index 31d4d292e7c..00000000000 --- a/erpnext/non_profit/doctype/donor/donor_list.js +++ /dev/null @@ -1,3 +0,0 @@ -frappe.listview_settings['Donor'] = { - add_fields: ["donor_name", "donor_type", "image"], -}; diff --git a/erpnext/non_profit/doctype/donor/test_donor.py b/erpnext/non_profit/doctype/donor/test_donor.py deleted file mode 100644 index fe591c8e72c..00000000000 --- a/erpnext/non_profit/doctype/donor/test_donor.py +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors -# See license.txt - -import unittest - - -class TestDonor(unittest.TestCase): - pass diff --git a/erpnext/non_profit/doctype/donor_type/__init__.py b/erpnext/non_profit/doctype/donor_type/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/non_profit/doctype/donor_type/donor_type.js b/erpnext/non_profit/doctype/donor_type/donor_type.js deleted file mode 100644 index 7b1fd4fe890..00000000000 --- a/erpnext/non_profit/doctype/donor_type/donor_type.js +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Donor Type', { - refresh: function() { - - } -}); diff --git a/erpnext/non_profit/doctype/donor_type/donor_type.json b/erpnext/non_profit/doctype/donor_type/donor_type.json deleted file mode 100644 index 07118fdc826..00000000000 --- a/erpnext/non_profit/doctype/donor_type/donor_type.json +++ /dev/null @@ -1,94 +0,0 @@ -{ - "allow_copy": 0, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, - "autoname": "field:donor_type", - "beta": 0, - "creation": "2017-09-19 16:19:16.639635", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "", - "editable_grid": 1, - "engine": "InnoDB", - "fields": [ - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "donor_type", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 1, - "label": "Donor Type", - "length": 0, - "no_copy": 0, - "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, - "unique": 0 - } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 0, - "max_attachments": 0, - "modified": "2017-12-05 07:04:36.757595", - "modified_by": "Administrator", - "module": "Non Profit", - "name": "Donor Type", - "name_case": "", - "owner": "Administrator", - "permissions": [ - { - "amend": 0, - "apply_user_permissions": 0, - "cancel": 0, - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Non Profit Manager", - "set_user_permissions": 0, - "share": 1, - "submit": 0, - "write": 1 - } - ], - "quick_entry": 1, - "read_only": 0, - "read_only_onload": 0, - "restrict_to_domain": "Non Profit", - "show_name_in_global_search": 0, - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1, - "track_seen": 0 -} \ No newline at end of file diff --git a/erpnext/non_profit/doctype/donor_type/donor_type.py b/erpnext/non_profit/doctype/donor_type/donor_type.py deleted file mode 100644 index 17dca899d56..00000000000 --- a/erpnext/non_profit/doctype/donor_type/donor_type.py +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - - -from frappe.model.document import Document - - -class DonorType(Document): - pass diff --git a/erpnext/non_profit/doctype/donor_type/test_donor_type.py b/erpnext/non_profit/doctype/donor_type/test_donor_type.py deleted file mode 100644 index d433733ee25..00000000000 --- a/erpnext/non_profit/doctype/donor_type/test_donor_type.py +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors -# See license.txt - -import unittest - - -class TestDonorType(unittest.TestCase): - pass diff --git a/erpnext/non_profit/doctype/grant_application/__init__.py b/erpnext/non_profit/doctype/grant_application/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/non_profit/doctype/grant_application/grant_application.js b/erpnext/non_profit/doctype/grant_application/grant_application.js deleted file mode 100644 index 70f319b828e..00000000000 --- a/erpnext/non_profit/doctype/grant_application/grant_application.js +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Grant Application', { - refresh: function(frm) { - frappe.dynamic_link = {doc: frm.doc, fieldname: 'name', doctype: 'Grant Application'}; - - frm.toggle_display(['address_html','contact_html'], !frm.doc.__islocal); - - if(!frm.doc.__islocal) { - frappe.contacts.render_address_and_contact(frm); - } else { - frappe.contacts.clear_address_and_contact(frm); - } - - if(frm.doc.status == 'Received' && !frm.doc.email_notification_sent){ - frm.add_custom_button(__("Send Grant Review Email"), function() { - frappe.call({ - method: "erpnext.non_profit.doctype.grant_application.grant_application.send_grant_review_emails", - args: { - grant_application: frm.doc.name - } - }); - }); - } - } -}); diff --git a/erpnext/non_profit/doctype/grant_application/grant_application.json b/erpnext/non_profit/doctype/grant_application/grant_application.json deleted file mode 100644 index 2eb20879250..00000000000 --- a/erpnext/non_profit/doctype/grant_application/grant_application.json +++ /dev/null @@ -1,851 +0,0 @@ -{ - "allow_copy": 0, - "allow_guest_to_view": 1, - "allow_import": 0, - "allow_rename": 0, - "autoname": "", - "beta": 0, - "creation": "2017-09-21 12:02:01.206913", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "", - "editable_grid": 1, - "engine": "InnoDB", - "fields": [ - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "applicant_type", - "fieldtype": "Select", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Applicant Type", - "length": 0, - "no_copy": 0, - "options": "Individual\nOrganization", - "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, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "applicant_name", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Name", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "eval:doc.applicant_type=='Organization'", - "fieldname": "contact_person", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Contact Person", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "email", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Email", - "length": 0, - "no_copy": 0, - "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, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break_5", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "Open", - "fieldname": "status", - "fieldtype": "Select", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Status", - "length": 0, - "no_copy": 0, - "options": "Open\nReceived\nIn Progress\nApproved\nRejected\nExpired\nWithdrawn", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "website_url", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Website URL", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "company", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Company", - "length": 0, - "no_copy": 0, - "options": "Company", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "address_contacts", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Address and Contact", - "length": 0, - "no_copy": 0, - "options": "fa fa-map-marker", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "address_html", - "fieldtype": "HTML", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Address HTML", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break_9", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "contact_html", - "fieldtype": "HTML", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Contact HTML", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "grant_application_details", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Grant Application Details ", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "grant_description", - "fieldtype": "Long Text", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Grant Description", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "section_break_15", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "amount", - "fieldtype": "Currency", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Requested Amount", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "has_any_past_grant_record", - "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Has any past Grant Record", - "length": 0, - "no_copy": 0, - "options": "", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break_17", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "route", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Route", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "published", - "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Show on Website", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "assessment_result", - "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": "Assessment Result", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "assessment_mark", - "fieldtype": "Float", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Assessment Mark (Out of 10)", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "note", - "fieldtype": "Small Text", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Note", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break_24", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "assessment_manager", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Assessment Manager", - "length": 0, - "no_copy": 0, - "options": "User", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "email_notification_sent", - "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Email Notification Sent", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - } - ], - "has_web_view": 1, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_field": "", - "image_view": 0, - "in_create": 0, - "is_published_field": "published", - "is_submittable": 0, - "issingle": 0, - "istable": 0, - "max_attachments": 0, - "modified": "2017-12-06 12:39:57.677899", - "modified_by": "Administrator", - "module": "Non Profit", - "name": "Grant Application", - "name_case": "", - "owner": "Administrator", - "permissions": [ - { - "amend": 0, - "apply_user_permissions": 0, - "cancel": 0, - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Non Profit Manager", - "set_user_permissions": 0, - "share": 1, - "submit": 0, - "write": 1 - } - ], - "quick_entry": 0, - "read_only": 0, - "read_only_onload": 0, - "restrict_to_domain": "Non Profit", - "route": "grant-application", - "show_name_in_global_search": 0, - "sort_field": "modified", - "sort_order": "DESC", - "title_field": "applicant_name", - "track_changes": 1, - "track_seen": 0 -} \ No newline at end of file diff --git a/erpnext/non_profit/doctype/grant_application/grant_application.py b/erpnext/non_profit/doctype/grant_application/grant_application.py deleted file mode 100644 index cc5e1b1442d..00000000000 --- a/erpnext/non_profit/doctype/grant_application/grant_application.py +++ /dev/null @@ -1,58 +0,0 @@ -# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - - -import frappe -from frappe import _ -from frappe.contacts.address_and_contact import load_address_and_contact -from frappe.utils import get_url -from frappe.website.website_generator import WebsiteGenerator - - -class GrantApplication(WebsiteGenerator): - _website = frappe._dict( - condition_field = "published", - ) - - def validate(self): - if not self.route: #pylint: disable=E0203 - self.route = 'grant-application/' + self.scrub(self.name) - - def onload(self): - """Load address and contacts in `__onload`""" - load_address_and_contact(self) - - def get_context(self, context): - context.no_cache = True - context.show_sidebar = True - context.parents = [dict(label='View All Grant Applications', - route='grant-application', title='View Grants')] - -def get_list_context(context): - context.allow_guest = True - context.no_cache = True - context.no_breadcrumbs = True - context.show_sidebar = True - context.order_by = 'creation desc' - context.introduction =''' - Apply for new Grant Application''' - -@frappe.whitelist() -def send_grant_review_emails(grant_application): - grant = frappe.get_doc("Grant Application", grant_application) - url = get_url('grant-application/{0}'.format(grant_application)) - frappe.sendmail( - recipients= grant.assessment_manager, - sender=frappe.session.user, - subject='Grant Application for {0}'.format(grant.applicant_name), - message='

Please Review this grant application


' + url, - reference_doctype=grant.doctype, - reference_name=grant.name - ) - - grant.status = 'In Progress' - grant.email_notification_sent = 1 - grant.save() - frappe.db.commit() - - frappe.msgprint(_("Review Invitation Sent")) diff --git a/erpnext/non_profit/doctype/grant_application/templates/grant_application.html b/erpnext/non_profit/doctype/grant_application/templates/grant_application.html deleted file mode 100644 index 52e8469284e..00000000000 --- a/erpnext/non_profit/doctype/grant_application/templates/grant_application.html +++ /dev/null @@ -1,68 +0,0 @@ -{% extends "templates/web.html" %} - -{% block page_content %} -

{{ applicant_name }}

- {% if frappe.user == owner %} -

Edit Grant

- {% endif %} -
- - - - - - - - - - - - - - - - - - - - - -
Organization/Indvidual{{ applicant_type }}
Grant Applicant Name{{ applicant_name}}
Date{{ frappe.format_date(creation) }}
Status{{ status }}
Email{{ email }}
-

Q. Please outline your current situation and why you are applying for a grant?

-

{{ grant_description }}

-

Q. Requested grant amount

-

{{ amount }}

-

Q. Have you recevied grant from us before?

-

{{ has_any_past_grant_record }}

-

Contact

- {% if frappe.user != 'Guest' %} - - {% if contact_person %} - - - - - {% endif %} - - - - -
Contact Person{{ contact_person }}
Email{{ email }}
- {% else %} -

You must register and login to view contact details

- {% endif %} -
- {% if frappe.session.user == assessment_manager %} - {% if assessment_scale %} -

Assessment Review done

- {% endif %} - {% else %} -


Post a New Grant

- {% endif %} -{% endblock %} -{% block style %} - - -{% endblock %} diff --git a/erpnext/non_profit/doctype/grant_application/templates/grant_application_row.html b/erpnext/non_profit/doctype/grant_application/templates/grant_application_row.html deleted file mode 100644 index e375b16154d..00000000000 --- a/erpnext/non_profit/doctype/grant_application/templates/grant_application_row.html +++ /dev/null @@ -1,11 +0,0 @@ -{% if doc.published %} -
- -

{{ doc.name }}

-

- {{ frappe.format_date(doc.creation) }} -

-
-
-{% endif %} diff --git a/erpnext/non_profit/doctype/grant_application/test_grant_application.py b/erpnext/non_profit/doctype/grant_application/test_grant_application.py deleted file mode 100644 index ef267d7af86..00000000000 --- a/erpnext/non_profit/doctype/grant_application/test_grant_application.py +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors -# See license.txt - -import unittest - - -class TestGrantApplication(unittest.TestCase): - pass diff --git a/erpnext/non_profit/doctype/member/__init__.py b/erpnext/non_profit/doctype/member/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/non_profit/doctype/member/member.js b/erpnext/non_profit/doctype/member/member.js deleted file mode 100644 index e58ec0f5eea..00000000000 --- a/erpnext/non_profit/doctype/member/member.js +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Member', { - setup: function(frm) { - frappe.db.get_single_value('Non Profit Settings', 'enable_razorpay_for_memberships').then(val => { - if (val && (frm.doc.subscription_id || frm.doc.customer_id)) { - frm.set_df_property('razorpay_details_section', 'hidden', false); - } - }) - }, - - refresh: function(frm) { - - frappe.dynamic_link = {doc: frm.doc, fieldname: 'name', doctype: 'Member'}; - - frm.toggle_display(['address_html','contact_html'], !frm.doc.__islocal); - - if(!frm.doc.__islocal) { - frappe.contacts.render_address_and_contact(frm); - - // custom buttons - frm.add_custom_button(__('Accounting Ledger'), function() { - frappe.set_route('query-report', 'General Ledger', - {party_type:'Member', party:frm.doc.name}); - }); - - frm.add_custom_button(__('Accounts Receivable'), function() { - frappe.set_route('query-report', 'Accounts Receivable', {member:frm.doc.name}); - }); - - if (!frm.doc.customer) { - frm.add_custom_button(__('Create Customer'), () => { - frm.call('make_customer_and_link').then(() => { - frm.reload_doc(); - }); - }); - } - - // indicator - erpnext.utils.set_party_dashboard_indicators(frm); - - } else { - frappe.contacts.clear_address_and_contact(frm); - } - - frappe.call({ - method:"frappe.client.get_value", - args:{ - 'doctype':"Membership", - 'filters':{'member': frm.doc.name}, - 'fieldname':[ - 'to_date' - ] - }, - callback: function (data) { - if(data.message) { - frappe.model.set_value(frm.doctype,frm.docname, - "membership_expiry_date", data.message.to_date); - } - } - }); - } -}); diff --git a/erpnext/non_profit/doctype/member/member.json b/erpnext/non_profit/doctype/member/member.json deleted file mode 100644 index 7c1baf1a8d1..00000000000 --- a/erpnext/non_profit/doctype/member/member.json +++ /dev/null @@ -1,210 +0,0 @@ -{ - "actions": [], - "allow_rename": 1, - "autoname": "naming_series:", - "creation": "2017-09-11 09:24:52.898356", - "doctype": "DocType", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "naming_series", - "member_name", - "membership_expiry_date", - "column_break_5", - "membership_type", - "email_id", - "image", - "customer_section", - "customer", - "customer_name", - "supplier_section", - "supplier", - "address_contacts", - "address_html", - "column_break_9", - "contact_html", - "razorpay_details_section", - "subscription_id", - "customer_id", - "subscription_status", - "column_break_21", - "subscription_start", - "subscription_end" - ], - "fields": [ - { - "fieldname": "naming_series", - "fieldtype": "Select", - "label": "Series", - "options": "NPO-MEM-.YYYY.-", - "reqd": 1 - }, - { - "fieldname": "member_name", - "fieldtype": "Data", - "in_list_view": 1, - "label": "Member Name", - "reqd": 1 - }, - { - "fieldname": "membership_expiry_date", - "fieldtype": "Date", - "label": "Membership Expiry Date" - }, - { - "fieldname": "column_break_5", - "fieldtype": "Column Break" - }, - { - "fieldname": "membership_type", - "fieldtype": "Link", - "in_list_view": 1, - "label": "Membership Type", - "options": "Membership Type", - "reqd": 1 - }, - { - "fieldname": "image", - "fieldtype": "Attach Image", - "hidden": 1, - "label": "Image", - "no_copy": 1, - "print_hide": 1 - }, - { - "collapsible": 1, - "fieldname": "customer_section", - "fieldtype": "Section Break", - "label": "Customer" - }, - { - "fieldname": "customer", - "fieldtype": "Link", - "label": "Customer", - "options": "Customer" - }, - { - "fetch_from": "customer.customer_name", - "fieldname": "customer_name", - "fieldtype": "Data", - "label": "Customer Name", - "read_only": 1 - }, - { - "collapsible": 1, - "fieldname": "supplier_section", - "fieldtype": "Section Break", - "label": "Supplier" - }, - { - "fieldname": "supplier", - "fieldtype": "Link", - "label": "Supplier", - "options": "Supplier" - }, - { - "depends_on": "eval:!doc.__islocal;", - "fieldname": "address_contacts", - "fieldtype": "Section Break", - "label": "Address and Contact", - "options": "fa fa-map-marker" - }, - { - "fieldname": "address_html", - "fieldtype": "HTML", - "label": "Address HTML" - }, - { - "fieldname": "column_break_9", - "fieldtype": "Column Break" - }, - { - "fieldname": "contact_html", - "fieldtype": "HTML", - "label": "Contact HTML" - }, - { - "fieldname": "email_id", - "fieldtype": "Data", - "label": "Email Address", - "options": "Email" - }, - { - "fieldname": "subscription_id", - "fieldtype": "Data", - "label": "Subscription ID", - "read_only": 1 - }, - { - "fieldname": "customer_id", - "fieldtype": "Data", - "label": "Customer ID", - "read_only": 1 - }, - { - "fieldname": "razorpay_details_section", - "fieldtype": "Section Break", - "hidden": 1, - "label": "Razorpay Details" - }, - { - "fieldname": "column_break_21", - "fieldtype": "Column Break" - }, - { - "fieldname": "subscription_start", - "fieldtype": "Date", - "label": "Subscription Start " - }, - { - "fieldname": "subscription_end", - "fieldtype": "Date", - "label": "Subscription End" - }, - { - "fieldname": "subscription_status", - "fieldtype": "Select", - "label": "Subscription Status", - "options": "\nActive\nHalted" - } - ], - "image_field": "image", - "links": [], - "modified": "2021-07-11 14:27:26.368039", - "modified_by": "Administrator", - "module": "Non Profit", - "name": "Member", - "owner": "Administrator", - "permissions": [ - { - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "Non Profit Manager", - "share": 1, - "write": 1 - }, - { - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "Non Profit Member", - "share": 1, - "write": 1 - } - ], - "quick_entry": 1, - "restrict_to_domain": "Non Profit", - "sort_field": "modified", - "sort_order": "DESC", - "title_field": "member_name", - "track_changes": 1 -} \ No newline at end of file diff --git a/erpnext/non_profit/doctype/member/member.py b/erpnext/non_profit/doctype/member/member.py deleted file mode 100644 index 4d80e57eccf..00000000000 --- a/erpnext/non_profit/doctype/member/member.py +++ /dev/null @@ -1,185 +0,0 @@ -# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - - -import frappe -from frappe import _ -from frappe.contacts.address_and_contact import load_address_and_contact -from frappe.integrations.utils import get_payment_gateway_controller -from frappe.model.document import Document -from frappe.utils import cint, get_link_to_form - -from erpnext.non_profit.doctype.membership_type.membership_type import get_membership_type - - -class Member(Document): - def onload(self): - """Load address and contacts in `__onload`""" - load_address_and_contact(self) - - - def validate(self): - if self.email_id: - self.validate_email_type(self.email_id) - - def validate_email_type(self, email): - from frappe.utils import validate_email_address - validate_email_address(email.strip(), True) - - def setup_subscription(self): - non_profit_settings = frappe.get_doc('Non Profit Settings') - if not non_profit_settings.enable_razorpay_for_memberships: - frappe.throw(_('Please check Enable Razorpay for Memberships in {0} to setup subscription')).format( - get_link_to_form('Non Profit Settings', 'Non Profit Settings')) - - controller = get_payment_gateway_controller("Razorpay") - settings = controller.get_settings({}) - - plan_id = frappe.get_value("Membership Type", self.membership_type, "razorpay_plan_id") - - if not plan_id: - frappe.throw(_("Please setup Razorpay Plan ID")) - - subscription_details = { - "plan_id": plan_id, - "billing_frequency": cint(non_profit_settings.billing_frequency), - "customer_notify": 1 - } - - args = { - 'subscription_details': subscription_details - } - - subscription = controller.setup_subscription(settings, **args) - - return subscription - - @frappe.whitelist() - def make_customer_and_link(self): - if self.customer: - frappe.msgprint(_("A customer is already linked to this Member")) - - customer = create_customer(frappe._dict({ - 'fullname': self.member_name, - 'email': self.email_id, - 'phone': None - })) - - self.customer = customer - self.save() - frappe.msgprint(_("Customer {0} has been created succesfully.").format(self.customer)) - - -def get_or_create_member(user_details): - member_list = frappe.get_all("Member", filters={'email': user_details.email, 'membership_type': user_details.plan_id}) - if member_list and member_list[0]: - return member_list[0]['name'] - else: - return create_member(user_details) - -def create_member(user_details): - user_details = frappe._dict(user_details) - member = frappe.new_doc("Member") - member.update({ - "member_name": user_details.fullname, - "email_id": user_details.email, - "pan_number": user_details.pan or None, - "membership_type": user_details.plan_id, - "customer_id": user_details.customer_id or None, - "subscription_id": user_details.subscription_id or None, - "subscription_status": user_details.subscription_status or "" - }) - - member.insert(ignore_permissions=True) - member.customer = create_customer(user_details, member.name) - member.save(ignore_permissions=True) - - return member - -def create_customer(user_details, member=None): - customer = frappe.new_doc("Customer") - customer.customer_name = user_details.fullname - customer.customer_type = "Individual" - customer.flags.ignore_mandatory = True - customer.insert(ignore_permissions=True) - - try: - contact = frappe.new_doc("Contact") - contact.first_name = user_details.fullname - if user_details.mobile: - contact.add_phone(user_details.mobile, is_primary_phone=1, is_primary_mobile_no=1) - if user_details.email: - contact.add_email(user_details.email, is_primary=1) - contact.insert(ignore_permissions=True) - - contact.append("links", { - "link_doctype": "Customer", - "link_name": customer.name - }) - - if member: - contact.append("links", { - "link_doctype": "Member", - "link_name": member - }) - - contact.save(ignore_permissions=True) - - except frappe.DuplicateEntryError: - return customer.name - - except Exception as e: - frappe.log_error(frappe.get_traceback(), _("Contact Creation Failed")) - pass - - return customer.name - -@frappe.whitelist(allow_guest=True) -def create_member_subscription_order(user_details): - """Create Member subscription and order for payment - - Args: - user_details (TYPE): Description - - Returns: - Dictionary: Dictionary with subscription details - { - 'subscription_details': { - 'plan_id': 'plan_EXwyxDYDCj3X4v', - 'billing_frequency': 24, - 'customer_notify': 1 - }, - 'subscription_id': 'sub_EZycCvXFvqnC6p' - } - """ - - user_details = frappe._dict(user_details) - member = get_or_create_member(user_details) - - subscription = member.setup_subscription() - - member.subscription_id = subscription.get('subscription_id') - member.save(ignore_permissions=True) - - return subscription - -@frappe.whitelist() -def register_member(fullname, email, rzpay_plan_id, subscription_id, pan=None, mobile=None): - plan = get_membership_type(rzpay_plan_id) - if not plan: - raise frappe.DoesNotExistError - - member = frappe.db.exists("Member", {'email': email, 'subscription_id': subscription_id }) - if member: - return member - else: - member = create_member(dict( - fullname=fullname, - email=email, - plan_id=plan, - subscription_id=subscription_id, - pan=pan, - mobile=mobile - )) - - return member.name diff --git a/erpnext/non_profit/doctype/member/member_dashboard.py b/erpnext/non_profit/doctype/member/member_dashboard.py deleted file mode 100644 index 0e31e3ceb83..00000000000 --- a/erpnext/non_profit/doctype/member/member_dashboard.py +++ /dev/null @@ -1,22 +0,0 @@ -from frappe import _ - - -def get_data(): - return { - 'heatmap': True, - 'heatmap_message': _('Member Activity'), - 'fieldname': 'member', - 'non_standard_fieldnames': { - 'Bank Account': 'party' - }, - 'transactions': [ - { - 'label': _('Membership Details'), - 'items': ['Membership'] - }, - { - 'label': _('Fee'), - 'items': ['Bank Account'] - } - ] - } diff --git a/erpnext/non_profit/doctype/member/member_list.js b/erpnext/non_profit/doctype/member/member_list.js deleted file mode 100644 index 8e41e7fdde8..00000000000 --- a/erpnext/non_profit/doctype/member/member_list.js +++ /dev/null @@ -1,3 +0,0 @@ -frappe.listview_settings['Member'] = { - add_fields: ["member_name", "membership_type", "image"], -}; diff --git a/erpnext/non_profit/doctype/member/test_member.py b/erpnext/non_profit/doctype/member/test_member.py deleted file mode 100644 index 46f14ed1312..00000000000 --- a/erpnext/non_profit/doctype/member/test_member.py +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors -# See license.txt - -import unittest - - -class TestMember(unittest.TestCase): - pass diff --git a/erpnext/non_profit/doctype/membership/__init__.py b/erpnext/non_profit/doctype/membership/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/non_profit/doctype/membership/membership.js b/erpnext/non_profit/doctype/membership/membership.js deleted file mode 100644 index 31872048a06..00000000000 --- a/erpnext/non_profit/doctype/membership/membership.js +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Membership', { - setup: function(frm) { - frappe.db.get_single_value("Non Profit Settings", "enable_razorpay_for_memberships").then(val => { - if (val) frm.set_df_property("razorpay_details_section", "hidden", false); - }) - }, - - refresh: function(frm) { - if (frm.doc.__islocal) - return; - - !frm.doc.invoice && frm.add_custom_button("Generate Invoice", () => { - frm.call({ - doc: frm.doc, - method: "generate_invoice", - args: {save: true}, - freeze: true, - freeze_message: __("Creating Membership Invoice"), - callback: function(r) { - if (r.invoice) - frm.reload_doc(); - } - }); - }); - - frappe.db.get_single_value("Non Profit Settings", "send_email").then(val => { - if (val) frm.add_custom_button("Send Acknowledgement", () => { - frm.call("send_acknowlement").then(() => { - frm.reload_doc(); - }); - }); - }) - }, - - onload: function(frm) { - frm.add_fetch("membership_type", "amount", "amount"); - } -}); diff --git a/erpnext/non_profit/doctype/membership/membership.json b/erpnext/non_profit/doctype/membership/membership.json deleted file mode 100644 index 11d32f9c2b4..00000000000 --- a/erpnext/non_profit/doctype/membership/membership.json +++ /dev/null @@ -1,184 +0,0 @@ -{ - "actions": [], - "autoname": "NPO-MSH-.YYYY.-.#####", - "creation": "2017-09-11 11:39:18.492184", - "doctype": "DocType", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "member", - "member_name", - "membership_type", - "column_break_3", - "company", - "membership_status", - "membership_validity_section", - "from_date", - "to_date", - "column_break_8", - "member_since_date", - "payment_details", - "paid", - "currency", - "amount", - "invoice", - "razorpay_details_section", - "subscription_id", - "payment_id" - ], - "fields": [ - { - "fieldname": "member", - "fieldtype": "Link", - "label": "Member", - "options": "Member" - }, - { - "fieldname": "membership_type", - "fieldtype": "Link", - "in_list_view": 1, - "label": "Membership Type", - "options": "Membership Type", - "reqd": 1 - }, - { - "fieldname": "column_break_3", - "fieldtype": "Column Break" - }, - { - "fieldname": "membership_status", - "fieldtype": "Select", - "in_list_view": 1, - "in_standard_filter": 1, - "label": "Membership Status", - "options": "New\nCurrent\nExpired\nPending\nCancelled" - }, - { - "fieldname": "membership_validity_section", - "fieldtype": "Section Break", - "label": "Validity" - }, - { - "fieldname": "from_date", - "fieldtype": "Date", - "in_list_view": 1, - "label": "From", - "reqd": 1 - }, - { - "fieldname": "to_date", - "fieldtype": "Date", - "in_list_view": 1, - "label": "To", - "reqd": 1 - }, - { - "fieldname": "column_break_8", - "fieldtype": "Column Break" - }, - { - "fieldname": "member_since_date", - "fieldtype": "Date", - "label": "Member Since" - }, - { - "fieldname": "payment_details", - "fieldtype": "Section Break", - "label": "Payment Details" - }, - { - "default": "0", - "fieldname": "paid", - "fieldtype": "Check", - "label": "Paid" - }, - { - "fieldname": "currency", - "fieldtype": "Link", - "label": "Currency", - "options": "Currency" - }, - { - "fieldname": "amount", - "fieldtype": "Float", - "label": "Amount" - }, - { - "fieldname": "razorpay_details_section", - "fieldtype": "Section Break", - "hidden": 1, - "label": "Razorpay Details" - }, - { - "fieldname": "subscription_id", - "fieldtype": "Data", - "label": "Subscription ID", - "read_only": 1 - }, - { - "fieldname": "payment_id", - "fieldtype": "Data", - "label": "Payment ID", - "read_only": 1 - }, - { - "fieldname": "invoice", - "fieldtype": "Link", - "label": "Invoice", - "options": "Sales Invoice" - }, - { - "fetch_from": "member.member_name", - "fieldname": "member_name", - "fieldtype": "Data", - "label": "Member Name", - "read_only": 1 - }, - { - "fieldname": "company", - "fieldtype": "Link", - "label": "Company", - "options": "Company", - "reqd": 1 - } - ], - "index_web_pages_for_search": 1, - "links": [], - "modified": "2021-02-19 14:33:44.925122", - "modified_by": "Administrator", - "module": "Non Profit", - "name": "Membership", - "owner": "Administrator", - "permissions": [ - { - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "Non Profit Manager", - "share": 1, - "write": 1 - }, - { - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "Non Profit Member", - "share": 1, - "write": 1 - } - ], - "restrict_to_domain": "Non Profit", - "search_fields": "member, member_name", - "sort_field": "modified", - "sort_order": "DESC", - "title_field": "member_name", - "track_changes": 1 -} \ No newline at end of file diff --git a/erpnext/non_profit/doctype/membership/membership_list.js b/erpnext/non_profit/doctype/membership/membership_list.js deleted file mode 100644 index a959159899d..00000000000 --- a/erpnext/non_profit/doctype/membership/membership_list.js +++ /dev/null @@ -1,15 +0,0 @@ -frappe.listview_settings['Membership'] = { - get_indicator: function(doc) { - if (doc.membership_status == 'New') { - return [__('New'), 'blue', 'membership_status,=,New']; - } else if (doc.membership_status === 'Current') { - return [__('Current'), 'green', 'membership_status,=,Current']; - } else if (doc.membership_status === 'Pending') { - return [__('Pending'), 'yellow', 'membership_status,=,Pending']; - } else if (doc.membership_status === 'Expired') { - return [__('Expired'), 'grey', 'membership_status,=,Expired']; - } else { - return [__('Cancelled'), 'red', 'membership_status,=,Cancelled']; - } - } -}; diff --git a/erpnext/non_profit/doctype/membership/test_membership.py b/erpnext/non_profit/doctype/membership/test_membership.py deleted file mode 100644 index fbe344c6a15..00000000000 --- a/erpnext/non_profit/doctype/membership/test_membership.py +++ /dev/null @@ -1,164 +0,0 @@ -# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors -# See license.txt - -import unittest - -import frappe -from frappe.utils import add_months, nowdate - -import erpnext -from erpnext.non_profit.doctype.member.member import create_member -from erpnext.non_profit.doctype.membership.membership import update_halted_razorpay_subscription - - -class TestMembership(unittest.TestCase): - def setUp(self): - plan = setup_membership() - - # make test member - self.member_doc = create_member( - frappe._dict({ - "fullname": "_Test_Member", - "email": "_test_member_erpnext@example.com", - "plan_id": plan.name, - "subscription_id": "sub_DEX6xcJ1HSW4CR", - "customer_id": "cust_C0WlbKhp3aLA7W", - "subscription_status": "Active" - }) - ) - self.member_doc.make_customer_and_link() - self.member = self.member_doc.name - - def test_auto_generate_invoice_and_payment_entry(self): - entry = make_membership(self.member) - - # Naive test to see if at all invoice was generated and attached to member - # In any case if details were missing, the invoicing would throw an error - invoice = entry.generate_invoice(save=True) - self.assertEqual(invoice.name, entry.invoice) - - def test_renew_within_30_days(self): - # create a membership for two months - # Should work fine - make_membership(self.member, { "from_date": nowdate() }) - make_membership(self.member, { "from_date": add_months(nowdate(), 1) }) - - from frappe.utils.user import add_role - add_role("test@example.com", "Non Profit Manager") - frappe.set_user("test@example.com") - - # create next membership with expiry not within 30 days - self.assertRaises(frappe.ValidationError, make_membership, self.member, { - "from_date": add_months(nowdate(), 2), - }) - - frappe.set_user("Administrator") - # create the same membership but as administrator - make_membership(self.member, { - "from_date": add_months(nowdate(), 2), - "to_date": add_months(nowdate(), 3), - }) - - def test_halted_memberships(self): - make_membership(self.member, { - "from_date": add_months(nowdate(), 2), - "to_date": add_months(nowdate(), 3) - }) - - self.assertEqual(frappe.db.get_value("Member", self.member, "subscription_status"), "Active") - payload = get_subscription_payload() - update_halted_razorpay_subscription(data=payload) - self.assertEqual(frappe.db.get_value("Member", self.member, "subscription_status"), "Halted") - - def tearDown(self): - frappe.db.rollback() - -def set_config(key, value): - frappe.db.set_value("Non Profit Settings", None, key, value) - -def make_membership(member, payload={}): - data = { - "doctype": "Membership", - "member": member, - "membership_status": "Current", - "membership_type": "_rzpy_test_milythm", - "currency": "INR", - "paid": 1, - "from_date": nowdate(), - "amount": 100 - } - data.update(payload) - membership = frappe.get_doc(data) - membership.insert(ignore_permissions=True, ignore_if_duplicate=True) - return membership - -def create_item(item_code): - if not frappe.db.exists("Item", item_code): - item = frappe.new_doc("Item") - item.item_code = item_code - item.item_name = item_code - item.stock_uom = "Nos" - item.description = item_code - item.item_group = "All Item Groups" - item.is_stock_item = 0 - item.save() - else: - item = frappe.get_doc("Item", item_code) - return item - -def setup_membership(): - # Get default company - company = frappe.get_doc("Company", erpnext.get_default_company()) - - # update non profit settings - settings = frappe.get_doc("Non Profit Settings") - # Enable razorpay - settings.enable_razorpay_for_memberships = 1 - settings.billing_cycle = "Monthly" - settings.billing_frequency = 24 - # Enable invoicing - settings.allow_invoicing = 1 - settings.automate_membership_payment_entries = 1 - settings.company = company.name - settings.donation_company = company.name - settings.membership_payment_account = company.default_cash_account - settings.membership_debit_account = company.default_receivable_account - settings.flags.ignore_mandatory = True - settings.save() - - # make test plan - if not frappe.db.exists("Membership Type", "_rzpy_test_milythm"): - plan = frappe.new_doc("Membership Type") - plan.membership_type = "_rzpy_test_milythm" - plan.amount = 100 - plan.razorpay_plan_id = "_rzpy_test_milythm" - plan.linked_item = create_item("_Test Item for Non Profit Membership").name - plan.insert() - else: - plan = frappe.get_doc("Membership Type", "_rzpy_test_milythm") - - return plan - -def get_subscription_payload(): - return { - "entity": "event", - "account_id": "acc_BFQ7uQEaa7j2z7", - "event": "subscription.halted", - "contains": [ - "subscription" - ], - "payload": { - "subscription": { - "entity": { - "id": "sub_DEX6xcJ1HSW4CR", - "entity": "subscription", - "plan_id": "_rzpy_test_milythm", - "customer_id": "cust_C0WlbKhp3aLA7W", - "status": "halted", - "notes": { - "Important": "Notes for Internal Reference" - }, - } - } - } - } diff --git a/erpnext/non_profit/doctype/membership_type/__init__.py b/erpnext/non_profit/doctype/membership_type/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/non_profit/doctype/membership_type/membership_type.js b/erpnext/non_profit/doctype/membership_type/membership_type.js deleted file mode 100644 index 2f2427629c3..00000000000 --- a/erpnext/non_profit/doctype/membership_type/membership_type.js +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Membership Type', { - refresh: function (frm) { - frappe.db.get_single_value('Non Profit Settings', 'enable_razorpay_for_memberships').then(val => { - if (val) frm.set_df_property('razorpay_plan_id', 'hidden', false); - }); - - frappe.db.get_single_value('Non Profit Settings', 'allow_invoicing').then(val => { - if (val) frm.set_df_property('linked_item', 'hidden', false); - }); - - frm.set_query('linked_item', () => { - return { - filters: { - is_stock_item: 0 - } - }; - }); - } -}); diff --git a/erpnext/non_profit/doctype/membership_type/membership_type.json b/erpnext/non_profit/doctype/membership_type/membership_type.json deleted file mode 100644 index 6ce1ecde123..00000000000 --- a/erpnext/non_profit/doctype/membership_type/membership_type.json +++ /dev/null @@ -1,71 +0,0 @@ -{ - "actions": [], - "autoname": "field:membership_type", - "creation": "2017-09-18 12:56:56.343999", - "doctype": "DocType", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "membership_type", - "amount", - "razorpay_plan_id", - "linked_item" - ], - "fields": [ - { - "fieldname": "membership_type", - "fieldtype": "Data", - "in_list_view": 1, - "in_standard_filter": 1, - "label": "Membership Type", - "reqd": 1, - "unique": 1 - }, - { - "fieldname": "amount", - "fieldtype": "Float", - "in_list_view": 1, - "label": "Amount", - "reqd": 1 - }, - { - "fieldname": "razorpay_plan_id", - "fieldtype": "Data", - "hidden": 1, - "label": "Razorpay Plan ID", - "unique": 1 - }, - { - "fieldname": "linked_item", - "fieldtype": "Link", - "label": "Linked Item", - "options": "Item", - "unique": 1 - } - ], - "links": [], - "modified": "2020-08-05 15:21:43.595745", - "modified_by": "Administrator", - "module": "Non Profit", - "name": "Membership Type", - "owner": "Administrator", - "permissions": [ - { - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "Non Profit Manager", - "share": 1, - "write": 1 - } - ], - "quick_entry": 1, - "restrict_to_domain": "Non Profit", - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1 -} \ No newline at end of file diff --git a/erpnext/non_profit/doctype/membership_type/membership_type.py b/erpnext/non_profit/doctype/membership_type/membership_type.py deleted file mode 100644 index b4464215715..00000000000 --- a/erpnext/non_profit/doctype/membership_type/membership_type.py +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - - -import frappe -from frappe import _ -from frappe.model.document import Document - - -class MembershipType(Document): - def validate(self): - if self.linked_item: - is_stock_item = frappe.db.get_value("Item", self.linked_item, "is_stock_item") - if is_stock_item: - frappe.throw(_("The Linked Item should be a service item")) - -def get_membership_type(razorpay_id): - return frappe.db.exists("Membership Type", {"razorpay_plan_id": razorpay_id}) diff --git a/erpnext/non_profit/doctype/membership_type/test_membership_type.py b/erpnext/non_profit/doctype/membership_type/test_membership_type.py deleted file mode 100644 index 98bc087acde..00000000000 --- a/erpnext/non_profit/doctype/membership_type/test_membership_type.py +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors -# See license.txt - -import unittest - - -class TestMembershipType(unittest.TestCase): - pass diff --git a/erpnext/non_profit/doctype/non_profit_settings/__init__.py b/erpnext/non_profit/doctype/non_profit_settings/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/non_profit/doctype/non_profit_settings/non_profit_settings.js b/erpnext/non_profit/doctype/non_profit_settings/non_profit_settings.js deleted file mode 100644 index 4c4ca9834b0..00000000000 --- a/erpnext/non_profit/doctype/non_profit_settings/non_profit_settings.js +++ /dev/null @@ -1,133 +0,0 @@ -// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors -// For license information, please see license.txt - -frappe.ui.form.on("Non Profit Settings", { - refresh: function(frm) { - frm.set_query("inv_print_format", function() { - return { - filters: { - "doc_type": "Sales Invoice" - } - }; - }); - - frm.set_query("membership_print_format", function() { - return { - filters: { - "doc_type": "Membership" - } - }; - }); - - frm.set_query("membership_debit_account", function() { - return { - filters: { - "account_type": "Receivable", - "is_group": 0, - "company": frm.doc.company - } - }; - }); - - frm.set_query("donation_debit_account", function() { - return { - filters: { - "account_type": "Receivable", - "is_group": 0, - "company": frm.doc.donation_company - } - }; - }); - - frm.set_query("membership_payment_account", function () { - var account_types = ["Bank", "Cash"]; - return { - filters: { - "account_type": ["in", account_types], - "is_group": 0, - "company": frm.doc.company - } - }; - }); - - frm.set_query("donation_payment_account", function () { - var account_types = ["Bank", "Cash"]; - return { - filters: { - "account_type": ["in", account_types], - "is_group": 0, - "company": frm.doc.donation_company - } - }; - }); - - let docs_url = "https://docs.erpnext.com/docs/user/manual/en/non_profit/membership"; - - frm.set_intro(__("You can learn more about memberships in the manual. ") + `${__('ERPNext Docs')}`, true); - frm.trigger("setup_buttons_for_membership"); - frm.trigger("setup_buttons_for_donation"); - }, - - setup_buttons_for_membership: function(frm) { - let label; - - if (frm.doc.membership_webhook_secret) { - - frm.add_custom_button(__("Copy Webhook URL"), () => { - frappe.utils.copy_to_clipboard(`https://${frappe.boot.sitename}/api/method/erpnext.non_profit.doctype.membership.membership.trigger_razorpay_subscription`); - }, __("Memberships")); - - frm.add_custom_button(__("Revoke Key"), () => { - frm.call("revoke_key", { - key: "membership_webhook_secret" - }).then(() => { - frm.refresh(); - }); - }, __("Memberships")); - - label = __("Regenerate Webhook Secret"); - - } else { - label = __("Generate Webhook Secret"); - } - - frm.add_custom_button(label, () => { - frm.call("generate_webhook_secret", { - field: "membership_webhook_secret" - }).then(() => { - frm.refresh(); - }); - }, __("Memberships")); - }, - - setup_buttons_for_donation: function(frm) { - let label; - - if (frm.doc.donation_webhook_secret) { - label = __("Regenerate Webhook Secret"); - - frm.add_custom_button(__("Copy Webhook URL"), () => { - frappe.utils.copy_to_clipboard(`https://${frappe.boot.sitename}/api/method/erpnext.non_profit.doctype.donation.donation.capture_razorpay_donations`); - }, __("Donations")); - - frm.add_custom_button(__("Revoke Key"), () => { - frm.call("revoke_key", { - key: "donation_webhook_secret" - }).then(() => { - frm.refresh(); - }); - }, __("Donations")); - - } else { - label = __("Generate Webhook Secret"); - } - - frm.add_custom_button(label, () => { - frm.call("generate_webhook_secret", { - field: "donation_webhook_secret" - }).then(() => { - frm.refresh(); - }); - }, __("Donations")); - } -}); diff --git a/erpnext/non_profit/doctype/non_profit_settings/non_profit_settings.json b/erpnext/non_profit/doctype/non_profit_settings/non_profit_settings.json deleted file mode 100644 index 25ff0c1bb02..00000000000 --- a/erpnext/non_profit/doctype/non_profit_settings/non_profit_settings.json +++ /dev/null @@ -1,273 +0,0 @@ -{ - "actions": [], - "creation": "2020-03-29 12:57:03.005120", - "doctype": "DocType", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "enable_razorpay_for_memberships", - "razorpay_settings_section", - "billing_cycle", - "billing_frequency", - "membership_webhook_secret", - "column_break_6", - "allow_invoicing", - "automate_membership_invoicing", - "automate_membership_payment_entries", - "company", - "membership_debit_account", - "membership_payment_account", - "column_break_9", - "send_email", - "send_invoice", - "membership_print_format", - "inv_print_format", - "email_template", - "donation_settings_section", - "donation_company", - "default_donor_type", - "donation_webhook_secret", - "column_break_22", - "automate_donation_payment_entries", - "donation_debit_account", - "donation_payment_account", - "section_break_27", - "creation_user" - ], - "fields": [ - { - "fieldname": "billing_cycle", - "fieldtype": "Select", - "label": "Billing Cycle", - "options": "Monthly\nYearly" - }, - { - "depends_on": "eval:doc.enable_razorpay_for_memberships", - "fieldname": "razorpay_settings_section", - "fieldtype": "Section Break", - "label": "RazorPay Settings for Memberships" - }, - { - "description": "The number of billing cycles for which the customer should be charged. For example, if a customer is buying a 1-year membership that should be billed on a monthly basis, this value should be 12.", - "fieldname": "billing_frequency", - "fieldtype": "Int", - "label": "Billing Frequency" - }, - { - "fieldname": "column_break_6", - "fieldtype": "Section Break", - "label": "Membership Invoicing" - }, - { - "fieldname": "column_break_9", - "fieldtype": "Column Break" - }, - { - "description": "This company will be set for the Memberships created via webhook.", - "fieldname": "company", - "fieldtype": "Link", - "in_list_view": 1, - "label": "Company", - "options": "Company", - "reqd": 1 - }, - { - "default": "0", - "depends_on": "eval:doc.allow_invoicing && doc.send_email", - "fieldname": "send_invoice", - "fieldtype": "Check", - "label": "Send Invoice with Email" - }, - { - "default": "0", - "fieldname": "send_email", - "fieldtype": "Check", - "label": "Send Membership Acknowledgement" - }, - { - "depends_on": "eval: doc.send_invoice", - "fieldname": "inv_print_format", - "fieldtype": "Link", - "label": "Invoice Print Format", - "mandatory_depends_on": "eval: doc.send_invoice", - "options": "Print Format" - }, - { - "depends_on": "eval:doc.send_email", - "fieldname": "membership_print_format", - "fieldtype": "Link", - "label": "Membership Print Format", - "options": "Print Format" - }, - { - "depends_on": "eval:doc.send_email", - "fieldname": "email_template", - "fieldtype": "Link", - "label": "Email Template", - "mandatory_depends_on": "eval:doc.send_email", - "options": "Email Template" - }, - { - "default": "0", - "fieldname": "allow_invoicing", - "fieldtype": "Check", - "label": "Allow Invoicing for Memberships", - "mandatory_depends_on": "eval:doc.send_invoice || doc.make_payment_entry" - }, - { - "default": "0", - "depends_on": "eval:doc.allow_invoicing", - "description": "Automatically create an invoice when payment is authorized from a web form entry", - "fieldname": "automate_membership_invoicing", - "fieldtype": "Check", - "label": "Automate Invoicing for Web Forms" - }, - { - "default": "0", - "depends_on": "eval:doc.allow_invoicing", - "description": "Auto creates Payment Entry for Sales Invoices created for Membership from web forms.", - "fieldname": "automate_membership_payment_entries", - "fieldtype": "Check", - "label": "Automate Payment Entry Creation" - }, - { - "default": "0", - "fieldname": "enable_razorpay_for_memberships", - "fieldtype": "Check", - "label": "Enable RazorPay For Memberships" - }, - { - "depends_on": "eval:doc.automate_membership_payment_entries", - "description": "Account for accepting membership payments", - "fieldname": "membership_payment_account", - "fieldtype": "Link", - "label": "Membership Payment To", - "mandatory_depends_on": "eval:doc.automate_membership_payment_entries", - "options": "Account" - }, - { - "fieldname": "membership_webhook_secret", - "fieldtype": "Password", - "label": "Membership Webhook Secret", - "read_only": 1 - }, - { - "fieldname": "donation_webhook_secret", - "fieldtype": "Password", - "label": "Donation Webhook Secret", - "read_only": 1 - }, - { - "depends_on": "automate_donation_payment_entries", - "description": "Account for accepting donation payments", - "fieldname": "donation_payment_account", - "fieldtype": "Link", - "label": "Donation Payment To", - "mandatory_depends_on": "automate_donation_payment_entries", - "options": "Account" - }, - { - "default": "0", - "description": "Auto creates Payment Entry for Donations created from web forms.", - "fieldname": "automate_donation_payment_entries", - "fieldtype": "Check", - "label": "Automate Donation Payment Entries" - }, - { - "depends_on": "eval:doc.allow_invoicing", - "fieldname": "membership_debit_account", - "fieldtype": "Link", - "label": "Debit Account", - "mandatory_depends_on": "eval:doc.allow_invoicing", - "options": "Account" - }, - { - "depends_on": "automate_donation_payment_entries", - "fieldname": "donation_debit_account", - "fieldtype": "Link", - "label": "Debit Account", - "mandatory_depends_on": "automate_donation_payment_entries", - "options": "Account" - }, - { - "description": "This company will be set for the Donations created via webhook.", - "fieldname": "donation_company", - "fieldtype": "Link", - "in_list_view": 1, - "label": "Company", - "options": "Company", - "reqd": 1 - }, - { - "fieldname": "donation_settings_section", - "fieldtype": "Section Break", - "label": "Donation Settings" - }, - { - "fieldname": "column_break_22", - "fieldtype": "Column Break" - }, - { - "description": "This Donor Type will be set for the Donor created via Donation web form entry.", - "fieldname": "default_donor_type", - "fieldtype": "Link", - "in_list_view": 1, - "label": "Default Donor Type", - "options": "Donor Type", - "reqd": 1 - }, - { - "fieldname": "section_break_27", - "fieldtype": "Section Break" - }, - { - "description": "The user that will be used to create Donations, Memberships, Invoices, and Payment Entries. This user should have the relevant permissions.", - "fieldname": "creation_user", - "fieldtype": "Link", - "label": "Creation User", - "options": "User", - "reqd": 1 - } - ], - "index_web_pages_for_search": 1, - "issingle": 1, - "links": [], - "modified": "2021-03-11 10:43:38.124240", - "modified_by": "Administrator", - "module": "Non Profit", - "name": "Non Profit Settings", - "owner": "Administrator", - "permissions": [ - { - "create": 1, - "delete": 1, - "email": 1, - "print": 1, - "read": 1, - "role": "System Manager", - "share": 1, - "write": 1 - }, - { - "create": 1, - "delete": 1, - "email": 1, - "print": 1, - "read": 1, - "role": "Non Profit Manager", - "share": 1, - "write": 1 - }, - { - "email": 1, - "print": 1, - "read": 1, - "role": "Non Profit Member", - "share": 1 - } - ], - "quick_entry": 1, - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1 -} \ No newline at end of file diff --git a/erpnext/non_profit/doctype/non_profit_settings/non_profit_settings.py b/erpnext/non_profit/doctype/non_profit_settings/non_profit_settings.py deleted file mode 100644 index ace66055427..00000000000 --- a/erpnext/non_profit/doctype/non_profit_settings/non_profit_settings.py +++ /dev/null @@ -1,38 +0,0 @@ -# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - - -import frappe -from frappe import _ -from frappe.integrations.utils import get_payment_gateway_controller -from frappe.model.document import Document - - -class NonProfitSettings(Document): - @frappe.whitelist() - def generate_webhook_secret(self, field="membership_webhook_secret"): - key = frappe.generate_hash(length=20) - self.set(field, key) - self.save() - - secret_for = "Membership" if field == "membership_webhook_secret" else "Donation" - - frappe.msgprint( - _("Here is your webhook secret for {0} API, this will be shown to you only once.").format(secret_for) + "

" + key, - _("Webhook Secret") - ) - - @frappe.whitelist() - def revoke_key(self, key): - self.set(key, None) - self.save() - - def get_webhook_secret(self, endpoint="Membership"): - fieldname = "membership_webhook_secret" if endpoint == "Membership" else "donation_webhook_secret" - return self.get_password(fieldname=fieldname, raise_exception=False) - -@frappe.whitelist() -def get_plans_for_membership(*args, **kwargs): - controller = get_payment_gateway_controller("Razorpay") - plans = controller.get_plans() - return [plan.get("item") for plan in plans.get("items")] diff --git a/erpnext/non_profit/doctype/non_profit_settings/test_non_profit_settings.py b/erpnext/non_profit/doctype/non_profit_settings/test_non_profit_settings.py deleted file mode 100644 index 51d1ba02eba..00000000000 --- a/erpnext/non_profit/doctype/non_profit_settings/test_non_profit_settings.py +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors -# See license.txt - -# import frappe -import unittest - - -class TestNonProfitSettings(unittest.TestCase): - pass diff --git a/erpnext/non_profit/doctype/volunteer/__init__.py b/erpnext/non_profit/doctype/volunteer/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/non_profit/doctype/volunteer/test_volunteer.py b/erpnext/non_profit/doctype/volunteer/test_volunteer.py deleted file mode 100644 index 0a0ab2cf342..00000000000 --- a/erpnext/non_profit/doctype/volunteer/test_volunteer.py +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors -# See license.txt - -import unittest - - -class TestVolunteer(unittest.TestCase): - pass diff --git a/erpnext/non_profit/doctype/volunteer/volunteer.js b/erpnext/non_profit/doctype/volunteer/volunteer.js deleted file mode 100644 index ac93d8c8011..00000000000 --- a/erpnext/non_profit/doctype/volunteer/volunteer.js +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Volunteer', { - refresh: function(frm) { - - frappe.dynamic_link = {doc: frm.doc, fieldname: 'name', doctype: 'Volunteer'}; - - frm.toggle_display(['address_html','contact_html'], !frm.doc.__islocal); - - if(!frm.doc.__islocal) { - frappe.contacts.render_address_and_contact(frm); - } else { - frappe.contacts.clear_address_and_contact(frm); - } - } -}); diff --git a/erpnext/non_profit/doctype/volunteer/volunteer.json b/erpnext/non_profit/doctype/volunteer/volunteer.json deleted file mode 100644 index 08b7f87b2a9..00000000000 --- a/erpnext/non_profit/doctype/volunteer/volunteer.json +++ /dev/null @@ -1,148 +0,0 @@ -{ - "actions": [], - "allow_rename": 1, - "autoname": "field:email", - "creation": "2017-09-19 16:16:45.676019", - "doctype": "DocType", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "volunteer_name", - "column_break_5", - "volunteer_type", - "email", - "image", - "address_contacts", - "address_html", - "column_break_9", - "contact_html", - "volunteer_availability_and_skills_details", - "availability", - "availability_timeslot", - "column_break_12", - "volunteer_skills", - "section_break_15", - "note" - ], - "fields": [ - { - "fieldname": "volunteer_name", - "fieldtype": "Data", - "in_list_view": 1, - "label": "Volunteer Name", - "reqd": 1 - }, - { - "fieldname": "column_break_5", - "fieldtype": "Column Break" - }, - { - "fieldname": "volunteer_type", - "fieldtype": "Link", - "in_list_view": 1, - "label": "Volunteer Type", - "options": "Volunteer Type", - "reqd": 1 - }, - { - "fieldname": "email", - "fieldtype": "Data", - "in_list_view": 1, - "label": "Email", - "reqd": 1, - "unique": 1 - }, - { - "fieldname": "image", - "fieldtype": "Attach Image", - "hidden": 1, - "label": "Image", - "no_copy": 1, - "print_hide": 1 - }, - { - "depends_on": "eval:!doc.__islocal;", - "fieldname": "address_contacts", - "fieldtype": "Section Break", - "label": "Address and Contact", - "options": "fa fa-map-marker" - }, - { - "fieldname": "address_html", - "fieldtype": "HTML", - "label": "Address HTML" - }, - { - "fieldname": "column_break_9", - "fieldtype": "Column Break" - }, - { - "fieldname": "contact_html", - "fieldtype": "HTML", - "label": "Contact HTML" - }, - { - "fieldname": "volunteer_availability_and_skills_details", - "fieldtype": "Section Break", - "label": "Availability and Skills" - }, - { - "fieldname": "availability", - "fieldtype": "Select", - "label": "Availability", - "options": "\nWeekly\nWeekdays\nWeekends" - }, - { - "fieldname": "availability_timeslot", - "fieldtype": "Select", - "label": "Availability Timeslot", - "options": "\nMorning\nAfternoon\nEvening\nAnytime" - }, - { - "fieldname": "column_break_12", - "fieldtype": "Column Break" - }, - { - "fieldname": "volunteer_skills", - "fieldtype": "Table", - "label": "Volunteer Skills", - "options": "Volunteer Skill" - }, - { - "fieldname": "section_break_15", - "fieldtype": "Section Break" - }, - { - "fieldname": "note", - "fieldtype": "Long Text", - "label": "Note" - } - ], - "image_field": "image", - "links": [], - "modified": "2020-09-16 23:45:15.595952", - "modified_by": "Administrator", - "module": "Non Profit", - "name": "Volunteer", - "owner": "Administrator", - "permissions": [ - { - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "Non Profit Manager", - "share": 1, - "write": 1 - } - ], - "quick_entry": 1, - "restrict_to_domain": "Non Profit", - "sort_field": "modified", - "sort_order": "DESC", - "title_field": "volunteer_name", - "track_changes": 1 -} \ No newline at end of file diff --git a/erpnext/non_profit/doctype/volunteer/volunteer.py b/erpnext/non_profit/doctype/volunteer/volunteer.py deleted file mode 100644 index b44d67dae39..00000000000 --- a/erpnext/non_profit/doctype/volunteer/volunteer.py +++ /dev/null @@ -1,12 +0,0 @@ -# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - - -from frappe.contacts.address_and_contact import load_address_and_contact -from frappe.model.document import Document - - -class Volunteer(Document): - def onload(self): - """Load address and contacts in `__onload`""" - load_address_and_contact(self) diff --git a/erpnext/non_profit/doctype/volunteer_skill/__init__.py b/erpnext/non_profit/doctype/volunteer_skill/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/non_profit/doctype/volunteer_skill/volunteer_skill.json b/erpnext/non_profit/doctype/volunteer_skill/volunteer_skill.json deleted file mode 100644 index 7d210aa7bdf..00000000000 --- a/erpnext/non_profit/doctype/volunteer_skill/volunteer_skill.json +++ /dev/null @@ -1,73 +0,0 @@ -{ - "allow_copy": 0, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, - "beta": 0, - "creation": "2017-09-20 15:26:26.453435", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "", - "editable_grid": 1, - "engine": "InnoDB", - "fields": [ - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "volunteer_skill", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Volunteer Skill", - "length": 0, - "no_copy": 0, - "options": "", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 1, - "max_attachments": 0, - "modified": "2017-12-06 11:54:14.396354", - "modified_by": "Administrator", - "module": "Non Profit", - "name": "Volunteer Skill", - "name_case": "", - "owner": "Administrator", - "permissions": [], - "quick_entry": 1, - "read_only": 0, - "read_only_onload": 0, - "restrict_to_domain": "Non Profit", - "show_name_in_global_search": 0, - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1, - "track_seen": 0 -} \ No newline at end of file diff --git a/erpnext/non_profit/doctype/volunteer_skill/volunteer_skill.py b/erpnext/non_profit/doctype/volunteer_skill/volunteer_skill.py deleted file mode 100644 index fe7251876d2..00000000000 --- a/erpnext/non_profit/doctype/volunteer_skill/volunteer_skill.py +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - - -from frappe.model.document import Document - - -class VolunteerSkill(Document): - pass diff --git a/erpnext/non_profit/doctype/volunteer_type/__init__.py b/erpnext/non_profit/doctype/volunteer_type/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/non_profit/doctype/volunteer_type/test_volunteer_type.py b/erpnext/non_profit/doctype/volunteer_type/test_volunteer_type.py deleted file mode 100644 index cef27c83a56..00000000000 --- a/erpnext/non_profit/doctype/volunteer_type/test_volunteer_type.py +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors -# See license.txt - -import unittest - - -class TestVolunteerType(unittest.TestCase): - pass diff --git a/erpnext/non_profit/doctype/volunteer_type/volunteer_type.js b/erpnext/non_profit/doctype/volunteer_type/volunteer_type.js deleted file mode 100644 index 5c17505be9d..00000000000 --- a/erpnext/non_profit/doctype/volunteer_type/volunteer_type.js +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Volunteer Type', { - refresh: function() { - - } -}); diff --git a/erpnext/non_profit/doctype/volunteer_type/volunteer_type.json b/erpnext/non_profit/doctype/volunteer_type/volunteer_type.json deleted file mode 100644 index 256b25fe911..00000000000 --- a/erpnext/non_profit/doctype/volunteer_type/volunteer_type.json +++ /dev/null @@ -1,94 +0,0 @@ -{ - "allow_copy": 0, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, - "autoname": "prompt", - "beta": 0, - "creation": "2017-09-19 16:13:07.763273", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "", - "editable_grid": 1, - "engine": "InnoDB", - "fields": [ - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "amount", - "fieldtype": "Float", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Amount", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 0, - "max_attachments": 0, - "modified": "2017-12-06 11:52:08.800425", - "modified_by": "Administrator", - "module": "Non Profit", - "name": "Volunteer Type", - "name_case": "", - "owner": "Administrator", - "permissions": [ - { - "amend": 0, - "apply_user_permissions": 0, - "cancel": 0, - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Non Profit Manager", - "set_user_permissions": 0, - "share": 1, - "submit": 0, - "write": 1 - } - ], - "quick_entry": 1, - "read_only": 0, - "read_only_onload": 0, - "restrict_to_domain": "Non Profit", - "show_name_in_global_search": 0, - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1, - "track_seen": 0 -} \ No newline at end of file diff --git a/erpnext/non_profit/doctype/volunteer_type/volunteer_type.py b/erpnext/non_profit/doctype/volunteer_type/volunteer_type.py deleted file mode 100644 index 3b1ae1a88e0..00000000000 --- a/erpnext/non_profit/doctype/volunteer_type/volunteer_type.py +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - - -from frappe.model.document import Document - - -class VolunteerType(Document): - pass diff --git a/erpnext/non_profit/report/__init__.py b/erpnext/non_profit/report/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/non_profit/report/expiring_memberships/__init__.py b/erpnext/non_profit/report/expiring_memberships/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/non_profit/report/expiring_memberships/expiring_memberships.js b/erpnext/non_profit/report/expiring_memberships/expiring_memberships.js deleted file mode 100644 index be3a2438fc3..00000000000 --- a/erpnext/non_profit/report/expiring_memberships/expiring_memberships.js +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors -// For license information, please see license.txt -/* eslint-disable */ - -frappe.query_reports["Expiring Memberships"] = { - "filters": [ - { - "fieldname": "fiscal_year", - "label": __("Fiscal Year"), - "fieldtype": "Link", - "options": "Fiscal Year", - "default": frappe.defaults.get_user_default("fiscal_year"), - "reqd": 1 - }, - { - "fieldname":"month", - "label": __("Month"), - "fieldtype": "Select", - "options": "Jan\nFeb\nMar\nApr\nMay\nJun\nJul\nAug\nSep\nOct\nNov\nDec", - "default": ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", - "Dec"][frappe.datetime.str_to_obj(frappe.datetime.get_today()).getMonth()], - } - ] -} diff --git a/erpnext/non_profit/report/expiring_memberships/expiring_memberships.json b/erpnext/non_profit/report/expiring_memberships/expiring_memberships.json deleted file mode 100644 index c3110572011..00000000000 --- a/erpnext/non_profit/report/expiring_memberships/expiring_memberships.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "add_total_row": 0, - "apply_user_permissions": 1, - "creation": "2018-05-24 11:44:08.942809", - "disabled": 0, - "docstatus": 0, - "doctype": "Report", - "idx": 0, - "is_standard": "Yes", - "letter_head": "ERPNext Foundation", - "modified": "2018-05-24 11:44:08.942809", - "modified_by": "Administrator", - "module": "Non Profit", - "name": "Expiring Memberships", - "owner": "Administrator", - "ref_doctype": "Membership", - "report_name": "Expiring Memberships", - "report_type": "Script Report", - "roles": [ - { - "role": "Non Profit Manager" - }, - { - "role": "Non Profit Member" - } - ] -} \ No newline at end of file diff --git a/erpnext/non_profit/report/expiring_memberships/expiring_memberships.py b/erpnext/non_profit/report/expiring_memberships/expiring_memberships.py deleted file mode 100644 index 3ddbfdc3b0d..00000000000 --- a/erpnext/non_profit/report/expiring_memberships/expiring_memberships.py +++ /dev/null @@ -1,34 +0,0 @@ -# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - - -import frappe -from frappe import _ - - -def execute(filters=None): - columns = get_columns(filters) - data = get_data(filters) - return columns, data - -def get_columns(filters): - return [ - _("Membership Type") + ":Link/Membership Type:100", _("Membership ID") + ":Link/Membership:140", - _("Member ID") + ":Link/Member:140", _("Member Name") + ":Data:140", _("Email") + ":Data:140", - _("Expiring On") + ":Date:120" - ] - -def get_data(filters): - - filters["month"] = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"].index(filters.month) + 1 - - return frappe.db.sql(""" - select ms.membership_type,ms.name,m.name,m.member_name,m.email,ms.max_membership_date - from `tabMember` m - inner join (select name,membership_type,max(to_date) as max_membership_date,member - from `tabMembership` - where paid = 1 - group by member - order by max_membership_date asc) ms - on m.name = ms.member - where month(max_membership_date) = %(month)s and year(max_membership_date) = %(year)s """,{'month': filters.get('month'),'year':filters.get('fiscal_year')}) diff --git a/erpnext/non_profit/utils.py b/erpnext/non_profit/utils.py deleted file mode 100644 index 47ea5f57832..00000000000 --- a/erpnext/non_profit/utils.py +++ /dev/null @@ -1,12 +0,0 @@ -import frappe - - -def get_company(): - company = frappe.defaults.get_defaults().company - if company: - return company - else: - company = frappe.get_list("Company", limit=1) - if company: - return company[0].name - return None diff --git a/erpnext/non_profit/web_form/__init__.py b/erpnext/non_profit/web_form/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/non_profit/web_form/certification_application/__init__.py b/erpnext/non_profit/web_form/certification_application/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/non_profit/web_form/certification_application/certification_application.js b/erpnext/non_profit/web_form/certification_application/certification_application.js deleted file mode 100644 index 8b455edafa2..00000000000 --- a/erpnext/non_profit/web_form/certification_application/certification_application.js +++ /dev/null @@ -1,16 +0,0 @@ -frappe.ready(function() { - // bind events here - $(".page-header-actions-block .btn-primary, .page-header-actions-block .btn-default").addClass('hidden'); - $(".text-right .btn-primary").addClass('hidden'); - - if (frappe.utils.get_url_arg('name')) { - $('.page-content .btn-form-submit').addClass('hidden'); - } else { - user_name = frappe.full_name - user_email_id = frappe.session.user - $('[data-fieldname="currency"]').val("INR"); - $('[data-fieldname="name_of_applicant"]').val(user_name); - $('[data-fieldname="email"]').val(user_email_id); - $('[data-fieldname="amount"]').val(20000); - } -}) diff --git a/erpnext/non_profit/web_form/certification_application/certification_application.json b/erpnext/non_profit/web_form/certification_application/certification_application.json deleted file mode 100644 index 5fda978fba0..00000000000 --- a/erpnext/non_profit/web_form/certification_application/certification_application.json +++ /dev/null @@ -1,79 +0,0 @@ -{ - "accept_payment": 1, - "allow_comments": 0, - "allow_delete": 0, - "allow_edit": 0, - "allow_incomplete": 0, - "allow_multiple": 1, - "allow_print": 0, - "amount": 0.0, - "amount_based_on_field": 1, - "amount_field": "amount", - "creation": "2018-06-08 16:24:05.805225", - "doc_type": "Certification Application", - "docstatus": 0, - "doctype": "Web Form", - "idx": 0, - "introduction_text": "", - "is_standard": 1, - "login_required": 1, - "max_attachment_size": 0, - "modified": "2018-06-11 16:11:14.544987", - "modified_by": "Administrator", - "module": "Non Profit", - "name": "certification-application", - "owner": "Administrator", - "payment_button_help": "Pay for your certification using RazorPay", - "payment_button_label": "Pay Now", - "payment_gateway": "Razorpay", - "published": 1, - "route": "certification-application", - "show_sidebar": 1, - "sidebar_items": [], - "success_url": "/certification-application", - "title": "Certification Application", - "web_form_fields": [ - { - "fieldname": "name_of_applicant", - "fieldtype": "Data", - "hidden": 0, - "label": "Name of Applicant", - "max_length": 0, - "max_value": 0, - "read_only": 0, - "reqd": 0 - }, - { - "fieldname": "email", - "fieldtype": "Link", - "hidden": 0, - "label": "Email", - "max_length": 0, - "max_value": 0, - "options": "User", - "read_only": 1, - "reqd": 1 - }, - { - "fieldname": "currency", - "fieldtype": "Select", - "hidden": 0, - "label": "Currency", - "max_length": 0, - "max_value": 0, - "options": "USD\nINR", - "read_only": 1, - "reqd": 0 - }, - { - "fieldname": "amount", - "fieldtype": "Float", - "hidden": 0, - "label": "Amount", - "max_length": 0, - "max_value": 0, - "read_only": 1, - "reqd": 0 - } - ] -} \ No newline at end of file diff --git a/erpnext/non_profit/web_form/certification_application/certification_application.py b/erpnext/non_profit/web_form/certification_application/certification_application.py deleted file mode 100644 index 02e3e933330..00000000000 --- a/erpnext/non_profit/web_form/certification_application/certification_application.py +++ /dev/null @@ -1,3 +0,0 @@ -def get_context(context): - # do your magic here - pass diff --git a/erpnext/non_profit/web_form/certification_application_usd/__init__.py b/erpnext/non_profit/web_form/certification_application_usd/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/non_profit/web_form/certification_application_usd/certification_application_usd.js b/erpnext/non_profit/web_form/certification_application_usd/certification_application_usd.js deleted file mode 100644 index 005d1dd6c13..00000000000 --- a/erpnext/non_profit/web_form/certification_application_usd/certification_application_usd.js +++ /dev/null @@ -1,16 +0,0 @@ -frappe.ready(function() { - // bind events here - $(".page-header-actions-block .btn-primary, .page-header-actions-block .btn-default").addClass('hidden'); - $(".text-right .btn-primary").addClass('hidden'); - - if (frappe.utils.get_url_arg('name')) { - $('.page-content .btn-form-submit').addClass('hidden'); - } else { - user_name = frappe.full_name - user_email_id = frappe.session.user - $('[data-fieldname="currency"]').val("USD"); - $('[data-fieldname="name_of_applicant"]').val(user_name); - $('[data-fieldname="email"]').val(user_email_id); - $('[data-fieldname="amount"]').val(300); - } -}) diff --git a/erpnext/non_profit/web_form/certification_application_usd/certification_application_usd.json b/erpnext/non_profit/web_form/certification_application_usd/certification_application_usd.json deleted file mode 100644 index 266109f5800..00000000000 --- a/erpnext/non_profit/web_form/certification_application_usd/certification_application_usd.json +++ /dev/null @@ -1,80 +0,0 @@ -{ - "accept_payment": 1, - "allow_comments": 0, - "allow_delete": 0, - "allow_edit": 0, - "allow_incomplete": 0, - "allow_multiple": 1, - "allow_print": 0, - "amount": 0.0, - "amount_based_on_field": 1, - "amount_field": "amount", - "creation": "2018-06-13 09:22:48.262441", - "currency": "USD", - "doc_type": "Certification Application", - "docstatus": 0, - "doctype": "Web Form", - "idx": 0, - "introduction_text": "", - "is_standard": 1, - "login_required": 1, - "max_attachment_size": 0, - "modified": "2018-06-13 09:26:35.502064", - "modified_by": "Administrator", - "module": "Non Profit", - "name": "certification-application-usd", - "owner": "Administrator", - "payment_button_help": "Pay for your certification using PayPal", - "payment_button_label": "Pay Now", - "payment_gateway": "PayPal", - "published": 1, - "route": "certification-application-usd", - "show_sidebar": 1, - "sidebar_items": [], - "success_url": "/certification-application-usd", - "title": "Certification Application USD", - "web_form_fields": [ - { - "fieldname": "name_of_applicant", - "fieldtype": "Data", - "hidden": 0, - "label": "Name of Applicant", - "max_length": 0, - "max_value": 0, - "read_only": 0, - "reqd": 0 - }, - { - "fieldname": "email", - "fieldtype": "Link", - "hidden": 0, - "label": "Email", - "max_length": 0, - "max_value": 0, - "options": "User", - "read_only": 1, - "reqd": 1 - }, - { - "fieldname": "currency", - "fieldtype": "Select", - "hidden": 0, - "label": "Currency", - "max_length": 0, - "max_value": 0, - "options": "USD\nINR", - "read_only": 1, - "reqd": 0 - }, - { - "fieldname": "amount", - "fieldtype": "Float", - "hidden": 0, - "label": "Amount", - "max_length": 0, - "max_value": 0, - "read_only": 1, - "reqd": 0 - } - ] -} \ No newline at end of file diff --git a/erpnext/non_profit/web_form/certification_application_usd/certification_application_usd.py b/erpnext/non_profit/web_form/certification_application_usd/certification_application_usd.py deleted file mode 100644 index 02e3e933330..00000000000 --- a/erpnext/non_profit/web_form/certification_application_usd/certification_application_usd.py +++ /dev/null @@ -1,3 +0,0 @@ -def get_context(context): - # do your magic here - pass diff --git a/erpnext/non_profit/web_form/grant_application/__init__.py b/erpnext/non_profit/web_form/grant_application/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/non_profit/web_form/grant_application/grant_application.js b/erpnext/non_profit/web_form/grant_application/grant_application.js deleted file mode 100644 index f09e5409192..00000000000 --- a/erpnext/non_profit/web_form/grant_application/grant_application.js +++ /dev/null @@ -1,3 +0,0 @@ -frappe.ready(function() { - // bind events here -}); diff --git a/erpnext/non_profit/web_form/grant_application/grant_application.json b/erpnext/non_profit/web_form/grant_application/grant_application.json deleted file mode 100644 index 73c94455002..00000000000 --- a/erpnext/non_profit/web_form/grant_application/grant_application.json +++ /dev/null @@ -1,108 +0,0 @@ -{ - "accept_payment": 0, - "allow_comments": 0, - "allow_delete": 1, - "allow_edit": 1, - "allow_incomplete": 0, - "allow_multiple": 1, - "allow_print": 0, - "amount": 0.0, - "amount_based_on_field": 0, - "creation": "2017-10-30 15:57:10.825188", - "currency": "INR", - "doc_type": "Grant Application", - "docstatus": 0, - "doctype": "Web Form", - "idx": 0, - "introduction_text": "Share as many details as you can to get quick response from organization", - "is_standard": 1, - "login_required": 1, - "max_attachment_size": 0, - "modified": "2017-12-06 12:32:16.893289", - "modified_by": "Administrator", - "module": "Non Profit", - "name": "grant-application", - "owner": "Administrator", - "payment_button_label": "Buy Now", - "published": 1, - "route": "my-grant", - "show_sidebar": 1, - "sidebar_items": [], - "success_url": "/grant-application", - "title": "Grant Application", - "web_form_fields": [ - { - "fieldname": "applicant_type", - "fieldtype": "Select", - "hidden": 0, - "label": "Applicant Type", - "max_length": 0, - "max_value": 0, - "options": "Individual\nOrganization", - "read_only": 0, - "reqd": 1 - }, - { - "fieldname": "applicant_name", - "fieldtype": "Data", - "hidden": 0, - "label": "Name", - "max_length": 0, - "max_value": 0, - "read_only": 0, - "reqd": 1 - }, - { - "fieldname": "email", - "fieldtype": "Data", - "hidden": 0, - "label": "Email Address", - "max_length": 0, - "max_value": 0, - "read_only": 0, - "reqd": 1 - }, - { - "description": "", - "fieldname": "grant_description", - "fieldtype": "Text", - "hidden": 0, - "label": "Please outline your current situation and why you are applying for a grant?", - "max_length": 0, - "max_value": 0, - "read_only": 0, - "reqd": 1 - }, - { - "fieldname": "amount", - "fieldtype": "Float", - "hidden": 0, - "label": "Requested Amount", - "max_length": 0, - "max_value": 0, - "read_only": 0, - "reqd": 0 - }, - { - "fieldname": "has_any_past_grant_record", - "fieldtype": "Check", - "hidden": 0, - "label": "Have you received any grant from us before?", - "max_length": 0, - "max_value": 0, - "options": "", - "read_only": 0, - "reqd": 0 - }, - { - "fieldname": "published", - "fieldtype": "Check", - "hidden": 0, - "label": "Show on Website", - "max_length": 0, - "max_value": 0, - "read_only": 0, - "reqd": 0 - } - ] -} \ No newline at end of file diff --git a/erpnext/non_profit/web_form/grant_application/grant_application.py b/erpnext/non_profit/web_form/grant_application/grant_application.py deleted file mode 100644 index 3dfb381f657..00000000000 --- a/erpnext/non_profit/web_form/grant_application/grant_application.py +++ /dev/null @@ -1,4 +0,0 @@ -def get_context(context): - context.no_cache = True - context.parents = [dict(label='View All ', - route='grant-application', title='View All')] diff --git a/erpnext/non_profit/workspace/non_profit/non_profit.json b/erpnext/non_profit/workspace/non_profit/non_profit.json deleted file mode 100644 index ba2f919d016..00000000000 --- a/erpnext/non_profit/workspace/non_profit/non_profit.json +++ /dev/null @@ -1,272 +0,0 @@ -{ - "charts": [], - "content": "[{\"type\": \"header\", \"data\": {\"text\": \"Your Shortcuts\", \"level\": 4, \"col\": 12}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Member\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Non Profit Settings\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Membership\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Chapter\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Chapter Member\", \"col\": 4}}, {\"type\": \"spacer\", \"data\": {\"col\": 12}}, {\"type\": \"header\", \"data\": {\"text\": \"Reports & Masters\", \"level\": 4, \"col\": 12}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Loan Management\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Grant Application\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Membership\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Volunteer\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Chapter\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Donation\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Tax Exemption Certification (India)\", \"col\": 4}}]", - "creation": "2020-03-02 17:23:47.811421", - "docstatus": 0, - "doctype": "Workspace", - "for_user": "", - "hide_custom": 0, - "icon": "non-profit", - "idx": 0, - "label": "Non Profit", - "links": [ - { - "hidden": 0, - "is_query_report": 0, - "label": "Loan Management", - "link_count": 0, - "onboard": 0, - "type": "Card Break" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Loan Type", - "link_count": 0, - "link_to": "Loan Type", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Loan Application", - "link_count": 0, - "link_to": "Loan Application", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Loan", - "link_count": 0, - "link_to": "Loan", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "hidden": 0, - "is_query_report": 0, - "label": "Grant Application", - "link_count": 0, - "onboard": 0, - "type": "Card Break" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Grant Application", - "link_count": 0, - "link_to": "Grant Application", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "hidden": 0, - "is_query_report": 0, - "label": "Membership", - "link_count": 0, - "onboard": 0, - "type": "Card Break" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Member", - "link_count": 0, - "link_to": "Member", - "link_type": "DocType", - "onboard": 1, - "type": "Link" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Membership", - "link_count": 0, - "link_to": "Membership", - "link_type": "DocType", - "onboard": 1, - "type": "Link" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Membership Type", - "link_count": 0, - "link_to": "Membership Type", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Membership Settings", - "link_count": 0, - "link_to": "Non Profit Settings", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "hidden": 0, - "is_query_report": 0, - "label": "Volunteer", - "link_count": 0, - "onboard": 0, - "type": "Card Break" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Volunteer", - "link_count": 0, - "link_to": "Volunteer", - "link_type": "DocType", - "onboard": 1, - "type": "Link" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Volunteer Type", - "link_count": 0, - "link_to": "Volunteer Type", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "hidden": 0, - "is_query_report": 0, - "label": "Chapter", - "link_count": 0, - "onboard": 0, - "type": "Card Break" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Chapter", - "link_count": 0, - "link_to": "Chapter", - "link_type": "DocType", - "onboard": 1, - "type": "Link" - }, - { - "hidden": 0, - "is_query_report": 0, - "label": "Donation", - "link_count": 0, - "onboard": 0, - "type": "Card Break" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Donor", - "link_count": 0, - "link_to": "Donor", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Donor Type", - "link_count": 0, - "link_to": "Donor Type", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "hidden": 0, - "is_query_report": 0, - "label": "Donation", - "link_count": 0, - "link_to": "Donation", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "hidden": 0, - "is_query_report": 0, - "label": "Tax Exemption Certification (India)", - "link_count": 0, - "link_type": "DocType", - "onboard": 0, - "type": "Card Break" - }, - { - "hidden": 0, - "is_query_report": 0, - "label": "Tax Exemption 80G Certificate", - "link_count": 0, - "link_to": "Tax Exemption 80G Certificate", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - } - ], - "modified": "2021-08-05 12:16:01.146207", - "modified_by": "Administrator", - "module": "Non Profit", - "name": "Non Profit", - "owner": "Administrator", - "parent_page": "", - "public": 1, - "restrict_to_domain": "Non Profit", - "roles": [], - "sequence_id": 18, - "shortcuts": [ - { - "label": "Member", - "link_to": "Member", - "type": "DocType" - }, - { - "label": "Non Profit Settings", - "link_to": "Non Profit Settings", - "type": "DocType" - }, - { - "label": "Membership", - "link_to": "Membership", - "type": "DocType" - }, - { - "label": "Chapter", - "link_to": "Chapter", - "type": "DocType" - }, - { - "label": "Chapter Member", - "link_to": "Chapter Member", - "type": "DocType" - } - ], - "title": "Non Profit" -} \ No newline at end of file diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 268db40a8e7..970a8f9b5d8 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -323,3 +323,5 @@ execute:frappe.delete_doc_if_exists('Workspace', 'ERPNext Integrations Settings' erpnext.patches.v14_0.set_payroll_cost_centers erpnext.patches.v13_0.agriculture_deprecation_warning erpnext.patches.v14_0.delete_agriculture_doctypes +erpnext.patches.v13_0.non_profit_deprecation_warning +erpnext.patches.v14_0.delete_non_profit_doctypes diff --git a/erpnext/patches/v13_0/non_profit_deprecation_warning.py b/erpnext/patches/v13_0/non_profit_deprecation_warning.py new file mode 100644 index 00000000000..c170de5c1cc --- /dev/null +++ b/erpnext/patches/v13_0/non_profit_deprecation_warning.py @@ -0,0 +1,10 @@ +import click + + +def execute(): + + click.secho( + "Non Profit Domain is moved to a separate app and will be removed from ERPNext in version-14.\n" + "When upgrading to ERPNext version-14, please install the app to continue using the Agriculture domain: https://github.com/frappe/non_profit", + fg="yellow", + ) diff --git a/erpnext/patches/v14_0/delete_non_profit_doctypes.py b/erpnext/patches/v14_0/delete_non_profit_doctypes.py new file mode 100644 index 00000000000..3b3dbe45769 --- /dev/null +++ b/erpnext/patches/v14_0/delete_non_profit_doctypes.py @@ -0,0 +1,19 @@ +import frappe + + +def execute(): + frappe.delete_doc("Module Def", "Non Profit", ignore_missing=True, force=True) + + frappe.delete_doc("Workspace", "Non Profit", ignore_missing=True, force=True) + + reports = frappe.get_all("Report", {"module": "Non Profit", "is_standard": "Yes"}, pluck='name') + for report in reports: + frappe.delete_doc("Report", report, ignore_missing=True, force=True) + + dashboards = frappe.get_all("Dashboard", {"module": "Non Profit", "is_standard": 1}, pluck='name') + for dashboard in dashboards: + frappe.delete_doc("Dashboard", dashboard, ignore_missing=True, force=True) + + doctypes = frappe.get_all("DocType", {"module": "Non Profit", "custom": 0}, pluck='name') + for doctype in doctypes: + frappe.delete_doc("DocType", doctype, ignore_missing=True) diff --git a/erpnext/regional/india/setup.py b/erpnext/regional/india/setup.py index c0dcb70b92c..fa4e454f33d 100644 --- a/erpnext/regional/india/setup.py +++ b/erpnext/regional/india/setup.py @@ -679,14 +679,6 @@ def get_custom_fields(): 'insert_after': 'email_id' } ], - 'Donor': [ - { - 'fieldname': 'pan_number', - 'label': 'PAN Details', - 'fieldtype': 'Data', - 'insert_after': 'email' - } - ], 'Finance Book': [ { 'fieldname': 'for_income_tax', diff --git a/erpnext/setup/setup_wizard/operations/install_fixtures.py b/erpnext/setup/setup_wizard/operations/install_fixtures.py index 336b51c0ab2..906db561db0 100644 --- a/erpnext/setup/setup_wizard/operations/install_fixtures.py +++ b/erpnext/setup/setup_wizard/operations/install_fixtures.py @@ -198,7 +198,6 @@ def install(country=None): {'doctype': "Party Type", "party_type": "Member", "account_type": "Receivable"}, {'doctype': "Party Type", "party_type": "Shareholder", "account_type": "Payable"}, {'doctype': "Party Type", "party_type": "Student", "account_type": "Receivable"}, - {'doctype': "Party Type", "party_type": "Donor", "account_type": "Receivable"}, {'doctype': "Opportunity Type", "name": _("Sales")}, {'doctype': "Opportunity Type", "name": _("Support")}, From e04b3aaf7a2cb0792436a7e5f868572cb35c39f4 Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Tue, 18 Jan 2022 14:36:22 +0530 Subject: [PATCH 02/75] feat(Employee Advance): add 'Returned' and 'Partly Claimed and Returned' status --- .../employee_advance/employee_advance.json | 42 +++++++++++++++++-- .../employee_advance/employee_advance.py | 39 ++++++++++------- .../hr/doctype/expense_claim/expense_claim.js | 2 +- .../hr/doctype/expense_claim/expense_claim.py | 31 +++++++++----- 4 files changed, 85 insertions(+), 29 deletions(-) diff --git a/erpnext/hr/doctype/employee_advance/employee_advance.json b/erpnext/hr/doctype/employee_advance/employee_advance.json index 04754530c3a..b0501830ccd 100644 --- a/erpnext/hr/doctype/employee_advance/employee_advance.json +++ b/erpnext/hr/doctype/employee_advance/employee_advance.json @@ -2,7 +2,7 @@ "actions": [], "allow_import": 1, "autoname": "naming_series:", - "creation": "2017-10-09 14:26:29.612365", + "creation": "2022-01-17 18:36:51.450395", "doctype": "DocType", "editable_grid": 1, "engine": "InnoDB", @@ -121,7 +121,7 @@ "fieldtype": "Select", "label": "Status", "no_copy": 1, - "options": "Draft\nPaid\nUnpaid\nClaimed\nCancelled", + "options": "Draft\nPaid\nUnpaid\nClaimed\nReturned\nPartly Claimed and Returned\nCancelled", "read_only": 1 }, { @@ -200,7 +200,7 @@ ], "is_submittable": 1, "links": [], - "modified": "2021-09-11 18:38:38.617478", + "modified": "2022-01-17 19:33:52.345823", "modified_by": "Administrator", "module": "HR", "name": "Employee Advance", @@ -237,5 +237,41 @@ "search_fields": "employee,employee_name", "sort_field": "modified", "sort_order": "DESC", + "states": [ + { + "color": "Red", + "custom": 1, + "title": "Draft" + }, + { + "color": "Green", + "custom": 1, + "title": "Paid" + }, + { + "color": "Orange", + "custom": 1, + "title": "Unpaid" + }, + { + "color": "Blue", + "custom": 1, + "title": "Claimed" + }, + { + "color": "Gray", + "title": "Returned" + }, + { + "color": "Yellow", + "title": "Partly Claimed and Returned" + }, + { + "color": "Red", + "custom": 1, + "title": "Cancelled" + } + ], + "title_field": "employee_name", "track_changes": 1 } \ No newline at end of file diff --git a/erpnext/hr/doctype/employee_advance/employee_advance.py b/erpnext/hr/doctype/employee_advance/employee_advance.py index 7aac2b63ed3..e17eb214a1d 100644 --- a/erpnext/hr/doctype/employee_advance/employee_advance.py +++ b/erpnext/hr/doctype/employee_advance/employee_advance.py @@ -28,18 +28,31 @@ class EmployeeAdvance(Document): def on_cancel(self): self.ignore_linked_doctypes = ('GL Entry') - def set_status(self): + def set_status(self, update=False): + precision = self.precision("paid_amount") + total_amount = flt(flt(self.claimed_amount) + flt(self.return_amount), precision) + status = None + if self.docstatus == 0: - self.status = "Draft" - if self.docstatus == 1: - if self.claimed_amount and flt(self.claimed_amount) == flt(self.paid_amount): - self.status = "Claimed" - elif self.paid_amount and self.advance_amount == flt(self.paid_amount): - self.status = "Paid" + status = "Draft" + elif self.docstatus == 1: + if flt(self.claimed_amount) > 0 and flt(self.claimed_amount, precision) == flt(self.paid_amount, precision): + status = "Claimed" + elif flt(self.return_amount) > 0 and flt(self.return_amount, precision) == flt(self.paid_amount, precision): + status = "Returned" + elif flt(self.claimed_amount) > 0 and (flt(self.return_amount) > 0) and total_amount == flt(self.paid_amount, precision): + status = "Partly Claimed and Returned" + elif flt(self.paid_amount) > 0 and flt(self.advance_amount, precision) == flt(self.paid_amount, precision): + status = "Paid" else: - self.status = "Unpaid" + status = "Unpaid" elif self.docstatus == 2: - self.status = "Cancelled" + status = "Cancelled" + + if update: + self.db_set("status", status) + else: + self.status = status def set_total_advance_paid(self): gle = frappe.qb.DocType("GL Entry") @@ -85,9 +98,7 @@ class EmployeeAdvance(Document): self.db_set("paid_amount", paid_amount) self.db_set("return_amount", return_amount) - self.set_status() - frappe.db.set_value("Employee Advance", self.name , "status", self.status) - + self.set_status(update=True) def update_claimed_amount(self): claimed_amount = frappe.db.sql(""" @@ -103,8 +114,8 @@ class EmployeeAdvance(Document): frappe.db.set_value("Employee Advance", self.name, "claimed_amount", flt(claimed_amount)) self.reload() - self.set_status() - frappe.db.set_value("Employee Advance", self.name, "status", self.status) + self.set_status(update=True) + @frappe.whitelist() def get_pending_amount(employee, posting_date): diff --git a/erpnext/hr/doctype/expense_claim/expense_claim.js b/erpnext/hr/doctype/expense_claim/expense_claim.js index 047945787d7..af80b63845e 100644 --- a/erpnext/hr/doctype/expense_claim/expense_claim.js +++ b/erpnext/hr/doctype/expense_claim/expense_claim.js @@ -171,7 +171,7 @@ frappe.ui.form.on("Expense Claim", { ['docstatus', '=', 1], ['employee', '=', frm.doc.employee], ['paid_amount', '>', 0], - ['status', '!=', 'Claimed'] + ['status', 'not in', ['Claimed', 'Returned', 'Partly Claimed and Returned']] ] }; }); diff --git a/erpnext/hr/doctype/expense_claim/expense_claim.py b/erpnext/hr/doctype/expense_claim/expense_claim.py index 7e3898b7d51..2d2bb093ce5 100644 --- a/erpnext/hr/doctype/expense_claim/expense_claim.py +++ b/erpnext/hr/doctype/expense_claim/expense_claim.py @@ -341,18 +341,27 @@ def get_expense_claim_account(expense_claim_type, company): @frappe.whitelist() def get_advances(employee, advance_id=None): - if not advance_id: - condition = 'docstatus=1 and employee={0} and paid_amount > 0 and paid_amount > claimed_amount + return_amount'.format(frappe.db.escape(employee)) - else: - condition = 'name={0}'.format(frappe.db.escape(advance_id)) + advance = frappe.qb.DocType("Employee Advance") - return frappe.db.sql(""" - select - name, posting_date, paid_amount, claimed_amount, advance_account - from - `tabEmployee Advance` - where {0} - """.format(condition), as_dict=1) + query = ( + frappe.qb.from_(advance) + .select( + advance.name, advance.posting_date, advance.paid_amount, + advance.claimed_amount, advance.advance_account + ) + ) + + if not advance_id: + query = query.where( + (advance.docstatus == 1) + & (advance.employee == employee) + & (advance.paid_amount > 0) + & (advance.status.notin(["Claimed", "Returned", "Partly Claimed and Returned"])) + ) + else: + query = query.where(advance.name == advance_id) + + return query.run(as_dict=True) @frappe.whitelist() From bf30932de0524c42ab3d9718e3d19a73e1cb2d39 Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Tue, 18 Jan 2022 14:36:38 +0530 Subject: [PATCH 03/75] patch: Employee Advance return statuses --- erpnext/patches.txt | 3 ++- .../v14_0/update_employee_advance_status.py | 26 +++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 erpnext/patches/v14_0/update_employee_advance_status.py diff --git a/erpnext/patches.txt b/erpnext/patches.txt index fa62b7fc276..ed39c204f6e 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -326,4 +326,5 @@ erpnext.patches.v13_0.agriculture_deprecation_warning erpnext.patches.v14_0.delete_agriculture_doctypes erpnext.patches.v13_0.update_exchange_rate_settings erpnext.patches.v14_0.rearrange_company_fields -erpnext.patches.v14_0.update_leave_notification_template \ No newline at end of file +erpnext.patches.v14_0.update_leave_notification_template +erpnext.patches.v14_0.update_employee_advance_status \ No newline at end of file diff --git a/erpnext/patches/v14_0/update_employee_advance_status.py b/erpnext/patches/v14_0/update_employee_advance_status.py new file mode 100644 index 00000000000..a20e35a9f6b --- /dev/null +++ b/erpnext/patches/v14_0/update_employee_advance_status.py @@ -0,0 +1,26 @@ +import frappe + + +def execute(): + frappe.reload_doc('hr', 'doctype', 'employee_advance') + + advance = frappe.qb.DocType('Employee Advance') + (frappe.qb + .update(advance) + .set(advance.status, 'Returned') + .where( + (advance.docstatus == 1) + & ((advance.return_amount) & (advance.paid_amount == advance.return_amount)) + & (advance.status == 'Paid') + ) + ).run() + + (frappe.qb + .update(advance) + .set(advance.status, 'Partly Claimed and Returned') + .where( + (advance.docstatus == 1) + & ((advance.claimed_amount & advance.return_amount) & (advance.paid_amount == (advance.return_amount + advance.claimed_amount))) + & (advance.status == 'Paid') + ) + ).run() \ No newline at end of file From 0843d4388569616803a562a6928d6f1204f0e733 Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Tue, 18 Jan 2022 14:37:45 +0530 Subject: [PATCH 04/75] fix(Expense Claim): validate advances after setting totals --- erpnext/hr/doctype/expense_claim/expense_claim.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/hr/doctype/expense_claim/expense_claim.py b/erpnext/hr/doctype/expense_claim/expense_claim.py index 2d2bb093ce5..5146a5be907 100644 --- a/erpnext/hr/doctype/expense_claim/expense_claim.py +++ b/erpnext/hr/doctype/expense_claim/expense_claim.py @@ -23,10 +23,10 @@ class ExpenseClaim(AccountsController): def validate(self): validate_active_employee(self.employee) - self.validate_advances() + set_employee_name(self) self.validate_sanctioned_amount() self.calculate_total_amount() - set_employee_name(self) + self.validate_advances() self.set_expense_account(validate=True) self.set_payable_account() self.set_cost_center() From 85be0d22d4300a40f46b7268f7c56d8e7facbd40 Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Tue, 18 Jan 2022 14:38:16 +0530 Subject: [PATCH 05/75] fix: employee advance status update on return via additional salary --- erpnext/payroll/doctype/additional_salary/additional_salary.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/erpnext/payroll/doctype/additional_salary/additional_salary.py b/erpnext/payroll/doctype/additional_salary/additional_salary.py index bf8bd05fcc0..d6185684168 100644 --- a/erpnext/payroll/doctype/additional_salary/additional_salary.py +++ b/erpnext/payroll/doctype/additional_salary/additional_salary.py @@ -105,6 +105,8 @@ class AdditionalSalary(Document): return_amount += self.amount frappe.db.set_value("Employee Advance", self.ref_docname, "return_amount", return_amount) + advance = frappe.get_doc("Employee Advance", self.ref_docname) + advance.set_status(update=True) def update_employee_referral(self, cancel=False): if self.ref_doctype == "Employee Referral": From 17b1f5f256ff63d34b3c20b4792cd77ae75402e0 Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Tue, 18 Jan 2022 18:35:25 +0530 Subject: [PATCH 06/75] test: employee advance status --- .../employee_advance/employee_advance.py | 6 +- .../employee_advance/test_employee_advance.py | 97 ++++++++++++++++++- 2 files changed, 100 insertions(+), 3 deletions(-) diff --git a/erpnext/hr/doctype/employee_advance/employee_advance.py b/erpnext/hr/doctype/employee_advance/employee_advance.py index e17eb214a1d..f63bb86129b 100644 --- a/erpnext/hr/doctype/employee_advance/employee_advance.py +++ b/erpnext/hr/doctype/employee_advance/employee_advance.py @@ -233,7 +233,8 @@ def make_return_entry(employee, company, employee_advance_name, return_amount, 'reference_name': employee_advance_name, 'party_type': 'Employee', 'party': employee, - 'is_advance': 'Yes' + 'is_advance': 'Yes', + 'cost_center': erpnext.get_default_cost_center(company) }) bank_amount = flt(return_amount) if bank_cash_account.account_currency==currency \ @@ -244,7 +245,8 @@ def make_return_entry(employee, company, employee_advance_name, return_amount, "debit_in_account_currency": bank_amount, "account_currency": bank_cash_account.account_currency, "account_type": bank_cash_account.account_type, - "exchange_rate": flt(exchange_rate) if bank_cash_account.account_currency == currency else 1 + "exchange_rate": flt(exchange_rate) if bank_cash_account.account_currency == currency else 1, + "cost_center": erpnext.get_default_cost_center(company) }) return je.as_dict() diff --git a/erpnext/hr/doctype/employee_advance/test_employee_advance.py b/erpnext/hr/doctype/employee_advance/test_employee_advance.py index 5f2e720eb46..5f3a66a04fa 100644 --- a/erpnext/hr/doctype/employee_advance/test_employee_advance.py +++ b/erpnext/hr/doctype/employee_advance/test_employee_advance.py @@ -4,7 +4,7 @@ import unittest import frappe -from frappe.utils import nowdate +from frappe.utils import flt, nowdate import erpnext from erpnext.hr.doctype.employee.test_employee import make_employee @@ -12,6 +12,12 @@ from erpnext.hr.doctype.employee_advance.employee_advance import ( EmployeeAdvanceOverPayment, create_return_through_additional_salary, make_bank_entry, + make_return_entry, +) +from erpnext.hr.doctype.expense_claim.expense_claim import get_advances +from erpnext.hr.doctype.expense_claim.test_expense_claim import ( + get_payable_account, + make_expense_claim, ) from erpnext.payroll.doctype.salary_component.test_salary_component import create_salary_component from erpnext.payroll.doctype.salary_structure.test_salary_structure import make_salary_structure @@ -52,9 +58,75 @@ class TestEmployeeAdvance(unittest.TestCase): self.assertEqual(advance.paid_amount, 0) self.assertEqual(advance.status, "Unpaid") + def test_claimed_and_returned_status(self): + # Claimed Status check, full amount claimed + payable_account = get_payable_account("_Test Company") + claim = make_expense_claim(payable_account, 1000, 1000, "_Test Company", "Travel Expenses - _TC", do_not_submit=True) + + advance = make_employee_advance(claim.employee) + pe = make_payment_entry(advance) + pe.submit() + + claim = get_advances_for_claim(claim, advance.name) + claim.save() + claim.submit() + + advance.reload() + self.assertEqual(advance.claimed_amount, 1000) + self.assertEqual(advance.status, "Claimed") + + # cancel claim; status should be Paid + claim.cancel() + advance.reload() + self.assertEqual(advance.claimed_amount, 0) + self.assertEqual(advance.status, "Paid") + + # Partly Claimed and Returned status check + # 500 Claimed, 500 Returned + claim = make_expense_claim(payable_account, 500, 500, "_Test Company", "Travel Expenses - _TC", do_not_submit=True) + + advance = make_employee_advance(claim.employee) + pe = make_payment_entry(advance) + pe.submit() + + claim = get_advances_for_claim(claim, advance.name, amount=500) + claim.save() + claim.submit() + + advance.reload() + self.assertEqual(advance.claimed_amount, 500) + self.assertEqual(advance.status, "Paid") + + entry = make_return_entry( + employee=advance.employee, + company=advance.company, + employee_advance_name=advance.name, + return_amount=flt(advance.paid_amount - advance.claimed_amount), + advance_account=advance.advance_account, + mode_of_payment=advance.mode_of_payment, + currency=advance.currency, + exchange_rate=advance.exchange_rate + ) + + entry = frappe.get_doc(entry) + entry.insert() + entry.submit() + + advance.reload() + self.assertEqual(advance.return_amount, 500) + self.assertEqual(advance.status, "Partly Claimed and Returned") + + # Cancel return entry; status should change to Paid + entry.cancel() + advance.reload() + self.assertEqual(advance.return_amount, 0) + self.assertEqual(advance.status, "Paid") + def test_repay_unclaimed_amount_from_salary(self): employee_name = make_employee("_T@employe.advance") advance = make_employee_advance(employee_name, {"repay_unclaimed_amount_from_salary": 1}) + pe = make_payment_entry(advance) + pe.submit() args = {"type": "Deduction"} create_salary_component("Advance Salary - Deduction", **args) @@ -82,11 +154,13 @@ class TestEmployeeAdvance(unittest.TestCase): advance.reload() self.assertEqual(advance.return_amount, 1000) + self.assertEqual(advance.status, "Returned") # update advance return amount on additional salary cancellation additional_salary.cancel() advance.reload() self.assertEqual(advance.return_amount, 700) + self.assertEqual(advance.status, "Paid") def tearDown(self): frappe.db.rollback() @@ -118,3 +192,24 @@ def make_employee_advance(employee_name, args=None): doc.submit() return doc + + +def get_advances_for_claim(claim, advance_name, amount=None): + advances = get_advances(claim.employee, advance_name) + + for entry in advances: + if amount: + allocated_amount = amount + else: + allocated_amount = flt(entry.paid_amount) - flt(entry.claimed_amount) + + claim.append("advances", { + "employee_advance": entry.name, + "posting_date": entry.posting_date, + "advance_account": entry.advance_account, + "advance_paid": entry.paid_amount, + "unclaimed_amount": allocated_amount, + "allocated_amount": allocated_amount + }) + + return claim \ No newline at end of file From f423de530a4140bfb84e93dbfa0f1140dcaa8e9b Mon Sep 17 00:00:00 2001 From: ChillarAnand Date: Thu, 20 Jan 2022 11:02:30 +0530 Subject: [PATCH 07/75] refactor: Code cleanup --- .../doctype/membership/membership.py | 415 ------------------ erpnext/regional/india/setup.py | 8 - .../operations/install_fixtures.py | 1 - 3 files changed, 424 deletions(-) delete mode 100644 erpnext/non_profit/doctype/membership/membership.py diff --git a/erpnext/non_profit/doctype/membership/membership.py b/erpnext/non_profit/doctype/membership/membership.py deleted file mode 100644 index f9b295a223d..00000000000 --- a/erpnext/non_profit/doctype/membership/membership.py +++ /dev/null @@ -1,415 +0,0 @@ -# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - - -import json -from datetime import datetime - -import frappe -from frappe import _ -from frappe.email import sendmail_to_system_managers -from frappe.model.document import Document -from frappe.utils import add_days, add_months, add_years, get_link_to_form, getdate, nowdate - -import erpnext -from erpnext.non_profit.doctype.member.member import create_member - - -class Membership(Document): - def validate(self): - if not self.member or not frappe.db.exists("Member", self.member): - # for web forms - user_type = frappe.db.get_value("User", frappe.session.user, "user_type") - if user_type == "Website User": - self.create_member_from_website_user() - else: - frappe.throw(_("Please select a Member")) - - self.validate_membership_period() - - def create_member_from_website_user(self): - member_name = frappe.get_value("Member", dict(email_id=frappe.session.user)) - - if not member_name: - user = frappe.get_doc("User", frappe.session.user) - member = frappe.get_doc(dict( - doctype="Member", - email_id=frappe.session.user, - membership_type=self.membership_type, - member_name=user.get_fullname() - )).insert(ignore_permissions=True) - member_name = member.name - - if self.get("__islocal"): - self.member = member_name - - def validate_membership_period(self): - # get last membership (if active) - last_membership = erpnext.get_last_membership(self.member) - - # if person applied for offline membership - if last_membership and last_membership.name != self.name and not frappe.session.user == "Administrator": - # if last membership does not expire in 30 days, then do not allow to renew - if getdate(add_days(last_membership.to_date, -30)) > getdate(nowdate()) : - frappe.throw(_("You can only renew if your membership expires within 30 days")) - - self.from_date = add_days(last_membership.to_date, 1) - elif frappe.session.user == "Administrator": - self.from_date = self.from_date - else: - self.from_date = nowdate() - - if frappe.db.get_single_value("Non Profit Settings", "billing_cycle") == "Yearly": - self.to_date = add_years(self.from_date, 1) - else: - self.to_date = add_months(self.from_date, 1) - - def on_payment_authorized(self, status_changed_to=None): - if status_changed_to not in ("Completed", "Authorized"): - return - self.load_from_db() - self.db_set("paid", 1) - settings = frappe.get_doc("Non Profit Settings") - if settings.allow_invoicing and settings.automate_membership_invoicing: - self.generate_invoice(with_payment_entry=settings.automate_membership_payment_entries, save=True) - - - @frappe.whitelist() - def generate_invoice(self, save=True, with_payment_entry=False): - if not (self.paid or self.currency or self.amount): - frappe.throw(_("The payment for this membership is not paid. To generate invoice fill the payment details")) - - if self.invoice: - frappe.throw(_("An invoice is already linked to this document")) - - member = frappe.get_doc("Member", self.member) - if not member.customer: - frappe.throw(_("No customer linked to member {0}").format(frappe.bold(self.member))) - - plan = frappe.get_doc("Membership Type", self.membership_type) - settings = frappe.get_doc("Non Profit Settings") - self.validate_membership_type_and_settings(plan, settings) - - invoice = make_invoice(self, member, plan, settings) - self.reload() - self.invoice = invoice.name - - if with_payment_entry: - self.make_payment_entry(settings, invoice) - - if save: - self.save() - - return invoice - - def validate_membership_type_and_settings(self, plan, settings): - settings_link = get_link_to_form("Membership Type", self.membership_type) - - if not settings.membership_debit_account: - frappe.throw(_("You need to set Debit Account in {0}").format(settings_link)) - - if not settings.company: - frappe.throw(_("You need to set Default Company for invoicing in {0}").format(settings_link)) - - if not plan.linked_item: - frappe.throw(_("Please set a Linked Item for the Membership Type {0}").format( - get_link_to_form("Membership Type", self.membership_type))) - - def make_payment_entry(self, settings, invoice): - if not settings.membership_payment_account: - frappe.throw(_("You need to set Payment Account for Membership in {0}").format( - get_link_to_form("Non Profit Settings", "Non Profit Settings"))) - - from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry - frappe.flags.ignore_account_permission = True - pe = get_payment_entry(dt="Sales Invoice", dn=invoice.name, bank_amount=invoice.grand_total) - frappe.flags.ignore_account_permission=False - pe.paid_to = settings.membership_payment_account - pe.reference_no = self.name - pe.reference_date = getdate() - pe.flags.ignore_mandatory = True - pe.save() - pe.submit() - - @frappe.whitelist() - def send_acknowlement(self): - settings = frappe.get_doc("Non Profit Settings") - if not settings.send_email: - frappe.throw(_("You need to enable Send Acknowledge Email in {0}").format( - get_link_to_form("Non Profit Settings", "Non Profit Settings"))) - - member = frappe.get_doc("Member", self.member) - if not member.email_id: - frappe.throw(_("Email address of member {0} is missing").format(frappe.utils.get_link_to_form("Member", self.member))) - - plan = frappe.get_doc("Membership Type", self.membership_type) - email = member.email_id - attachments = [frappe.attach_print("Membership", self.name, print_format=settings.membership_print_format)] - - if self.invoice and settings.send_invoice: - attachments.append(frappe.attach_print("Sales Invoice", self.invoice, print_format=settings.inv_print_format)) - - email_template = frappe.get_doc("Email Template", settings.email_template) - context = { "doc": self, "member": member} - - email_args = { - "recipients": [email], - "message": frappe.render_template(email_template.get("response"), context), - "subject": frappe.render_template(email_template.get("subject"), context), - "attachments": attachments, - "reference_doctype": self.doctype, - "reference_name": self.name - } - - if not frappe.flags.in_test: - frappe.enqueue(method=frappe.sendmail, queue="short", timeout=300, is_async=True, **email_args) - else: - frappe.sendmail(**email_args) - - def generate_and_send_invoice(self): - self.generate_invoice(save=False) - self.send_acknowlement() - - -def make_invoice(membership, member, plan, settings): - invoice = frappe.get_doc({ - "doctype": "Sales Invoice", - "customer": member.customer, - "debit_to": settings.membership_debit_account, - "currency": membership.currency, - "company": settings.company, - "is_pos": 0, - "items": [ - { - "item_code": plan.linked_item, - "rate": membership.amount, - "qty": 1 - } - ] - }) - invoice.set_missing_values() - invoice.insert() - invoice.submit() - - frappe.msgprint(_("Sales Invoice created successfully")) - - return invoice - - -def get_member_based_on_subscription(subscription_id, email=None, customer_id=None): - filters = {"subscription_id": subscription_id} - if email: - filters.update({"email_id": email}) - if customer_id: - filters.update({"customer_id": customer_id}) - - members = frappe.get_all("Member", filters=filters, order_by="creation desc") - - try: - return frappe.get_doc("Member", members[0]["name"]) - except Exception: - return None - - -def verify_signature(data, endpoint="Membership"): - signature = frappe.request.headers.get("X-Razorpay-Signature") - - settings = frappe.get_doc("Non Profit Settings") - key = settings.get_webhook_secret(endpoint) - - controller = frappe.get_doc("Razorpay Settings") - - controller.verify_signature(data, signature, key) - frappe.set_user(settings.creation_user) - - -@frappe.whitelist(allow_guest=True) -def trigger_razorpay_subscription(*args, **kwargs): - data = frappe.request.get_data(as_text=True) - data = process_request_data(data) - - subscription = data.payload.get("subscription", {}).get("entity", {}) - subscription = frappe._dict(subscription) - - payment = data.payload.get("payment", {}).get("entity", {}) - payment = frappe._dict(payment) - - try: - if not data.event == "subscription.charged": - return - - member = get_member_based_on_subscription(subscription.id, payment.email) - if not member: - member = create_member(frappe._dict({ - "fullname": payment.email, - "email": payment.email, - "plan_id": get_plan_from_razorpay_id(subscription.plan_id) - })) - - member.subscription_id = subscription.id - member.customer_id = payment.customer_id - - if subscription.get("notes"): - member = get_additional_notes(member, subscription) - - company = get_company_for_memberships() - # Update Membership - membership = frappe.new_doc("Membership") - membership.update({ - "company": company, - "member": member.name, - "membership_status": "Current", - "membership_type": member.membership_type, - "currency": "INR", - "paid": 1, - "payment_id": payment.id, - "from_date": datetime.fromtimestamp(subscription.current_start), - "to_date": datetime.fromtimestamp(subscription.current_end), - "amount": payment.amount / 100 # Convert to rupees from paise - }) - membership.flags.ignore_mandatory = True - membership.insert() - - # Update membership values - member.subscription_start = datetime.fromtimestamp(subscription.start_at) - member.subscription_end = datetime.fromtimestamp(subscription.end_at) - member.subscription_status = "Active" - member.flags.ignore_mandatory = True - member.save() - - settings = frappe.get_doc("Non Profit Settings") - if settings.allow_invoicing and settings.automate_membership_invoicing: - membership.reload() - membership.generate_invoice(with_payment_entry=settings.automate_membership_payment_entries, save=True) - - except Exception as e: - message = "{0}\n\n{1}\n\n{2}: {3}".format(e, frappe.get_traceback(), _("Payment ID"), payment.id) - log = frappe.log_error(message, _("Error creating membership entry for {0}").format(member.name)) - notify_failure(log) - return {"status": "Failed", "reason": e} - - return {"status": "Success"} - - -@frappe.whitelist(allow_guest=True) -def update_halted_razorpay_subscription(*args, **kwargs): - """ - When all retries have been exhausted, Razorpay moves the subscription to the halted state. - The customer has to manually retry the charge or change the card linked to the subscription, - for the subscription to move back to the active state. - """ - if frappe.request: - data = frappe.request.get_data(as_text=True) - data = process_request_data(data) - elif frappe.flags.in_test: - data = kwargs.get("data") - data = frappe._dict(data) - else: - return - - if not data.event == "subscription.halted": - return - - subscription = data.payload.get("subscription", {}).get("entity", {}) - subscription = frappe._dict(subscription) - - try: - member = get_member_based_on_subscription(subscription.id, customer_id=subscription.customer_id) - if not member: - frappe.throw(_("Member with Razorpay Subscription ID {0} not found").format(subscription.id)) - - member.subscription_status = "Halted" - member.flags.ignore_mandatory = True - member.save() - - if subscription.get("notes"): - member = get_additional_notes(member, subscription) - - except Exception as e: - message = "{0}\n\n{1}".format(e, frappe.get_traceback()) - log = frappe.log_error(message, _("Error updating halted status for member {0}").format(member.name)) - notify_failure(log) - return {"status": "Failed", "reason": e} - - return {"status": "Success"} - - -def process_request_data(data): - try: - verify_signature(data) - except Exception as e: - log = frappe.log_error(e, "Membership Webhook Verification Error") - notify_failure(log) - return {"status": "Failed", "reason": e} - - if isinstance(data, str): - data = json.loads(data) - data = frappe._dict(data) - - return data - - -def get_company_for_memberships(): - company = frappe.db.get_single_value("Non Profit Settings", "company") - if not company: - from erpnext.non_profit.utils import get_company - company = get_company() - return company - - -def get_additional_notes(member, subscription): - if type(subscription.notes) == dict: - for k, v in subscription.notes.items(): - notes = "\n".join("{}: {}".format(k, v)) - - # extract member name from notes - if "name" in k.lower(): - member.update({ - "member_name": subscription.notes.get(k) - }) - - # extract pan number from notes - if "pan" in k.lower(): - member.update({ - "pan_number": subscription.notes.get(k) - }) - - member.add_comment("Comment", notes) - - elif type(subscription.notes) == str: - member.add_comment("Comment", subscription.notes) - - return member - - -def notify_failure(log): - try: - content = """ - Dear System Manager, - Razorpay webhook for creating renewing membership subscription failed due to some reason. - Please check the following error log linked below - Error Log: {0} - Regards, Administrator - """.format(get_link_to_form("Error Log", log.name)) - - sendmail_to_system_managers("[Important] [ERPNext] Razorpay membership webhook failed , please check.", content) - except Exception: - pass - - -def get_plan_from_razorpay_id(plan_id): - plan = frappe.get_all("Membership Type", filters={"razorpay_plan_id": plan_id}, order_by="creation desc") - - try: - return plan[0]["name"] - except Exception: - return None - - -def set_expired_status(): - frappe.db.sql(""" - UPDATE - `tabMembership` SET `membership_status` = 'Expired' - WHERE - `membership_status` not in ('Cancelled') AND `to_date` < %s - """, (nowdate())) diff --git a/erpnext/regional/india/setup.py b/erpnext/regional/india/setup.py index fa4e454f33d..ecd9294342b 100644 --- a/erpnext/regional/india/setup.py +++ b/erpnext/regional/india/setup.py @@ -671,14 +671,6 @@ def get_custom_fields(): 'mandatory_depends_on': 'eval:in_list(["SEZ", "Overseas", "Deemed Export"], doc.gst_category)' } ], - 'Member': [ - { - 'fieldname': 'pan_number', - 'label': 'PAN Details', - 'fieldtype': 'Data', - 'insert_after': 'email_id' - } - ], 'Finance Book': [ { 'fieldname': 'for_income_tax', diff --git a/erpnext/setup/setup_wizard/operations/install_fixtures.py b/erpnext/setup/setup_wizard/operations/install_fixtures.py index 906db561db0..bf3525998c8 100644 --- a/erpnext/setup/setup_wizard/operations/install_fixtures.py +++ b/erpnext/setup/setup_wizard/operations/install_fixtures.py @@ -195,7 +195,6 @@ def install(country=None): {'doctype': "Party Type", "party_type": "Customer", "account_type": "Receivable"}, {'doctype': "Party Type", "party_type": "Supplier", "account_type": "Payable"}, {'doctype': "Party Type", "party_type": "Employee", "account_type": "Payable"}, - {'doctype': "Party Type", "party_type": "Member", "account_type": "Receivable"}, {'doctype': "Party Type", "party_type": "Shareholder", "account_type": "Payable"}, {'doctype': "Party Type", "party_type": "Student", "account_type": "Receivable"}, From 4bdf6248aae8140bd3c46846044d9dfe97fcacc6 Mon Sep 17 00:00:00 2001 From: ChillarAnand Date: Mon, 24 Jan 2022 11:06:11 +0530 Subject: [PATCH 08/75] refactor: Remove regional setup for non-profit --- .../tax_exemption_80g_certificate/__init__.py | 0 .../tax_exemption_80g_certificate.js | 67 ---- .../tax_exemption_80g_certificate.json | 297 ------------------ .../tax_exemption_80g_certificate.py | 104 ------ .../test_tax_exemption_80g_certificate.py | 106 ------- .../__init__.py | 0 .../tax_exemption_80g_certificate_detail.json | 66 ---- .../tax_exemption_80g_certificate_detail.py | 10 - 8 files changed, 650 deletions(-) delete mode 100644 erpnext/regional/doctype/tax_exemption_80g_certificate/__init__.py delete mode 100644 erpnext/regional/doctype/tax_exemption_80g_certificate/tax_exemption_80g_certificate.js delete mode 100644 erpnext/regional/doctype/tax_exemption_80g_certificate/tax_exemption_80g_certificate.json delete mode 100644 erpnext/regional/doctype/tax_exemption_80g_certificate/tax_exemption_80g_certificate.py delete mode 100644 erpnext/regional/doctype/tax_exemption_80g_certificate/test_tax_exemption_80g_certificate.py delete mode 100644 erpnext/regional/doctype/tax_exemption_80g_certificate_detail/__init__.py delete mode 100644 erpnext/regional/doctype/tax_exemption_80g_certificate_detail/tax_exemption_80g_certificate_detail.json delete mode 100644 erpnext/regional/doctype/tax_exemption_80g_certificate_detail/tax_exemption_80g_certificate_detail.py diff --git a/erpnext/regional/doctype/tax_exemption_80g_certificate/__init__.py b/erpnext/regional/doctype/tax_exemption_80g_certificate/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/regional/doctype/tax_exemption_80g_certificate/tax_exemption_80g_certificate.js b/erpnext/regional/doctype/tax_exemption_80g_certificate/tax_exemption_80g_certificate.js deleted file mode 100644 index 54cde9c0cf4..00000000000 --- a/erpnext/regional/doctype/tax_exemption_80g_certificate/tax_exemption_80g_certificate.js +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Tax Exemption 80G Certificate', { - refresh: function(frm) { - if (frm.doc.donor) { - frm.set_query('donation', function() { - return { - filters: { - docstatus: 1, - donor: frm.doc.donor - } - }; - }); - } - }, - - recipient: function(frm) { - if (frm.doc.recipient === 'Donor') { - frm.set_value({ - 'member': '', - 'member_name': '', - 'member_email': '', - 'member_pan_number': '', - 'fiscal_year': '', - 'total': 0, - 'payments': [] - }); - } else { - frm.set_value({ - 'donor': '', - 'donor_name': '', - 'donor_email': '', - 'donor_pan_number': '', - 'donation': '', - 'date_of_donation': '', - 'amount': 0, - 'mode_of_payment': '', - 'razorpay_payment_id': '' - }); - } - }, - - get_payments: function(frm) { - frm.call({ - doc: frm.doc, - method: 'get_payments', - freeze: true - }); - }, - - company: function(frm) { - if ((frm.doc.member || frm.doc.donor) && frm.doc.company) { - frm.call({ - doc: frm.doc, - method: 'set_company_address', - freeze: true - }); - } - }, - - donation: function(frm) { - if (frm.doc.recipient === 'Donor' && !frm.doc.donor) { - frappe.msgprint(__('Please select donor first')); - } - } -}); diff --git a/erpnext/regional/doctype/tax_exemption_80g_certificate/tax_exemption_80g_certificate.json b/erpnext/regional/doctype/tax_exemption_80g_certificate/tax_exemption_80g_certificate.json deleted file mode 100644 index 9eee722f420..00000000000 --- a/erpnext/regional/doctype/tax_exemption_80g_certificate/tax_exemption_80g_certificate.json +++ /dev/null @@ -1,297 +0,0 @@ -{ - "actions": [], - "autoname": "naming_series:", - "creation": "2021-02-15 12:37:21.577042", - "doctype": "DocType", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "naming_series", - "recipient", - "member", - "member_name", - "member_email", - "member_pan_number", - "donor", - "donor_name", - "donor_email", - "donor_pan_number", - "column_break_4", - "date", - "fiscal_year", - "section_break_11", - "company", - "company_address", - "company_address_display", - "column_break_14", - "company_pan_number", - "company_80g_number", - "company_80g_wef", - "title", - "section_break_6", - "get_payments", - "payments", - "total", - "donation_details_section", - "donation", - "date_of_donation", - "amount", - "column_break_27", - "mode_of_payment", - "razorpay_payment_id" - ], - "fields": [ - { - "fieldname": "recipient", - "fieldtype": "Select", - "in_list_view": 1, - "label": "Certificate Recipient", - "options": "Member\nDonor", - "reqd": 1 - }, - { - "depends_on": "eval:doc.recipient === \"Member\";", - "fieldname": "member", - "fieldtype": "Link", - "in_list_view": 1, - "label": "Member", - "mandatory_depends_on": "eval:doc.recipient === \"Member\";", - "options": "Member" - }, - { - "depends_on": "eval:doc.recipient === \"Member\";", - "fetch_from": "member.member_name", - "fieldname": "member_name", - "fieldtype": "Data", - "label": "Member Name", - "read_only": 1 - }, - { - "depends_on": "eval:doc.recipient === \"Donor\";", - "fieldname": "donor", - "fieldtype": "Link", - "in_list_view": 1, - "label": "Donor", - "mandatory_depends_on": "eval:doc.recipient === \"Donor\";", - "options": "Donor" - }, - { - "fieldname": "column_break_4", - "fieldtype": "Column Break" - }, - { - "fieldname": "date", - "fieldtype": "Date", - "label": "Date", - "reqd": 1 - }, - { - "depends_on": "eval:doc.recipient === \"Member\";", - "fieldname": "section_break_6", - "fieldtype": "Section Break" - }, - { - "fieldname": "payments", - "fieldtype": "Table", - "label": "Payments", - "options": "Tax Exemption 80G Certificate Detail" - }, - { - "fieldname": "total", - "fieldtype": "Currency", - "in_list_view": 1, - "label": "Total", - "read_only": 1 - }, - { - "depends_on": "eval:doc.recipient === \"Member\";", - "fieldname": "fiscal_year", - "fieldtype": "Link", - "in_list_view": 1, - "label": "Fiscal Year", - "options": "Fiscal Year" - }, - { - "fieldname": "company", - "fieldtype": "Link", - "label": "Company", - "options": "Company", - "reqd": 1 - }, - { - "fieldname": "get_payments", - "fieldtype": "Button", - "label": "Get Memberships" - }, - { - "fieldname": "naming_series", - "fieldtype": "Select", - "label": "Naming Series", - "options": "NPO-80G-.YYYY.-" - }, - { - "fieldname": "section_break_11", - "fieldtype": "Section Break", - "label": "Company Details" - }, - { - "fieldname": "company_address", - "fieldtype": "Link", - "label": "Company Address", - "options": "Address" - }, - { - "fieldname": "column_break_14", - "fieldtype": "Column Break" - }, - { - "fetch_from": "company.pan_details", - "fieldname": "company_pan_number", - "fieldtype": "Data", - "label": "PAN Number", - "read_only": 1 - }, - { - "fieldname": "company_address_display", - "fieldtype": "Small Text", - "hidden": 1, - "label": "Company Address Display", - "print_hide": 1, - "read_only": 1 - }, - { - "fetch_from": "company.company_80g_number", - "fieldname": "company_80g_number", - "fieldtype": "Data", - "label": "80G Number", - "read_only": 1 - }, - { - "fetch_from": "company.with_effect_from", - "fieldname": "company_80g_wef", - "fieldtype": "Date", - "label": "80G With Effect From", - "read_only": 1 - }, - { - "depends_on": "eval:doc.recipient === \"Donor\";", - "fieldname": "donation_details_section", - "fieldtype": "Section Break", - "label": "Donation Details" - }, - { - "fieldname": "donation", - "fieldtype": "Link", - "label": "Donation", - "mandatory_depends_on": "eval:doc.recipient === \"Donor\";", - "options": "Donation" - }, - { - "fetch_from": "donation.amount", - "fieldname": "amount", - "fieldtype": "Currency", - "label": "Amount", - "read_only": 1 - }, - { - "fetch_from": "donation.mode_of_payment", - "fieldname": "mode_of_payment", - "fieldtype": "Link", - "label": "Mode of Payment", - "options": "Mode of Payment", - "read_only": 1 - }, - { - "fetch_from": "donation.razorpay_payment_id", - "fieldname": "razorpay_payment_id", - "fieldtype": "Data", - "label": "RazorPay Payment ID", - "read_only": 1 - }, - { - "fetch_from": "donation.date", - "fieldname": "date_of_donation", - "fieldtype": "Date", - "label": "Date of Donation", - "read_only": 1 - }, - { - "fieldname": "column_break_27", - "fieldtype": "Column Break" - }, - { - "depends_on": "eval:doc.recipient === \"Donor\";", - "fetch_from": "donor.donor_name", - "fieldname": "donor_name", - "fieldtype": "Data", - "label": "Donor Name", - "read_only": 1 - }, - { - "depends_on": "eval:doc.recipient === \"Donor\";", - "fetch_from": "donor.email", - "fieldname": "donor_email", - "fieldtype": "Data", - "label": "Email", - "read_only": 1 - }, - { - "depends_on": "eval:doc.recipient === \"Member\";", - "fetch_from": "member.email_id", - "fieldname": "member_email", - "fieldtype": "Data", - "in_list_view": 1, - "label": "Email", - "read_only": 1 - }, - { - "depends_on": "eval:doc.recipient === \"Member\";", - "fetch_from": "member.pan_number", - "fieldname": "member_pan_number", - "fieldtype": "Data", - "label": "PAN Details", - "read_only": 1 - }, - { - "depends_on": "eval:doc.recipient === \"Donor\";", - "fetch_from": "donor.pan_number", - "fieldname": "donor_pan_number", - "fieldtype": "Data", - "label": "PAN Details", - "read_only": 1 - }, - { - "fieldname": "title", - "fieldtype": "Data", - "hidden": 1, - "label": "Title", - "print_hide": 1 - } - ], - "index_web_pages_for_search": 1, - "links": [], - "modified": "2021-02-22 00:03:34.215633", - "modified_by": "Administrator", - "module": "Regional", - "name": "Tax Exemption 80G Certificate", - "owner": "Administrator", - "permissions": [ - { - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "System Manager", - "share": 1, - "write": 1 - } - ], - "search_fields": "member, member_name", - "sort_field": "modified", - "sort_order": "DESC", - "title_field": "title", - "track_changes": 1 -} \ No newline at end of file diff --git a/erpnext/regional/doctype/tax_exemption_80g_certificate/tax_exemption_80g_certificate.py b/erpnext/regional/doctype/tax_exemption_80g_certificate/tax_exemption_80g_certificate.py deleted file mode 100644 index 0f0897841b4..00000000000 --- a/erpnext/regional/doctype/tax_exemption_80g_certificate/tax_exemption_80g_certificate.py +++ /dev/null @@ -1,104 +0,0 @@ -# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - - -import frappe -from frappe import _ -from frappe.contacts.doctype.address.address import get_company_address -from frappe.model.document import Document -from frappe.utils import flt, get_link_to_form, getdate - -from erpnext.accounts.utils import get_fiscal_year - - -class TaxExemption80GCertificate(Document): - def validate(self): - self.validate_date() - self.validate_duplicates() - self.validate_company_details() - self.set_company_address() - self.calculate_total() - self.set_title() - - def validate_date(self): - if self.recipient == 'Member': - if getdate(self.date): - fiscal_year = get_fiscal_year(fiscal_year=self.fiscal_year, as_dict=True) - - if not (fiscal_year.year_start_date <= getdate(self.date) \ - <= fiscal_year.year_end_date): - frappe.throw(_('The Certificate Date is not in the Fiscal Year {0}').format(frappe.bold(self.fiscal_year))) - - def validate_duplicates(self): - if self.recipient == 'Donor': - certificate = frappe.db.exists(self.doctype, { - 'donation': self.donation, - 'name': ('!=', self.name) - }) - if certificate: - frappe.throw(_('An 80G Certificate {0} already exists for the donation {1}').format( - get_link_to_form(self.doctype, certificate), frappe.bold(self.donation) - ), title=_('Duplicate Certificate')) - - def validate_company_details(self): - fields = ['company_80g_number', 'with_effect_from', 'pan_details'] - company_details = frappe.db.get_value('Company', self.company, fields, as_dict=True) - if not company_details.company_80g_number: - frappe.throw(_('Please set the {0} for company {1}').format(frappe.bold('80G Number'), - get_link_to_form('Company', self.company))) - - if not company_details.pan_details: - frappe.throw(_('Please set the {0} for company {1}').format(frappe.bold('PAN Number'), - get_link_to_form('Company', self.company))) - - @frappe.whitelist() - def set_company_address(self): - address = get_company_address(self.company) - self.company_address = address.company_address - self.company_address_display = address.company_address_display - - def calculate_total(self): - if self.recipient == 'Donor': - return - - total = 0 - for entry in self.payments: - total += flt(entry.amount) - self.total = total - - def set_title(self): - if self.recipient == 'Member': - self.title = self.member_name - else: - self.title = self.donor_name - - @frappe.whitelist() - def get_payments(self): - if not self.member: - frappe.throw(_('Please select a Member first.')) - - fiscal_year = get_fiscal_year(fiscal_year=self.fiscal_year, as_dict=True) - - memberships = frappe.db.get_all('Membership', { - 'member': self.member, - 'from_date': ['between', (fiscal_year.year_start_date, fiscal_year.year_end_date)], - 'membership_status': ('!=', 'Cancelled') - }, ['from_date', 'amount', 'name', 'invoice', 'payment_id'], order_by='from_date') - - if not memberships: - frappe.msgprint(_('No Membership Payments found against the Member {0}').format(self.member)) - - total = 0 - self.payments = [] - - for doc in memberships: - self.append('payments', { - 'date': doc.from_date, - 'amount': doc.amount, - 'invoice_id': doc.invoice, - 'razorpay_payment_id': doc.payment_id, - 'membership': doc.name - }) - total += flt(doc.amount) - - self.total = total diff --git a/erpnext/regional/doctype/tax_exemption_80g_certificate/test_tax_exemption_80g_certificate.py b/erpnext/regional/doctype/tax_exemption_80g_certificate/test_tax_exemption_80g_certificate.py deleted file mode 100644 index 6fa3b85d061..00000000000 --- a/erpnext/regional/doctype/tax_exemption_80g_certificate/test_tax_exemption_80g_certificate.py +++ /dev/null @@ -1,106 +0,0 @@ -# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors -# See license.txt - -import unittest - -import frappe -from frappe.utils import getdate - -from erpnext.accounts.utils import get_fiscal_year -from erpnext.non_profit.doctype.donation.donation import create_donation -from erpnext.non_profit.doctype.donation.test_donation import ( - create_donor, - create_donor_type, - create_mode_of_payment, -) -from erpnext.non_profit.doctype.member.member import create_member -from erpnext.non_profit.doctype.membership.test_membership import make_membership, setup_membership - - -class TestTaxExemption80GCertificate(unittest.TestCase): - def setUp(self): - frappe.db.sql('delete from `tabTax Exemption 80G Certificate`') - frappe.db.sql('delete from `tabMembership`') - create_donor_type() - settings = frappe.get_doc('Non Profit Settings') - settings.company = '_Test Company' - settings.donation_company = '_Test Company' - settings.default_donor_type = '_Test Donor' - settings.creation_user = 'Administrator' - settings.save() - - company = frappe.get_doc('Company', '_Test Company') - company.pan_details = 'BBBTI3374C' - company.company_80g_number = 'NQ.CIT(E)I2018-19/DEL-IE28615-27062018/10087' - company.with_effect_from = getdate() - company.save() - - def test_duplicate_donation_certificate(self): - donor = create_donor() - create_mode_of_payment() - payment = frappe._dict({ - 'amount': 100, - 'method': 'Debit Card', - 'id': 'pay_MeXAmsgeKOhq7O' - }) - donation = create_donation(donor, payment) - - args = frappe._dict({ - 'recipient': 'Donor', - 'donor': donor.name, - 'donation': donation.name - }) - certificate = create_80g_certificate(args) - certificate.insert() - - # check company details - self.assertEqual(certificate.company_pan_number, 'BBBTI3374C') - self.assertEqual(certificate.company_80g_number, 'NQ.CIT(E)I2018-19/DEL-IE28615-27062018/10087') - - # check donation details - self.assertEqual(certificate.amount, donation.amount) - - duplicate_certificate = create_80g_certificate(args) - # duplicate validation - self.assertRaises(frappe.ValidationError, duplicate_certificate.insert) - - def test_membership_80g_certificate(self): - plan = setup_membership() - - # make test member - member_doc = create_member(frappe._dict({ - 'fullname': "_Test_Member", - 'email': "_test_member_erpnext@example.com", - 'plan_id': plan.name - })) - member_doc.make_customer_and_link() - member = member_doc.name - - membership = make_membership(member, { "from_date": getdate() }) - invoice = membership.generate_invoice(save=True) - - args = frappe._dict({ - 'recipient': 'Member', - 'member': member, - 'fiscal_year': get_fiscal_year(getdate(), as_dict=True).get('name') - }) - certificate = create_80g_certificate(args) - certificate.get_payments() - certificate.insert() - - self.assertEqual(len(certificate.payments), 1) - self.assertEqual(certificate.payments[0].amount, membership.amount) - self.assertEqual(certificate.payments[0].invoice_id, invoice.name) - - -def create_80g_certificate(args): - certificate = frappe.get_doc({ - 'doctype': 'Tax Exemption 80G Certificate', - 'recipient': args.recipient, - 'date': getdate(), - 'company': '_Test Company' - }) - - certificate.update(args) - - return certificate diff --git a/erpnext/regional/doctype/tax_exemption_80g_certificate_detail/__init__.py b/erpnext/regional/doctype/tax_exemption_80g_certificate_detail/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/regional/doctype/tax_exemption_80g_certificate_detail/tax_exemption_80g_certificate_detail.json b/erpnext/regional/doctype/tax_exemption_80g_certificate_detail/tax_exemption_80g_certificate_detail.json deleted file mode 100644 index dfa817dd271..00000000000 --- a/erpnext/regional/doctype/tax_exemption_80g_certificate_detail/tax_exemption_80g_certificate_detail.json +++ /dev/null @@ -1,66 +0,0 @@ -{ - "actions": [], - "creation": "2021-02-15 12:43:52.754124", - "doctype": "DocType", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "date", - "amount", - "invoice_id", - "column_break_4", - "razorpay_payment_id", - "membership" - ], - "fields": [ - { - "fieldname": "date", - "fieldtype": "Date", - "in_list_view": 1, - "label": "Date", - "reqd": 1 - }, - { - "fieldname": "amount", - "fieldtype": "Currency", - "in_list_view": 1, - "label": "Amount", - "reqd": 1 - }, - { - "fieldname": "invoice_id", - "fieldtype": "Link", - "in_list_view": 1, - "label": "Invoice ID", - "options": "Sales Invoice", - "reqd": 1 - }, - { - "fieldname": "razorpay_payment_id", - "fieldtype": "Data", - "label": "Razorpay Payment ID" - }, - { - "fieldname": "membership", - "fieldtype": "Link", - "label": "Membership", - "options": "Membership" - }, - { - "fieldname": "column_break_4", - "fieldtype": "Column Break" - } - ], - "index_web_pages_for_search": 1, - "istable": 1, - "links": [], - "modified": "2021-02-15 16:35:10.777587", - "modified_by": "Administrator", - "module": "Regional", - "name": "Tax Exemption 80G Certificate Detail", - "owner": "Administrator", - "permissions": [], - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1 -} \ No newline at end of file diff --git a/erpnext/regional/doctype/tax_exemption_80g_certificate_detail/tax_exemption_80g_certificate_detail.py b/erpnext/regional/doctype/tax_exemption_80g_certificate_detail/tax_exemption_80g_certificate_detail.py deleted file mode 100644 index bb7f07f6883..00000000000 --- a/erpnext/regional/doctype/tax_exemption_80g_certificate_detail/tax_exemption_80g_certificate_detail.py +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - - -# import frappe -from frappe.model.document import Document - - -class TaxExemption80GCertificateDetail(Document): - pass From 16ca81d6a61be4bf7ef2df9ae488c9a49076244c Mon Sep 17 00:00:00 2001 From: ChillarAnand Date: Thu, 27 Jan 2022 10:05:40 +0530 Subject: [PATCH 09/75] refactor: Remove non-profit code in ERPNext --- .../doctype/payment_entry/payment_entry.js | 16 +++----------- .../doctype/payment_entry/payment_entry.py | 22 +------------------ 2 files changed, 4 insertions(+), 34 deletions(-) diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.js b/erpnext/accounts/doctype/payment_entry/payment_entry.js index 3be3925b5a9..a9bc0280bcf 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.js +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.js @@ -114,8 +114,6 @@ frappe.ui.form.on('Payment Entry', { var doctypes = ["Expense Claim", "Journal Entry"]; } else if (frm.doc.party_type == "Student") { var doctypes = ["Fees"]; - } else if (frm.doc.party_type == "Donor") { - var doctypes = ["Donation"]; } else { var doctypes = ["Journal Entry"]; } @@ -144,7 +142,7 @@ frappe.ui.form.on('Payment Entry', { const child = locals[cdt][cdn]; const filters = {"docstatus": 1, "company": doc.company}; const party_type_doctypes = ['Sales Invoice', 'Sales Order', 'Purchase Invoice', - 'Purchase Order', 'Expense Claim', 'Fees', 'Dunning', 'Donation']; + 'Purchase Order', 'Expense Claim', 'Fees', 'Dunning']; if (in_list(party_type_doctypes, child.reference_doctype)) { filters[doc.party_type.toLowerCase()] = doc.party; @@ -747,8 +745,7 @@ frappe.ui.form.on('Payment Entry', { (frm.doc.payment_type=="Receive" && frm.doc.party_type=="Customer") || (frm.doc.payment_type=="Pay" && frm.doc.party_type=="Supplier") || (frm.doc.payment_type=="Pay" && frm.doc.party_type=="Employee") || - (frm.doc.payment_type=="Receive" && frm.doc.party_type=="Student") || - (frm.doc.payment_type=="Receive" && frm.doc.party_type=="Donor") + (frm.doc.payment_type=="Receive" && frm.doc.party_type=="Student") ) { if(total_positive_outstanding > total_negative_outstanding) if (!frm.doc.paid_amount) @@ -791,8 +788,7 @@ frappe.ui.form.on('Payment Entry', { (frm.doc.payment_type=="Receive" && frm.doc.party_type=="Customer") || (frm.doc.payment_type=="Pay" && frm.doc.party_type=="Supplier") || (frm.doc.payment_type=="Pay" && frm.doc.party_type=="Employee") || - (frm.doc.payment_type=="Receive" && frm.doc.party_type=="Student") || - (frm.doc.payment_type=="Receive" && frm.doc.party_type=="Donor") + (frm.doc.payment_type=="Receive" && frm.doc.party_type=="Student") ) { if(total_positive_outstanding_including_order > paid_amount) { var remaining_outstanding = total_positive_outstanding_including_order - paid_amount; @@ -951,12 +947,6 @@ frappe.ui.form.on('Payment Entry', { frappe.msgprint(__("Row #{0}: Reference Document Type must be one of Expense Claim or Journal Entry", [row.idx])); return false; } - - if (frm.doc.party_type == "Donor" && row.reference_doctype != "Donation") { - frappe.model.set_value(row.doctype, row.name, "reference_doctype", null); - frappe.msgprint(__("Row #{0}: Reference Document Type must be Donation", [row.idx])); - return false; - } } if (row) { diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py index 02a144d3e79..286052cf3a4 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.py +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py @@ -91,7 +91,6 @@ class PaymentEntry(AccountsController): self.update_expense_claim() self.update_outstanding_amounts() self.update_advance_paid() - self.update_donation() self.update_payment_schedule() self.set_status() @@ -101,7 +100,6 @@ class PaymentEntry(AccountsController): self.update_expense_claim() self.update_outstanding_amounts() self.update_advance_paid() - self.update_donation(cancel=1) self.delink_advance_entry_references() self.update_payment_schedule(cancel=1) self.set_payment_req_status() @@ -284,8 +282,6 @@ class PaymentEntry(AccountsController): valid_reference_doctypes = ("Expense Claim", "Journal Entry", "Employee Advance", "Gratuity") elif self.party_type == "Shareholder": valid_reference_doctypes = ("Journal Entry") - elif self.party_type == "Donor": - valid_reference_doctypes = ("Donation") for d in self.get("references"): if not d.allocated_amount: @@ -843,13 +839,6 @@ class PaymentEntry(AccountsController): else: update_reimbursed_amount(doc, d.allocated_amount) - def update_donation(self, cancel=0): - if self.payment_type == "Receive" and self.party_type == "Donor" and self.party: - for d in self.get("references"): - if d.reference_doctype=="Donation" and d.reference_name: - is_paid = 0 if cancel else 1 - frappe.db.set_value("Donation", d.reference_name, "paid", is_paid) - def on_recurring(self, reference_doc, auto_repeat_doc): self.reference_no = reference_doc.name self.reference_date = nowdate() @@ -1337,10 +1326,6 @@ def get_reference_details(reference_doctype, reference_name, party_account_curre total_amount = ref_doc.get("grand_total") exchange_rate = 1 outstanding_amount = ref_doc.get("outstanding_amount") - elif reference_doctype == "Donation": - total_amount = ref_doc.get("amount") - outstanding_amount = total_amount - exchange_rate = 1 elif reference_doctype == "Dunning": total_amount = ref_doc.get("dunning_amount") exchange_rate = 1 @@ -1611,8 +1596,6 @@ def set_party_type(dt): party_type = "Employee" elif dt == "Fees": party_type = "Student" - elif dt == "Donation": - party_type = "Donor" return party_type def set_party_account(dt, dn, doc, party_type): @@ -1640,7 +1623,7 @@ def set_party_account_currency(dt, party_account, doc): return party_account_currency def set_payment_type(dt, doc): - if (dt in ("Sales Order", "Donation") or (dt in ("Sales Invoice", "Fees", "Dunning") and doc.outstanding_amount > 0)) \ + if (dt == "Sales Order" or (dt in ("Sales Invoice", "Fees", "Dunning") and doc.outstanding_amount > 0)) \ or (dt=="Purchase Invoice" and doc.outstanding_amount < 0): payment_type = "Receive" else: @@ -1673,9 +1656,6 @@ def set_grand_total_and_outstanding_amount(party_amount, dt, party_account_curre elif dt == "Dunning": grand_total = doc.grand_total outstanding_amount = doc.grand_total - elif dt == "Donation": - grand_total = doc.amount - outstanding_amount = doc.amount elif dt == "Gratuity": grand_total = doc.amount outstanding_amount = flt(doc.amount) - flt(doc.paid_amount) From 899ca8b3849995ac9164e70c4d5c73d6ebdb106a Mon Sep 17 00:00:00 2001 From: ChillarAnand Date: Mon, 31 Jan 2022 17:43:01 +0530 Subject: [PATCH 10/75] refactor: Code cleanup --- .../workspace/non_profit/non_profit.json | 272 ------------------ .../v14_0/delete_non_profit_doctypes.py | 20 ++ .../80g_certificate_for_donation.json | 26 -- .../80g_certificate_for_donation/__init__.py | 0 .../80g_certificate_for_membership.json | 26 -- .../__init__.py | 0 6 files changed, 20 insertions(+), 324 deletions(-) delete mode 100644 erpnext/non_profit/workspace/non_profit/non_profit.json delete mode 100644 erpnext/regional/print_format/80g_certificate_for_donation/80g_certificate_for_donation.json delete mode 100644 erpnext/regional/print_format/80g_certificate_for_donation/__init__.py delete mode 100644 erpnext/regional/print_format/80g_certificate_for_membership/80g_certificate_for_membership.json delete mode 100644 erpnext/regional/print_format/80g_certificate_for_membership/__init__.py diff --git a/erpnext/non_profit/workspace/non_profit/non_profit.json b/erpnext/non_profit/workspace/non_profit/non_profit.json deleted file mode 100644 index fc90475fb32..00000000000 --- a/erpnext/non_profit/workspace/non_profit/non_profit.json +++ /dev/null @@ -1,272 +0,0 @@ -{ - "charts": [], - "content": "[{\"type\":\"header\",\"data\":{\"text\":\"Your Shortcuts\",\"col\":12}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Member\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Non Profit Settings\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Membership\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Chapter\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Chapter Member\",\"col\":3}},{\"type\":\"spacer\",\"data\":{\"col\":12}},{\"type\":\"header\",\"data\":{\"text\":\"Reports & Masters\",\"col\":12}},{\"type\":\"card\",\"data\":{\"card_name\":\"Loan Management\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Grant Application\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Membership\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Volunteer\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Chapter\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Donation\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Tax Exemption Certification (India)\",\"col\":4}}]", - "creation": "2020-03-02 17:23:47.811421", - "docstatus": 0, - "doctype": "Workspace", - "for_user": "", - "hide_custom": 0, - "icon": "non-profit", - "idx": 0, - "label": "Non Profit", - "links": [ - { - "hidden": 0, - "is_query_report": 0, - "label": "Loan Management", - "link_count": 0, - "onboard": 0, - "type": "Card Break" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Loan Type", - "link_count": 0, - "link_to": "Loan Type", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Loan Application", - "link_count": 0, - "link_to": "Loan Application", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Loan", - "link_count": 0, - "link_to": "Loan", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "hidden": 0, - "is_query_report": 0, - "label": "Grant Application", - "link_count": 0, - "onboard": 0, - "type": "Card Break" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Grant Application", - "link_count": 0, - "link_to": "Grant Application", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "hidden": 0, - "is_query_report": 0, - "label": "Membership", - "link_count": 0, - "onboard": 0, - "type": "Card Break" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Member", - "link_count": 0, - "link_to": "Member", - "link_type": "DocType", - "onboard": 1, - "type": "Link" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Membership", - "link_count": 0, - "link_to": "Membership", - "link_type": "DocType", - "onboard": 1, - "type": "Link" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Membership Type", - "link_count": 0, - "link_to": "Membership Type", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Membership Settings", - "link_count": 0, - "link_to": "Non Profit Settings", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "hidden": 0, - "is_query_report": 0, - "label": "Volunteer", - "link_count": 0, - "onboard": 0, - "type": "Card Break" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Volunteer", - "link_count": 0, - "link_to": "Volunteer", - "link_type": "DocType", - "onboard": 1, - "type": "Link" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Volunteer Type", - "link_count": 0, - "link_to": "Volunteer Type", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "hidden": 0, - "is_query_report": 0, - "label": "Chapter", - "link_count": 0, - "onboard": 0, - "type": "Card Break" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Chapter", - "link_count": 0, - "link_to": "Chapter", - "link_type": "DocType", - "onboard": 1, - "type": "Link" - }, - { - "hidden": 0, - "is_query_report": 0, - "label": "Donation", - "link_count": 0, - "onboard": 0, - "type": "Card Break" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Donor", - "link_count": 0, - "link_to": "Donor", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Donor Type", - "link_count": 0, - "link_to": "Donor Type", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "hidden": 0, - "is_query_report": 0, - "label": "Donation", - "link_count": 0, - "link_to": "Donation", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "hidden": 0, - "is_query_report": 0, - "label": "Tax Exemption Certification (India)", - "link_count": 0, - "link_type": "DocType", - "onboard": 0, - "type": "Card Break" - }, - { - "hidden": 0, - "is_query_report": 0, - "label": "Tax Exemption 80G Certificate", - "link_count": 0, - "link_to": "Tax Exemption 80G Certificate", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - } - ], - "modified": "2022-01-13 17:40:50.220877", - "modified_by": "Administrator", - "module": "Non Profit", - "name": "Non Profit", - "owner": "Administrator", - "parent_page": "", - "public": 1, - "restrict_to_domain": "Non Profit", - "roles": [], - "sequence_id": 18.0, - "shortcuts": [ - { - "label": "Member", - "link_to": "Member", - "type": "DocType" - }, - { - "label": "Non Profit Settings", - "link_to": "Non Profit Settings", - "type": "DocType" - }, - { - "label": "Membership", - "link_to": "Membership", - "type": "DocType" - }, - { - "label": "Chapter", - "link_to": "Chapter", - "type": "DocType" - }, - { - "label": "Chapter Member", - "link_to": "Chapter Member", - "type": "DocType" - } - ], - "title": "Non Profit" -} \ No newline at end of file diff --git a/erpnext/patches/v14_0/delete_non_profit_doctypes.py b/erpnext/patches/v14_0/delete_non_profit_doctypes.py index 3b3dbe45769..86355a6426a 100644 --- a/erpnext/patches/v14_0/delete_non_profit_doctypes.py +++ b/erpnext/patches/v14_0/delete_non_profit_doctypes.py @@ -6,6 +6,14 @@ def execute(): frappe.delete_doc("Workspace", "Non Profit", ignore_missing=True, force=True) + print_formats = frappe.get_all("Print Format", {"module": "Non Profit", "standard": "Yes"}, pluck='name') + for print_format in print_formats: + frappe.delete_doc("Print Format", print_format, ignore_missing=True, force=True) + + print_formats = ['80G Certificate for Membership', '80G Certificate for Donation'] + for print_format in print_formats: + frappe.delete_doc("Print Format", print_format, ignore_missing=True, force=True) + reports = frappe.get_all("Report", {"module": "Non Profit", "is_standard": "Yes"}, pluck='name') for report in reports: frappe.delete_doc("Report", report, ignore_missing=True, force=True) @@ -17,3 +25,15 @@ def execute(): doctypes = frappe.get_all("DocType", {"module": "Non Profit", "custom": 0}, pluck='name') for doctype in doctypes: frappe.delete_doc("DocType", doctype, ignore_missing=True) + + doctypes = ['Tax Exemption 80G Certificate', 'Tax Exemption 80G Certificate Detail'] + for doctype in doctypes: + frappe.delete_doc("DocType", doctype, ignore_missing=True) + + custom_fields = [ + {"dt": "Member", "fieldname": "pan_number"}, + {"dt": "Donor", "fieldname": "pan_number"}, + ] + for field in custom_fields: + custom_field = frappe.db.get_value("Custom Field", field) + frappe.delete_doc("Custom Field", custom_field, ignore_missing=True) diff --git a/erpnext/regional/print_format/80g_certificate_for_donation/80g_certificate_for_donation.json b/erpnext/regional/print_format/80g_certificate_for_donation/80g_certificate_for_donation.json deleted file mode 100644 index a8da0bd2097..00000000000 --- a/erpnext/regional/print_format/80g_certificate_for_donation/80g_certificate_for_donation.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "absolute_value": 0, - "align_labels_right": 0, - "creation": "2021-02-22 00:17:33.878581", - "css": ".details {\n font-size: 15px;\n font-family: Tahoma, sans-serif;;\n line-height: 150%;\n}\n\n.certificate-footer {\n font-size: 15px;\n font-family: Tahoma, sans-serif;\n line-height: 140%;\n margin-top: 120px;\n}\n\n.company-address {\n color: #666666;\n font-size: 15px;\n font-family: Tahoma, sans-serif;;\n}", - "custom_format": 1, - "default_print_language": "en", - "disabled": 0, - "doc_type": "Tax Exemption 80G Certificate", - "docstatus": 0, - "doctype": "Print Format", - "font": "Default", - "html": "{% if letter_head and not no_letterhead -%}\n
{{ letter_head }}
\n{%- endif %}\n\n
\n

{{ doc.company }} 80G Donor Certificate

\n
\n

\n\n
\n

{{ _(\"Certificate No. : \") }} {{ doc.name }}

\n

\n \t{{ _(\"Date\") }} : {{ doc.get_formatted(\"date\") }}
\n

\n

\n \n
\n\n This is to confirm that the {{ doc.company }} received an amount of {{doc.get_formatted(\"amount\")}}\n from {{ doc.donor_name }}\n {% if doc.pan_number -%}\n bearing PAN Number {{ doc.member_pan_number }}\n {%- endif %}\n\n via the Mode of Payment {{doc.mode_of_payment}}\n\n {% if doc.razorpay_payment_id -%}\n bearing RazorPay Payment ID {{ doc.razorpay_payment_id }}\n {%- endif %}\n\n on {{ doc.get_formatted(\"date_of_donation\") }}\n

\n \n

\n We thank you for your contribution towards the corpus of the {{ doc.company }} and helping support our work.\n

\n\n
\n
\n\n

\n

{{doc.company_address_display }}

\n\n", - "idx": 0, - "line_breaks": 0, - "modified": "2021-02-22 00:20:08.516600", - "modified_by": "Administrator", - "module": "Regional", - "name": "80G Certificate for Donation", - "owner": "Administrator", - "print_format_builder": 0, - "print_format_type": "Jinja", - "raw_printing": 0, - "show_section_headings": 0, - "standard": "Yes" -} \ No newline at end of file diff --git a/erpnext/regional/print_format/80g_certificate_for_donation/__init__.py b/erpnext/regional/print_format/80g_certificate_for_donation/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/regional/print_format/80g_certificate_for_membership/80g_certificate_for_membership.json b/erpnext/regional/print_format/80g_certificate_for_membership/80g_certificate_for_membership.json deleted file mode 100644 index f1b15aab298..00000000000 --- a/erpnext/regional/print_format/80g_certificate_for_membership/80g_certificate_for_membership.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "absolute_value": 0, - "align_labels_right": 0, - "creation": "2021-02-15 16:53:55.026611", - "css": ".details {\n font-size: 15px;\n font-family: Tahoma, sans-serif;;\n line-height: 150%;\n}\n\n.certificate-footer {\n font-size: 15px;\n font-family: Tahoma, sans-serif;\n line-height: 140%;\n margin-top: 120px;\n}\n\n.company-address {\n color: #666666;\n font-size: 15px;\n font-family: Tahoma, sans-serif;;\n}", - "custom_format": 1, - "default_print_language": "en", - "disabled": 0, - "doc_type": "Tax Exemption 80G Certificate", - "docstatus": 0, - "doctype": "Print Format", - "font": "Default", - "html": "{% if letter_head and not no_letterhead -%}\n
{{ letter_head }}
\n{%- endif %}\n\n
\n

{{ doc.company }} Members 80G Donor Certificate

\n

Financial Cycle {{ doc.fiscal_year }}

\n
\n

\n\n
\n

{{ _(\"Certificate No. : \") }} {{ doc.name }}

\n

\n \t{{ _(\"Date\") }} : {{ doc.get_formatted(\"date\") }}
\n

\n

\n \n
\n This is to confirm that the {{ doc.company }} received a total amount of {{doc.get_formatted(\"total\")}}\n from {{ doc.member_name }}\n {% if doc.pan_number -%}\n bearing PAN Number {{ doc.member_pan_number }}\n {%- endif %}\n as per the payment details given below:\n \n

\n \n \t\n \t\t\n \t\t\t\n \t\t\t\n \t\t\t\n \t\t\n \t\n \t\n \t\t{%- for payment in doc.payments -%}\n \t\t\n \t\t\t\n \t\t\t\n \t\t\t\n \t\t\n \t\t{%- endfor -%}\n \t\n
{{ _(\"Date\") }}{{ _(\"Amount\") }}{{ _(\"Invoice ID\") }}
{{ payment.date }} {{ payment.get_formatted(\"amount\") }}{{ payment.invoice_id }}
\n \n
\n \n

\n We thank you for your contribution towards the corpus of the {{ doc.company }} and helping support our work.\n

\n\n
\n
\n\n

\n

{{doc.company_address_display }}

\n\n", - "idx": 0, - "line_breaks": 0, - "modified": "2021-02-21 23:29:00.778973", - "modified_by": "Administrator", - "module": "Regional", - "name": "80G Certificate for Membership", - "owner": "Administrator", - "print_format_builder": 0, - "print_format_type": "Jinja", - "raw_printing": 0, - "show_section_headings": 0, - "standard": "Yes" -} \ No newline at end of file diff --git a/erpnext/regional/print_format/80g_certificate_for_membership/__init__.py b/erpnext/regional/print_format/80g_certificate_for_membership/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 From dddeef71799bdc9c0c787fc1fee9dd05e3c998e0 Mon Sep 17 00:00:00 2001 From: ChillarAnand Date: Thu, 3 Feb 2022 16:41:36 +0530 Subject: [PATCH 11/75] chore: Clean up whitespace --- erpnext/patches.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 09cfdcee822..a8134f20fcb 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -336,7 +336,6 @@ erpnext.patches.v13_0.enable_provisional_accounting erpnext.patches.v13_0.non_profit_deprecation_warning erpnext.patches.v14_0.delete_non_profit_doctypes - [post_model_sync] erpnext.patches.v14_0.rename_ongoing_status_in_sla_documents erpnext.patches.v14_0.add_default_exit_questionnaire_notification_template From d636c3fb04ae5b1b95c67052bfb5f894e4cbf4f4 Mon Sep 17 00:00:00 2001 From: Devin Slauenwhite Date: Wed, 9 Feb 2022 10:52:38 -0500 Subject: [PATCH 12/75] test: many users linked to customer shopping cart --- .../shopping_cart/test_shopping_cart.py | 25 +++++++++++-------- erpnext/tests/utils.py | 14 +++++++++++ 2 files changed, 29 insertions(+), 10 deletions(-) diff --git a/erpnext/e_commerce/shopping_cart/test_shopping_cart.py b/erpnext/e_commerce/shopping_cart/test_shopping_cart.py index 8519e68d094..05c874af98c 100644 --- a/erpnext/e_commerce/shopping_cart/test_shopping_cart.py +++ b/erpnext/e_commerce/shopping_cart/test_shopping_cart.py @@ -57,13 +57,19 @@ class TestShoppingCart(unittest.TestCase): return quotation def test_get_cart_customer(self): - self.login_as_customer() + def validate_quotation(): + # test if quotation with customer is fetched + quotation = _get_cart_quotation() + self.assertEqual(quotation.quotation_to, "Customer") + self.assertEqual(quotation.party_name, "_Test Customer") + self.assertEqual(quotation.contact_email, frappe.session.user) + return quotation - # test if quotation with customer is fetched - quotation = _get_cart_quotation() - self.assertEqual(quotation.quotation_to, "Customer") - self.assertEqual(quotation.party_name, "_Test Customer") - self.assertEqual(quotation.contact_email, frappe.session.user) + self.login_as_customer("test_contact_two_customer@example.com", "_Test Contact 2 For _Test Customer") + validate_quotation() + + self.login_as_customer() + quotation = validate_quotation() return quotation @@ -254,10 +260,9 @@ class TestShoppingCart(unittest.TestCase): self.create_user_if_not_exists("test_cart_user@example.com") frappe.set_user("test_cart_user@example.com") - def login_as_customer(self): - self.create_user_if_not_exists("test_contact_customer@example.com", - "_Test Contact For _Test Customer") - frappe.set_user("test_contact_customer@example.com") + def login_as_customer(self, email="test_contact_customer@example.com", name="_Test Contact For _Test Customer"): + self.create_user_if_not_exists(email, name) + frappe.set_user(email) def clear_existing_quotations(self): quotations = frappe.get_all("Quotation", filters={ diff --git a/erpnext/tests/utils.py b/erpnext/tests/utils.py index 2bd7e9e71d0..40c95eb7a3a 100644 --- a/erpnext/tests/utils.py +++ b/erpnext/tests/utils.py @@ -66,6 +66,20 @@ def create_test_contact_and_address(): contact.add_phone("+91 0000000000", is_primary_phone=True) contact.insert() + contact_two = frappe.get_doc({ + "doctype": 'Contact', + "first_name": "_Test Contact 2 for _Test Customer", + "links": [ + { + "link_doctype": "Customer", + "link_name": "_Test Customer" + } + ] + }) + contact_two.add_email("test_contact_two_customer@example.com", is_primary=True) + contact_two.add_phone("+92 0000000000", is_primary_phone=True) + contact_two.insert() + @contextmanager def change_settings(doctype, settings_dict): From 34ad5b1abf534f55876fcfac2852df2ea42ecb41 Mon Sep 17 00:00:00 2001 From: Devin Slauenwhite Date: Wed, 9 Feb 2022 10:53:24 -0500 Subject: [PATCH 13/75] fix: get cart for logged in user. --- erpnext/e_commerce/shopping_cart/cart.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/e_commerce/shopping_cart/cart.py b/erpnext/e_commerce/shopping_cart/cart.py index 458cf69af7e..372aed0b95f 100644 --- a/erpnext/e_commerce/shopping_cart/cart.py +++ b/erpnext/e_commerce/shopping_cart/cart.py @@ -310,7 +310,7 @@ def _get_cart_quotation(party=None): party = get_party() quotation = frappe.get_all("Quotation", fields=["name"], filters= - {"party_name": party.name, "order_type": "Shopping Cart", "docstatus": 0}, + {"party_name": party.name, "contact_email": frappe.session.user, "order_type": "Shopping Cart", "docstatus": 0}, order_by="modified desc", limit_page_length=1) if quotation: From 49bee568a1d5bcfc315f539af734bc55a84a35ef Mon Sep 17 00:00:00 2001 From: Devin Slauenwhite Date: Wed, 9 Feb 2022 12:03:05 -0500 Subject: [PATCH 14/75] fix: get cart items for logged in user. --- erpnext/e_commerce/product_data_engine/query.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/e_commerce/product_data_engine/query.py b/erpnext/e_commerce/product_data_engine/query.py index 007bf8b3489..cfc3c7b357c 100644 --- a/erpnext/e_commerce/product_data_engine/query.py +++ b/erpnext/e_commerce/product_data_engine/query.py @@ -264,7 +264,7 @@ class ProductQuery: customer = get_customer(silent=True) if customer: quotation = frappe.get_all("Quotation", fields=["name"], filters= - {"party_name": customer, "order_type": "Shopping Cart", "docstatus": 0}, + {"party_name": customer, "contact_email": frappe.session.user, "order_type": "Shopping Cart", "docstatus": 0}, order_by="modified desc", limit_page_length=1) if quotation: items = frappe.get_all( @@ -298,4 +298,4 @@ class ProductQuery: # slice results manually result[:self.page_length] - return result \ No newline at end of file + return result From 72fe5590313f82ee22421339ca780ba9d4249ed1 Mon Sep 17 00:00:00 2001 From: ChillarAnand Date: Thu, 17 Feb 2022 08:33:15 +0530 Subject: [PATCH 15/75] refactor: Remove non profit templates --- .../templates/pages/non_profit/__init__.py | 0 .../pages/non_profit/join-chapter.html | 59 ------------------- .../pages/non_profit/join_chapter.js | 12 ---- .../pages/non_profit/join_chapter.py | 23 -------- .../pages/non_profit/leave-chapter.html | 42 ------------- .../pages/non_profit/leave_chapter.py | 8 --- 6 files changed, 144 deletions(-) delete mode 100644 erpnext/templates/pages/non_profit/__init__.py delete mode 100644 erpnext/templates/pages/non_profit/join-chapter.html delete mode 100644 erpnext/templates/pages/non_profit/join_chapter.js delete mode 100644 erpnext/templates/pages/non_profit/join_chapter.py delete mode 100644 erpnext/templates/pages/non_profit/leave-chapter.html delete mode 100644 erpnext/templates/pages/non_profit/leave_chapter.py diff --git a/erpnext/templates/pages/non_profit/__init__.py b/erpnext/templates/pages/non_profit/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/templates/pages/non_profit/join-chapter.html b/erpnext/templates/pages/non_profit/join-chapter.html deleted file mode 100644 index 4923efc4e8c..00000000000 --- a/erpnext/templates/pages/non_profit/join-chapter.html +++ /dev/null @@ -1,59 +0,0 @@ -{% extends "templates/web.html" %} - -{% block page_content %} - -{% macro chapter_button() %} -

- Go to Chapter Page

-{% endmacro %} -{% if frappe.session.user=='Guest' %} -

Please signup and login to join this chapter

-

Login

-{% else %} - {% if already_member %} -

You are already a member of {{ chapter.name }}!

- {{ chapter_button() }} -

Leave Chapter

- {% else %} - {% if request.method=='POST' %} -

Welcome to chapter {{ chapter.name }}!

- {{ chapter_button() }} - {% else %} -
-
-
-
-
- - -
-
- - -
-
- - -
-
- - -
-
- -
-
-
-
-
- {% endif %} - {% endif %} - -{% endif %} - -{% endblock %} diff --git a/erpnext/templates/pages/non_profit/join_chapter.js b/erpnext/templates/pages/non_profit/join_chapter.js deleted file mode 100644 index e2bc8bca717..00000000000 --- a/erpnext/templates/pages/non_profit/join_chapter.js +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) 2017, EOSSF and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Chapter Member', { - onsubmit: function (frm) { - console.log("here" + frappe.session.user) - // body... - } - refresh: function(frm) { - - } -}); diff --git a/erpnext/templates/pages/non_profit/join_chapter.py b/erpnext/templates/pages/non_profit/join_chapter.py deleted file mode 100644 index 7caf87db2b3..00000000000 --- a/erpnext/templates/pages/non_profit/join_chapter.py +++ /dev/null @@ -1,23 +0,0 @@ -import frappe - - -def get_context(context): - context.no_cache = True - chapter = frappe.get_doc('Chapter', frappe.form_dict.name) - if frappe.session.user!='Guest': - if frappe.session.user in [d.user for d in chapter.members if d.enabled == 1]: - context.already_member = True - else: - if frappe.request.method=='GET': - pass - elif frappe.request.method=='POST': - chapter.append('members', dict( - user=frappe.session.user, - introduction=frappe.form_dict.introduction, - website_url=frappe.form_dict.website_url, - enabled=1 - )) - chapter.save(ignore_permissions=1) - frappe.db.commit() - - context.chapter = chapter diff --git a/erpnext/templates/pages/non_profit/leave-chapter.html b/erpnext/templates/pages/non_profit/leave-chapter.html deleted file mode 100644 index fd7658b3b1e..00000000000 --- a/erpnext/templates/pages/non_profit/leave-chapter.html +++ /dev/null @@ -1,42 +0,0 @@ -{% extends "templates/web.html" %} -{% block page_content %} - - {% if member_deleted %} -

You are not a member of {{ chapter.name }}!

-
-
-
- - -
- -
-
-

Please signup and login to join this chapter

- -

Become Member agian

- {% endif %} - -{% endblock %} diff --git a/erpnext/templates/pages/non_profit/leave_chapter.py b/erpnext/templates/pages/non_profit/leave_chapter.py deleted file mode 100644 index 65908e1dd9d..00000000000 --- a/erpnext/templates/pages/non_profit/leave_chapter.py +++ /dev/null @@ -1,8 +0,0 @@ -import frappe - - -def get_context(context): - context.no_cache = True - chapter = frappe.get_doc('Chapter', frappe.form_dict.name) - context.member_deleted = True - context.chapter = chapter From b5ff9b27bdf762c4118974d69ef8b78b2c228348 Mon Sep 17 00:00:00 2001 From: ChillarAnand Date: Thu, 17 Feb 2022 08:33:55 +0530 Subject: [PATCH 16/75] refactor: Clean up non-profit setup --- erpnext/__init__.py | 8 ------ erpnext/patches.txt | 2 +- .../v14_0/delete_non_profit_doctypes.py | 28 ++++++++++++++----- erpnext/regional/india/setup.py | 9 ------ 4 files changed, 22 insertions(+), 25 deletions(-) diff --git a/erpnext/__init__.py b/erpnext/__init__.py index 0b4696c8034..a44c8fabe3b 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -130,11 +130,3 @@ def allow_regional(fn): return fn(*args, **kwargs) return caller - -def get_last_membership(member): - '''Returns last membership if exists''' - last_membership = frappe.get_all('Membership', 'name,to_date,membership_type', - dict(member=member, paid=1), order_by='to_date desc', limit=1) - - if last_membership: - return last_membership[0] diff --git a/erpnext/patches.txt b/erpnext/patches.txt index a8134f20fcb..7bc70714a29 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -334,7 +334,6 @@ erpnext.patches.v13_0.update_asset_quantity_field erpnext.patches.v13_0.delete_bank_reconciliation_detail erpnext.patches.v13_0.enable_provisional_accounting erpnext.patches.v13_0.non_profit_deprecation_warning -erpnext.patches.v14_0.delete_non_profit_doctypes [post_model_sync] erpnext.patches.v14_0.rename_ongoing_status_in_sla_documents @@ -351,3 +350,4 @@ erpnext.patches.v12_0.add_company_link_to_einvoice_settings erpnext.patches.v14_0.migrate_cost_center_allocations erpnext.patches.v13_0.convert_to_website_item_in_item_card_group_template erpnext.patches.v13_0.shopping_cart_to_ecommerce +erpnext.patches.v14_0.delete_non_profit_doctypes diff --git a/erpnext/patches/v14_0/delete_non_profit_doctypes.py b/erpnext/patches/v14_0/delete_non_profit_doctypes.py index 86355a6426a..39f2fecf08e 100644 --- a/erpnext/patches/v14_0/delete_non_profit_doctypes.py +++ b/erpnext/patches/v14_0/delete_non_profit_doctypes.py @@ -30,10 +30,24 @@ def execute(): for doctype in doctypes: frappe.delete_doc("DocType", doctype, ignore_missing=True) - custom_fields = [ - {"dt": "Member", "fieldname": "pan_number"}, - {"dt": "Donor", "fieldname": "pan_number"}, - ] - for field in custom_fields: - custom_field = frappe.db.get_value("Custom Field", field) - frappe.delete_doc("Custom Field", custom_field, ignore_missing=True) + forms = ['grant-application', 'certification-application', 'certification-application-usd'] + for form in forms: + frappe.delete_doc("Web Form", form, ignore_missing=True) + + custom_fields = { + 'Member': ['pan_number'], + 'Donor': ['pan_number'], + 'Company': [ + 'non_profit_section', 'company_80g_number', 'with_effect_from', + 'non_profit_column_break', 'pan_details' + ], + } + + for doc, fields in custom_fields.items(): + filters = { + 'dt': doc, + 'fieldname': ['in', fields] + } + records = frappe.get_all('Custom Field', filters=filters, pluck='name') + for record in records: + frappe.delete_doc('Custom Field', record, ignore_missing=True, force=True) diff --git a/erpnext/regional/india/setup.py b/erpnext/regional/india/setup.py index c2e83045c7d..8f3ef62c129 100644 --- a/erpnext/regional/india/setup.py +++ b/erpnext/regional/india/setup.py @@ -610,15 +610,6 @@ def get_custom_fields(): dict(fieldname='hra_column_break', fieldtype='Column Break', insert_after='hra_component'), dict(fieldname='arrear_component', label='Arrear Component', fieldtype='Link', options='Salary Component', insert_after='hra_column_break'), - dict(fieldname='non_profit_section', label='Non Profit Settings', - fieldtype='Section Break', insert_after='arrear_component', collapsible=1), - dict(fieldname='company_80g_number', label='80G Number', - fieldtype='Data', insert_after='non_profit_section'), - dict(fieldname='with_effect_from', label='80G With Effect From', - fieldtype='Date', insert_after='company_80g_number'), - dict(fieldname='non_profit_column_break', fieldtype='Column Break', insert_after='with_effect_from'), - dict(fieldname='pan_details', label='PAN Number', - fieldtype='Data', insert_after='non_profit_column_break') ], 'Employee Tax Exemption Declaration':[ dict(fieldname='hra_section', label='HRA Exemption', From fb59247182a4511fbdec106cc0ca0f68253b8579 Mon Sep 17 00:00:00 2001 From: ChillarAnand Date: Thu, 17 Feb 2022 15:15:10 +0530 Subject: [PATCH 17/75] fix: Delete party type records in patch --- erpnext/patches/v14_0/delete_non_profit_doctypes.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/erpnext/patches/v14_0/delete_non_profit_doctypes.py b/erpnext/patches/v14_0/delete_non_profit_doctypes.py index 39f2fecf08e..5b1cfefa4b4 100644 --- a/erpnext/patches/v14_0/delete_non_profit_doctypes.py +++ b/erpnext/patches/v14_0/delete_non_profit_doctypes.py @@ -34,6 +34,13 @@ def execute(): for form in forms: frappe.delete_doc("Web Form", form, ignore_missing=True) + custom_records = [ + {"doctype": "Party Type", "name": "Member"}, + {"doctype": "Party Type", "name": "Donor"}, + ] + for record in custom_records: + frappe.delete_doc(record['doctype'], record['name'], ignore_missing=True) + custom_fields = { 'Member': ['pan_number'], 'Donor': ['pan_number'], From 358734dceabbd503cbd2ae3d8401fda960140a80 Mon Sep 17 00:00:00 2001 From: ChillarAnand Date: Thu, 17 Feb 2022 16:31:27 +0530 Subject: [PATCH 18/75] fix: Skip deletion if linked docs exists --- erpnext/patches/v14_0/delete_non_profit_doctypes.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/erpnext/patches/v14_0/delete_non_profit_doctypes.py b/erpnext/patches/v14_0/delete_non_profit_doctypes.py index 5b1cfefa4b4..d53aecca921 100644 --- a/erpnext/patches/v14_0/delete_non_profit_doctypes.py +++ b/erpnext/patches/v14_0/delete_non_profit_doctypes.py @@ -39,7 +39,10 @@ def execute(): {"doctype": "Party Type", "name": "Donor"}, ] for record in custom_records: - frappe.delete_doc(record['doctype'], record['name'], ignore_missing=True) + try: + frappe.delete_doc(record['doctype'], record['name'], ignore_missing=True) + except frappe.LinkExistsError: + pass custom_fields = { 'Member': ['pan_number'], From 70b960e650bbc1c418eecd14ac42d64a3103a43c Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Tue, 22 Feb 2022 09:16:08 +0530 Subject: [PATCH 19/75] fix: Account filter in PSOA --- .../process_statement_of_accounts.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py index 09aa72352e4..1b34d6d1f2f 100644 --- a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py +++ b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py @@ -73,7 +73,7 @@ def get_report_pdf(doc, consolidated=True): 'to_date': doc.to_date, 'company': doc.company, 'finance_book': doc.finance_book if doc.finance_book else None, - 'account': doc.account if doc.account else None, + 'account': [doc.account] if doc.account else None, 'party_type': 'Customer', 'party': [entry.customer], 'presentation_currency': presentation_currency, From 8005fee6569abed607c57d31b26531925fd7e15b Mon Sep 17 00:00:00 2001 From: Saqib Ansari Date: Tue, 22 Feb 2022 15:06:19 +0530 Subject: [PATCH 20/75] feat: update ordered qty for packed items --- .../doctype/purchase_order/purchase_order.py | 10 +++++++++ .../purchase_order_item.json | 13 ++++++++++- .../doctype/sales_order/sales_order.js | 22 ++++++++++++++++++- .../doctype/sales_order/sales_order.py | 5 +++++ .../doctype/packed_item/packed_item.json | 11 +++++++++- 5 files changed, 58 insertions(+), 3 deletions(-) diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py index 1b5f35efbb4..2e7d3063ccb 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.py +++ b/erpnext/buying/doctype/purchase_order/purchase_order.py @@ -316,6 +316,16 @@ class PurchaseOrder(BuyingController): 'target_ref_field': 'stock_qty', 'source_field': 'stock_qty' }) + self.status_updater.append({ + 'source_dt': 'Purchase Order Item', + 'target_dt': 'Packed Item', + 'target_field': 'ordered_qty', + 'target_parent_dt': 'Sales Order', + 'target_parent_field': '', + 'join_field': 'sales_order_packed_item', + 'target_ref_field': 'qty', + 'source_field': 'stock_qty' + }) def update_delivered_qty_in_sales_order(self): """Update delivered qty in Sales Order for drop ship""" diff --git a/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json b/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json index 87cd57517e2..c26d592e3ee 100644 --- a/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json +++ b/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json @@ -63,6 +63,7 @@ "material_request_item", "sales_order", "sales_order_item", + "sales_order_packed_item", "supplier_quotation", "supplier_quotation_item", "col_break5", @@ -837,21 +838,31 @@ "label": "Product Bundle", "options": "Product Bundle", "read_only": 1 + }, + { + "fieldname": "sales_order_packed_item", + "fieldtype": "Data", + "label": "Sales Order Packed Item", + "no_copy": 1, + "print_hide": 1, + "search_index": 1 } ], "idx": 1, "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2021-08-30 20:06:26.712097", + "modified": "2022-02-02 13:10:18.398976", "modified_by": "Administrator", "module": "Buying", "name": "Purchase Order Item", + "naming_rule": "Random", "owner": "Administrator", "permissions": [], "quick_entry": 1, "search_fields": "item_name", "sort_field": "modified", "sort_order": "DESC", + "states": [], "track_changes": 1 } \ No newline at end of file diff --git a/erpnext/selling/doctype/sales_order/sales_order.js b/erpnext/selling/doctype/sales_order/sales_order.js index eb98e6c0bf8..f80eaf2757e 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.js +++ b/erpnext/selling/doctype/sales_order/sales_order.js @@ -562,6 +562,7 @@ erpnext.selling.SalesOrderController = class SalesOrderController extends erpnex var me = this; var dialog = new frappe.ui.Dialog({ title: __("Select Items"), + size: "large", fields: [ { "fieldtype": "Check", @@ -663,7 +664,8 @@ erpnext.selling.SalesOrderController = class SalesOrderController extends erpnex } else { let po_items = []; me.frm.doc.items.forEach(d => { - let pending_qty = (flt(d.stock_qty) - flt(d.ordered_qty)) / flt(d.conversion_factor); + let ordered_qty = me.get_ordered_qty(d, me.frm.doc); + let pending_qty = (flt(d.stock_qty) - ordered_qty) / flt(d.conversion_factor); if (pending_qty > 0) { po_items.push({ "doctype": "Sales Order Item", @@ -689,6 +691,24 @@ erpnext.selling.SalesOrderController = class SalesOrderController extends erpnex dialog.show(); } + get_ordered_qty(item, so) { + let ordered_qty = item.ordered_qty; + if (so.packed_items) { + // calculate ordered qty based on packed items in case of product bundle + let packed_items = so.packed_items.filter( + (pi) => pi.parent_detail_docname == item.name + ); + if (packed_items) { + ordered_qty = packed_items.reduce( + (sum, pi) => sum + flt(pi.ordered_qty), + 0 + ); + ordered_qty = ordered_qty / packed_items.length; + } + } + return ordered_qty; + } + hold_sales_order(){ var me = this; var d = new frappe.ui.Dialog({ diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py index 0f5b1e3b89c..abbb3c9b90e 100755 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -877,6 +877,9 @@ def make_purchase_order(source_name, selected_items=None, target_doc=None): target.stock_qty = (flt(source.stock_qty) - flt(source.ordered_qty)) target.project = source_parent.project + def update_item_for_packed_item(source, target, source_parent): + target.qty = flt(source.qty) - flt(source.ordered_qty) + # po = frappe.get_list("Purchase Order", filters={"sales_order":source_name, "supplier":supplier, "docstatus": ("<", "2")}) doc = get_mapped_doc("Sales Order", source_name, { "Sales Order": { @@ -920,6 +923,7 @@ def make_purchase_order(source_name, selected_items=None, target_doc=None): "Packed Item": { "doctype": "Purchase Order Item", "field_map": [ + ["name", "sales_order_packed_item"], ["parent", "sales_order"], ["uom", "uom"], ["conversion_factor", "conversion_factor"], @@ -934,6 +938,7 @@ def make_purchase_order(source_name, selected_items=None, target_doc=None): "supplier", "pricing_rules" ], + "postprocess": update_item_for_packed_item, "condition": lambda doc: doc.parent_item in items_to_map } }, target_doc, set_missing_values) diff --git a/erpnext/stock/doctype/packed_item/packed_item.json b/erpnext/stock/doctype/packed_item/packed_item.json index d2d47897658..d6e2e9ce2d7 100644 --- a/erpnext/stock/doctype/packed_item/packed_item.json +++ b/erpnext/stock/doctype/packed_item/packed_item.json @@ -26,6 +26,7 @@ "section_break_13", "actual_qty", "projected_qty", + "ordered_qty", "column_break_16", "incoming_rate", "page_break", @@ -224,13 +225,21 @@ "label": "Rate", "print_hide": 1, "read_only": 1 + }, + { + "allow_on_submit": 1, + "fieldname": "ordered_qty", + "fieldtype": "Float", + "label": "Ordered Qty", + "no_copy": 1, + "read_only": 1 } ], "idx": 1, "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2022-01-28 16:03:30.780111", + "modified": "2022-02-22 12:57:45.325488", "modified_by": "Administrator", "module": "Stock", "name": "Packed Item", From 8e3f1e306d705109a51271ba262b46fe4798a793 Mon Sep 17 00:00:00 2001 From: Saqib Ansari Date: Tue, 22 Feb 2022 15:34:26 +0530 Subject: [PATCH 21/75] test: po updates packed item's ordered_qty --- .../doctype/sales_order/test_sales_order.py | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py index 73c5bd299a2..e56e56cea19 100644 --- a/erpnext/selling/doctype/sales_order/test_sales_order.py +++ b/erpnext/selling/doctype/sales_order/test_sales_order.py @@ -959,6 +959,42 @@ class TestSalesOrder(ERPNextTestCase): self.assertEqual(purchase_order.items[0].item_code, "_Test Bundle Item 1") self.assertEqual(purchase_order.items[1].item_code, "_Test Bundle Item 2") + def test_purchase_order_updates_packed_item_ordered_qty(self): + """ + Tests if the packed item's `ordered_qty` is updated with the quantity of the Purchase Order + """ + from erpnext.selling.doctype.sales_order.sales_order import make_purchase_order + + product_bundle = make_item("_Test Product Bundle", {"is_stock_item": 0}) + make_item("_Test Bundle Item 1", {"is_stock_item": 1}) + make_item("_Test Bundle Item 2", {"is_stock_item": 1}) + + make_product_bundle("_Test Product Bundle", + ["_Test Bundle Item 1", "_Test Bundle Item 2"]) + + so_items = [ + { + "item_code": product_bundle.item_code, + "warehouse": "", + "qty": 2, + "rate": 400, + "delivered_by_supplier": 1, + "supplier": '_Test Supplier' + } + ] + + so = make_sales_order(item_list=so_items) + + purchase_order = make_purchase_order(so.name, selected_items=so_items) + purchase_order.supplier = "_Test Supplier" + purchase_order.set_warehouse = "_Test Warehouse - _TC" + purchase_order.save() + purchase_order.submit() + + so.reload() + self.assertEqual(so.packed_items[0].ordered_qty, 2) + self.assertEqual(so.packed_items[1].ordered_qty, 2) + def test_reserved_qty_for_closing_so(self): bin = frappe.get_all("Bin", filters={"item_code": "_Test Item", "warehouse": "_Test Warehouse - _TC"}, fields=["reserved_qty"]) From 239733acd1ad770fc58b5bedd2cf0bb6e75c569d Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Wed, 23 Feb 2022 20:41:49 +0530 Subject: [PATCH 22/75] fix: Make abbreviation limit to 10 --- erpnext/public/js/setup_wizard.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/erpnext/public/js/setup_wizard.js b/erpnext/public/js/setup_wizard.js index e746ce9ae09..83b69aebc5b 100644 --- a/erpnext/public/js/setup_wizard.js +++ b/erpnext/public/js/setup_wizard.js @@ -78,11 +78,11 @@ erpnext.setup.slides_settings = [ slide.get_input("company_name").on("change", function () { var parts = slide.get_input("company_name").val().split(" "); var abbr = $.map(parts, function (p) { return p ? p.substr(0, 1) : null }).join(""); - slide.get_field("company_abbr").set_value(abbr.slice(0, 5).toUpperCase()); + slide.get_field("company_abbr").set_value(abbr.slice(0, 10).toUpperCase()); }).val(frappe.boot.sysdefaults.company_name || "").trigger("change"); slide.get_input("company_abbr").on("change", function () { - if (slide.get_input("company_abbr").val().length > 5) { + if (slide.get_input("company_abbr").val().length > 10) { frappe.msgprint(__("Company Abbreviation cannot have more than 5 characters")); slide.get_field("company_abbr").set_value(""); } @@ -96,7 +96,7 @@ erpnext.setup.slides_settings = [ if (!this.values.company_abbr) { return false; } - if (this.values.company_abbr.length > 5) { + if (this.values.company_abbr.length > 10) { return false; } return true; From b1a46c80d5571d23a749656c98056ba1411b433f Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Thu, 24 Feb 2022 13:11:17 +0530 Subject: [PATCH 23/75] fix: Total taxes and charges in payment entry for multicurrency payments --- .../doctype/payment_entry/payment_entry.js | 13 ++++++++++--- .../doctype/payment_entry/payment_entry.json | 14 +++++++++++++- .../doctype/payment_entry/payment_entry.py | 8 ++++++-- 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.js b/erpnext/accounts/doctype/payment_entry/payment_entry.js index 3be3925b5a9..c14251b7d28 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.js +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.js @@ -196,8 +196,14 @@ frappe.ui.form.on('Payment Entry', { frm.doc.paid_from_account_currency != frm.doc.paid_to_account_currency)); frm.toggle_display("base_paid_amount", frm.doc.paid_from_account_currency != company_currency); - frm.toggle_display("base_total_taxes_and_charges", frm.doc.total_taxes_and_charges && - (frm.doc.paid_from_account_currency != company_currency)); + + if (frm.doc.payment_type == "Pay") { + frm.toggle_display("base_total_taxes_and_charges", frm.doc.total_taxes_and_charges && + (frm.doc.paid_to_account_currency != company_currency)); + } else { + frm.toggle_display("base_total_taxes_and_charges", frm.doc.total_taxes_and_charges && + (frm.doc.paid_from_account_currency != company_currency)); + } frm.toggle_display("base_received_amount", ( frm.doc.paid_to_account_currency != company_currency @@ -232,7 +238,8 @@ frappe.ui.form.on('Payment Entry', { var company_currency = frm.doc.company? frappe.get_doc(":Company", frm.doc.company).default_currency: ""; frm.set_currency_labels(["base_paid_amount", "base_received_amount", "base_total_allocated_amount", - "difference_amount", "base_paid_amount_after_tax", "base_received_amount_after_tax"], company_currency); + "difference_amount", "base_paid_amount_after_tax", "base_received_amount_after_tax", + "base_total_taxes_and_charges"], company_currency); frm.set_currency_labels(["paid_amount"], frm.doc.paid_from_account_currency); frm.set_currency_labels(["received_amount"], frm.doc.paid_to_account_currency); diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.json b/erpnext/accounts/doctype/payment_entry/payment_entry.json index c8d1db91f54..3fc1adff2d3 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.json +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.json @@ -66,7 +66,9 @@ "tax_withholding_category", "section_break_56", "taxes", + "section_break_60", "base_total_taxes_and_charges", + "column_break_61", "total_taxes_and_charges", "deductions_or_loss_section", "deductions", @@ -715,12 +717,21 @@ "fieldtype": "Data", "hidden": 1, "label": "Paid To Account Type" + }, + { + "fieldname": "column_break_61", + "fieldtype": "Column Break" + }, + { + "fieldname": "section_break_60", + "fieldtype": "Section Break", + "hide_border": 1 } ], "index_web_pages_for_search": 1, "is_submittable": 1, "links": [], - "modified": "2021-11-24 18:58:24.919764", + "modified": "2022-02-23 20:08:39.559814", "modified_by": "Administrator", "module": "Accounts", "name": "Payment Entry", @@ -763,6 +774,7 @@ "show_name_in_global_search": 1, "sort_field": "modified", "sort_order": "DESC", + "states": [], "title_field": "title", "track_changes": 1 } \ No newline at end of file diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py index 02a144d3e79..6ec15e1e879 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.py +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py @@ -945,8 +945,12 @@ class PaymentEntry(AccountsController): tax.base_total = tax.total * self.source_exchange_rate - self.total_taxes_and_charges += current_tax_amount - self.base_total_taxes_and_charges += current_tax_amount * self.source_exchange_rate + if self.payment_type == 'Pay': + self.base_total_taxes_and_charges += current_tax_amount * self.source_exchange_rate + self.total_taxes_and_charges += current_tax_amount * self.target_exchange_rate + else: + self.base_total_taxes_and_charges += current_tax_amount * self.target_exchange_rate + self.total_taxes_and_charges += current_tax_amount * self.source_exchange_rate if self.get('taxes'): self.paid_amount_after_tax = self.get('taxes')[-1].base_total From 03739147049ed78bd2bb43f5f47cfc70d6be43ba Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Thu, 24 Feb 2022 14:42:56 +0530 Subject: [PATCH 24/75] fix: Commission not applied while making Sales Order from Quotation --- .../doctype/sales_invoice_item/sales_invoice_item.json | 6 ++++-- .../doctype/sales_order_item/sales_order_item.json | 7 +++++-- .../doctype/delivery_note_item/delivery_note_item.json | 9 ++++++--- 3 files changed, 15 insertions(+), 7 deletions(-) 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 ae9ac35729a..2901cf0888a 100644 --- a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json +++ b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json @@ -832,6 +832,7 @@ }, { "default": "0", + "fetch_from": "item_code.grant_commission", "fieldname": "grant_commission", "fieldtype": "Check", "label": "Grant Commission", @@ -841,7 +842,7 @@ "idx": 1, "istable": 1, "links": [], - "modified": "2021-10-05 12:24:54.968907", + "modified": "2022-02-24 14:41:36.392560", "modified_by": "Administrator", "module": "Accounts", "name": "Sales Invoice Item", @@ -849,5 +850,6 @@ "owner": "Administrator", "permissions": [], "sort_field": "modified", - "sort_order": "DESC" + "sort_order": "DESC", + "states": [] } \ No newline at end of file diff --git a/erpnext/selling/doctype/sales_order_item/sales_order_item.json b/erpnext/selling/doctype/sales_order_item/sales_order_item.json index 080d517d131..7e55499533b 100644 --- a/erpnext/selling/doctype/sales_order_item/sales_order_item.json +++ b/erpnext/selling/doctype/sales_order_item/sales_order_item.json @@ -83,8 +83,8 @@ "planned_qty", "column_break_69", "work_order_qty", - "produced_qty", "delivered_qty", + "produced_qty", "returned_qty", "shopping_cart_section", "additional_notes", @@ -701,8 +701,10 @@ "width": "50px" }, { + "description": "For Production", "fieldname": "produced_qty", "fieldtype": "Float", + "hidden": 1, "label": "Produced Quantity", "oldfieldname": "produced_qty", "oldfieldtype": "Currency", @@ -791,6 +793,7 @@ }, { "default": "0", + "fetch_from": "item_code.grant_commission", "fieldname": "grant_commission", "fieldtype": "Check", "label": "Grant Commission", @@ -800,7 +803,7 @@ "idx": 1, "istable": 1, "links": [], - "modified": "2022-02-21 13:55:08.883104", + "modified": "2022-02-24 14:41:57.325799", "modified_by": "Administrator", "module": "Selling", "name": "Sales Order Item", diff --git a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json index 51c88bed61d..f1f5d96e628 100644 --- a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json +++ b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json @@ -757,6 +757,7 @@ }, { "default": "0", + "fetch_from": "item_code.grant_commission", "fieldname": "grant_commission", "fieldtype": "Check", "label": "Grant Commission", @@ -767,12 +768,14 @@ "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2021-10-06 12:12:44.018872", + "modified": "2022-02-24 14:42:20.211085", "modified_by": "Administrator", "module": "Stock", "name": "Delivery Note Item", + "naming_rule": "Random", "owner": "Administrator", "permissions": [], "sort_field": "modified", - "sort_order": "DESC" -} + "sort_order": "DESC", + "states": [] +} \ No newline at end of file From 1e139cf9a115228b993c83be29415b1f6971b33e Mon Sep 17 00:00:00 2001 From: Saqib Ansari Date: Thu, 24 Feb 2022 15:12:12 +0530 Subject: [PATCH 25/75] chore: remove unintentional search index --- .../buying/doctype/purchase_order_item/purchase_order_item.json | 1 - 1 file changed, 1 deletion(-) diff --git a/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json b/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json index c26d592e3ee..2c9fc36794e 100644 --- a/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json +++ b/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json @@ -845,7 +845,6 @@ "label": "Sales Order Packed Item", "no_copy": 1, "print_hide": 1, - "search_index": 1 } ], "idx": 1, From 2f1709dfef55ed17db3e2ae885aef5588dd7a31a Mon Sep 17 00:00:00 2001 From: Saqib Ansari Date: Thu, 24 Feb 2022 15:12:35 +0530 Subject: [PATCH 26/75] chore: remove unintentional search index --- .../buying/doctype/purchase_order_item/purchase_order_item.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json b/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json index 2c9fc36794e..a18c527644e 100644 --- a/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json +++ b/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json @@ -844,7 +844,7 @@ "fieldtype": "Data", "label": "Sales Order Packed Item", "no_copy": 1, - "print_hide": 1, + "print_hide": 1 } ], "idx": 1, From 6d72aa377f98f07f28312074b453a97e482998e8 Mon Sep 17 00:00:00 2001 From: marination Date: Thu, 24 Feb 2022 15:20:18 +0530 Subject: [PATCH 27/75] feat: Combine Sub-assembly items in Production Plan - Combine subassembly rows if same Item, Warehouse, Inhouse/Outhouse Manu.g, BOM No. --- erpnext/manufacturing/doctype/bom/bom.py | 2 +- .../production_plan/production_plan.js | 9 +++- .../production_plan/production_plan.json | 11 ++++- .../production_plan/production_plan.py | 49 ++++++++++++++++--- 4 files changed, 61 insertions(+), 10 deletions(-) diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py index d640f3fda7e..37d2b9ff978 100644 --- a/erpnext/manufacturing/doctype/bom/bom.py +++ b/erpnext/manufacturing/doctype/bom/bom.py @@ -918,7 +918,7 @@ def validate_bom_no(item, bom_no): frappe.throw(_("BOM {0} does not belong to Item {1}").format(bom_no, item)) @frappe.whitelist() -def get_children(doctype, parent=None, is_root=False, **filters): +def get_children(parent=None, is_root=False, **filters): if not parent or parent=="BOM": frappe.msgprint(_('Please select a BOM')) return diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.js b/erpnext/manufacturing/doctype/production_plan/production_plan.js index 0babf875e75..c78ff51a7cd 100644 --- a/erpnext/manufacturing/doctype/production_plan/production_plan.js +++ b/erpnext/manufacturing/doctype/production_plan/production_plan.js @@ -232,7 +232,7 @@ frappe.ui.form.on('Production Plan', { }); }, combine_items: function (frm) { - frm.clear_table('prod_plan_references'); + frm.clear_table("prod_plan_references"); frappe.call({ method: "get_items", @@ -247,6 +247,13 @@ frappe.ui.form.on('Production Plan', { }); }, + combine_sub_items: (frm) => { + if (frm.doc.sub_assembly_items.length > 0) { + frm.clear_table("sub_assembly_items"); + frm.trigger("get_sub_assembly_items"); + } + }, + get_sub_assembly_items: function(frm) { frm.dirty(); diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.json b/erpnext/manufacturing/doctype/production_plan/production_plan.json index 56cf2b4f08a..3bfb764ba50 100644 --- a/erpnext/manufacturing/doctype/production_plan/production_plan.json +++ b/erpnext/manufacturing/doctype/production_plan/production_plan.json @@ -36,6 +36,7 @@ "prod_plan_references", "section_break_24", "get_sub_assembly_items", + "combine_sub_items", "sub_assembly_items", "material_request_planning", "include_non_stock_items", @@ -340,7 +341,6 @@ { "fieldname": "prod_plan_references", "fieldtype": "Table", - "hidden": 1, "label": "Production Plan Item Reference", "options": "Production Plan Item Reference" }, @@ -370,16 +370,23 @@ "fieldname": "to_delivery_date", "fieldtype": "Date", "label": "To Delivery Date" + }, + { + "default": "0", + "fieldname": "combine_sub_items", + "fieldtype": "Check", + "label": "Consolidate Sub Assembly Items" } ], "icon": "fa fa-calendar", "index_web_pages_for_search": 1, "is_submittable": 1, "links": [], - "modified": "2021-09-06 18:35:59.642232", + "modified": "2022-02-23 17:16:10.629378", "modified_by": "Administrator", "module": "Manufacturing", "name": "Production Plan", + "naming_rule": "By \"Naming Series\" field", "owner": "Administrator", "permissions": [ { diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.py b/erpnext/manufacturing/doctype/production_plan/production_plan.py index 80003dab786..48cd753d751 100644 --- a/erpnext/manufacturing/doctype/production_plan/production_plan.py +++ b/erpnext/manufacturing/doctype/production_plan/production_plan.py @@ -21,7 +21,8 @@ from frappe.utils import ( ) from frappe.utils.csvutils import build_csv_response -from erpnext.manufacturing.doctype.bom.bom import get_children, validate_bom_no +from erpnext.manufacturing.doctype.bom.bom import get_children as get_bom_children +from erpnext.manufacturing.doctype.bom.bom import validate_bom_no from erpnext.manufacturing.doctype.work_order.work_order import get_item_details from erpnext.setup.doctype.item_group.item_group import get_item_group_defaults @@ -570,17 +571,28 @@ class ProductionPlan(Document): @frappe.whitelist() def get_sub_assembly_items(self, manufacturing_type=None): + "Fetch sub assembly items and optionally combine them." self.sub_assembly_items = [] + sub_assembly_items_store = [] # temporary store to process all subassembly items + for row in self.po_items: bom_data = [] get_sub_assembly_items(row.bom_no, bom_data, row.planned_qty) self.set_sub_assembly_items_based_on_level(row, bom_data, manufacturing_type) + sub_assembly_items_store.extend(bom_data) - self.sub_assembly_items.sort(key= lambda d: d.bom_level, reverse=True) - for idx, row in enumerate(self.sub_assembly_items, start=1): - row.idx = idx + if self.combine_sub_items: + # Combine subassembly items + sub_assembly_items_store = self.combine_subassembly_items(sub_assembly_items_store) + + sub_assembly_items_store.sort(key= lambda d: d.bom_level, reverse=True) # sort by bom level + + for idx, row in enumerate(sub_assembly_items_store): + row.idx = idx + 1 + self.append("sub_assembly_items", row) def set_sub_assembly_items_based_on_level(self, row, bom_data, manufacturing_type=None): + "Modify bom_data, set additional details." for data in bom_data: data.qty = data.stock_qty data.production_plan_item = row.name @@ -589,7 +601,32 @@ class ProductionPlan(Document): data.type_of_manufacturing = manufacturing_type or ("Subcontract" if data.is_sub_contracted_item else "In House") - self.append("sub_assembly_items", data) + def combine_subassembly_items(self, sub_assembly_items_store): + "Aggregate if same: Item, Warehouse, Inhouse/Outhouse Manu.g, BOM No." + key_wise_data = {} + for row in sub_assembly_items_store: + key = ( + row.get("production_item"), row.get("fg_warehouse"), + row.get("bom_no"), row.get("type_of_manufacturing") + ) + if key not in key_wise_data: + # intialise (item, wh, bom no, man.g type) wise dict + key_wise_data[key] = row + continue + + existing_row = key_wise_data[key] + if existing_row: + # if row with same (item, wh, bom no, man.g type) key, merge + existing_row.qty += flt(row.qty) + existing_row.stock_qty += flt(row.stock_qty) + existing_row.bom_level = max(existing_row.bom_level, row.bom_level) + continue + else: + # add row with key + key_wise_data[key] = row + + sub_assembly_items_store = [key_wise_data[key] for key in key_wise_data] # unpack into single level list + return sub_assembly_items_store def all_items_completed(self): all_items_produced = all(flt(d.planned_qty) - flt(d.produced_qty) < 0.000001 @@ -1031,7 +1068,7 @@ def get_item_data(item_code): } def get_sub_assembly_items(bom_no, bom_data, to_produce_qty, indent=0): - data = get_children('BOM', parent = bom_no) + data = get_bom_children(parent=bom_no) for d in data: if d.expandable: parent_item_code = frappe.get_cached_value("BOM", bom_no, "item") From 761e528ba39d5acdbd0bb7dd8cec48705d80cfc3 Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Thu, 24 Feb 2022 17:57:39 +0530 Subject: [PATCH 28/75] fix: deprecation warning --- erpnext/patches/v13_0/non_profit_deprecation_warning.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/patches/v13_0/non_profit_deprecation_warning.py b/erpnext/patches/v13_0/non_profit_deprecation_warning.py index c170de5c1cc..5b54b25a5bc 100644 --- a/erpnext/patches/v13_0/non_profit_deprecation_warning.py +++ b/erpnext/patches/v13_0/non_profit_deprecation_warning.py @@ -5,6 +5,6 @@ def execute(): click.secho( "Non Profit Domain is moved to a separate app and will be removed from ERPNext in version-14.\n" - "When upgrading to ERPNext version-14, please install the app to continue using the Agriculture domain: https://github.com/frappe/non_profit", + "When upgrading to ERPNext version-14, please install the app to continue using the Non Profit domain: https://github.com/frappe/non_profit", fg="yellow", ) From 04b9091821fbd64b1417883087f6a25bcab5a101 Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Thu, 24 Feb 2022 18:10:29 +0530 Subject: [PATCH 29/75] fix: web form deletion --- erpnext/patches/v14_0/delete_non_profit_doctypes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/patches/v14_0/delete_non_profit_doctypes.py b/erpnext/patches/v14_0/delete_non_profit_doctypes.py index d53aecca921..565b10cbb81 100644 --- a/erpnext/patches/v14_0/delete_non_profit_doctypes.py +++ b/erpnext/patches/v14_0/delete_non_profit_doctypes.py @@ -32,7 +32,7 @@ def execute(): forms = ['grant-application', 'certification-application', 'certification-application-usd'] for form in forms: - frappe.delete_doc("Web Form", form, ignore_missing=True) + frappe.delete_doc("Web Form", form, ignore_missing=True, force=True) custom_records = [ {"doctype": "Party Type", "name": "Member"}, From 69c34cd7ae128dde56cde10c53b479331c33d56f Mon Sep 17 00:00:00 2001 From: Saqib Ansari Date: Fri, 25 Feb 2022 14:36:29 +0530 Subject: [PATCH 30/75] fix(pos): mode of payment disappears after save --- erpnext/accounts/doctype/pos_invoice/pos_invoice.py | 1 - 1 file changed, 1 deletion(-) diff --git a/erpnext/accounts/doctype/pos_invoice/pos_invoice.py b/erpnext/accounts/doctype/pos_invoice/pos_invoice.py index 5229d87017b..9b3b3aa4149 100644 --- a/erpnext/accounts/doctype/pos_invoice/pos_invoice.py +++ b/erpnext/accounts/doctype/pos_invoice/pos_invoice.py @@ -439,7 +439,6 @@ class POSInvoice(SalesInvoice): self.paid_amount = 0 def set_account_for_mode_of_payment(self): - self.payments = [d for d in self.payments if d.amount or d.base_amount or d.default] for pay in self.payments: if not pay.account: pay.account = get_bank_cash_account(pay.mode_of_payment, self.company).get("account") From 81514516f3c7106a5b211796bb74ddad0a6add20 Mon Sep 17 00:00:00 2001 From: Saqib Ansari Date: Fri, 25 Feb 2022 15:18:06 +0530 Subject: [PATCH 31/75] fix(pos): coupon code is applied even if ignore pricing rule is check --- erpnext/public/js/controllers/transaction.js | 18 +++++++------ .../selling/page/point_of_sale/pos_payment.js | 25 +++++++++++-------- 2 files changed, 25 insertions(+), 18 deletions(-) diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js index ae8c0c8c6d3..00373a65138 100644 --- a/erpnext/public/js/controllers/transaction.js +++ b/erpnext/public/js/controllers/transaction.js @@ -2285,13 +2285,17 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe } coupon_code() { - var me = this; - frappe.run_serially([ - () => this.frm.doc.ignore_pricing_rule=1, - () => me.ignore_pricing_rule(), - () => this.frm.doc.ignore_pricing_rule=0, - () => me.apply_pricing_rule() - ]); + if (this.frm.doc.coupon_code || this.frm._last_coupon_code) { + // reset pricing rules if coupon code is set or is unset + const _ignore_pricing_rule = this.frm.doc.ignore_pricing_rule; + return frappe.run_serially([ + () => this.frm.doc.ignore_pricing_rule=1, + () => this.frm.trigger('ignore_pricing_rule'), + () => this.frm.doc.ignore_pricing_rule=_ignore_pricing_rule, + () => this.frm.trigger('apply_pricing_rule'), + () => this.frm._last_coupon_code = this.frm.doc.coupon_code + ]); + } } }; diff --git a/erpnext/selling/page/point_of_sale/pos_payment.js b/erpnext/selling/page/point_of_sale/pos_payment.js index 4d75e6ef1bf..1e9f6d7d920 100644 --- a/erpnext/selling/page/point_of_sale/pos_payment.js +++ b/erpnext/selling/page/point_of_sale/pos_payment.js @@ -170,17 +170,20 @@ erpnext.PointOfSale.Payment = class { }); frappe.ui.form.on('POS Invoice', 'coupon_code', (frm) => { - if (!frm.doc.ignore_pricing_rule) { - if (frm.doc.coupon_code) { - frappe.run_serially([ - () => frm.doc.ignore_pricing_rule=1, - () => frm.trigger('ignore_pricing_rule'), - () => frm.doc.ignore_pricing_rule=0, - () => frm.trigger('apply_pricing_rule'), - () => frm.save(), - () => this.update_totals_section(frm.doc) - ]); - } + if (!frm.doc.ignore_pricing_rule && frm.doc.coupon_code) { + frappe.run_serially([ + () => frm.doc.ignore_pricing_rule=1, + () => frm.trigger('ignore_pricing_rule'), + () => frm.doc.ignore_pricing_rule=0, + () => frm.trigger('apply_pricing_rule'), + () => frm.save(), + () => this.update_totals_section(frm.doc) + ]); + } else if (frm.doc.ignore_pricing_rule && frm.doc.coupon_code) { + frappe.show_alert({ + message: __("Ignore Pricing Rule is enabled. Cannot apply coupon code."), + indicator: "orange" + }); } }); From fe2ced7bee1713067912787b3e238269adf451ac Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Fri, 25 Feb 2022 16:57:59 +0530 Subject: [PATCH 32/75] fix: Regional print format addition --- erpnext/regional/india/setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/regional/india/setup.py b/erpnext/regional/india/setup.py index e8356909697..2df52a204b1 100644 --- a/erpnext/regional/india/setup.py +++ b/erpnext/regional/india/setup.py @@ -111,7 +111,7 @@ def add_permissions(): def add_print_formats(): frappe.reload_doc("regional", "print_format", "gst_tax_invoice") - frappe.reload_doc("accounts", "print_format", "gst_pos_invoice") + frappe.reload_doc("selling", "print_format", "gst_pos_invoice") frappe.reload_doc("accounts", "print_format", "GST E-Invoice") frappe.db.set_value("Print Format", "GST POS Invoice", "disabled", 0) From 36c76c40350cbc030cc2b27a84c1bfebbcad67c3 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Fri, 25 Feb 2022 17:15:57 +0530 Subject: [PATCH 33/75] fix: Failing setup wizard test --- erpnext/hr/doctype/department/department.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/hr/doctype/department/department.py b/erpnext/hr/doctype/department/department.py index ed0bfcf0d5a..ecc025a6e39 100644 --- a/erpnext/hr/doctype/department/department.py +++ b/erpnext/hr/doctype/department/department.py @@ -32,7 +32,7 @@ class Department(NestedSet): return new def on_update(self): - if not frappe.local.flags.ignore_update_nsm: + if not frappe.local.flags.ignore_update_nsm or frappe.flags.in_setup_wizard: super(Department, self).on_update() def on_trash(self): From 3e573e9838ef82a5e1b89c3d1dcbd6ce67c361b9 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Fri, 25 Feb 2022 17:18:53 +0530 Subject: [PATCH 34/75] fix: Condition --- erpnext/hr/doctype/department/department.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/hr/doctype/department/department.py b/erpnext/hr/doctype/department/department.py index ecc025a6e39..71300c40b0a 100644 --- a/erpnext/hr/doctype/department/department.py +++ b/erpnext/hr/doctype/department/department.py @@ -32,7 +32,7 @@ class Department(NestedSet): return new def on_update(self): - if not frappe.local.flags.ignore_update_nsm or frappe.flags.in_setup_wizard: + if not (frappe.local.flags.ignore_update_nsm or frappe.flags.in_setup_wizard): super(Department, self).on_update() def on_trash(self): From 4f463943990057e8ef43eac07e02dc75b9ff8580 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Fri, 25 Feb 2022 21:18:22 +0530 Subject: [PATCH 35/75] fix: Add parent to department --- erpnext/hr/doctype/department/test_records.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/hr/doctype/department/test_records.json b/erpnext/hr/doctype/department/test_records.json index 654925ef93f..e3421f28b8d 100644 --- a/erpnext/hr/doctype/department/test_records.json +++ b/erpnext/hr/doctype/department/test_records.json @@ -1,4 +1,4 @@ [ - {"doctype":"Department", "department_name":"_Test Department", "company": "_Test Company"}, - {"doctype":"Department", "department_name":"_Test Department 1", "company": "_Test Company"} + {"doctype":"Department", "department_name":"_Test Department", "company": "_Test Company", "parent_department": "All Departments"}, + {"doctype":"Department", "department_name":"_Test Department 1", "company": "_Test Company", "parent_department": "All Departments"} ] \ No newline at end of file From 71d33081aaf24db12906ec3069270a9df018fa2b Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Fri, 25 Feb 2022 23:01:32 +0530 Subject: [PATCH 36/75] fix: org chart connectors not rendered when Employee Naming is set to Full Name (#29997) --- .../js/hierarchy_chart/hierarchy_chart_desktop.js | 14 ++++++++------ .../js/hierarchy_chart/hierarchy_chart_mobile.js | 9 +++++---- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js b/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js index 831626aa915..a585aa614fb 100644 --- a/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js +++ b/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js @@ -304,12 +304,13 @@ erpnext.HierarchyChart = class { } get_child_nodes(node_id) { + let me = this; return new Promise(resolve => { frappe.call({ - method: this.method, + method: me.method, args: { parent: node_id, - company: this.company + company: me.company } }).then(r => resolve(r.message)); }); @@ -350,12 +351,13 @@ erpnext.HierarchyChart = class { } get_all_nodes() { + let me = this; return new Promise(resolve => { frappe.call({ method: 'erpnext.utilities.hierarchy_chart.get_all_nodes', args: { - method: this.method, - company: this.company + method: me.method, + company: me.company }, callback: (r) => { resolve(r.message); @@ -427,8 +429,8 @@ erpnext.HierarchyChart = class { add_connector(parent_id, child_id) { // using pure javascript for better performance - const parent_node = document.querySelector(`#${parent_id}`); - const child_node = document.querySelector(`#${child_id}`); + const parent_node = document.getElementById(`${parent_id}`); + const child_node = document.getElementById(`${child_id}`); let path = document.createElementNS('http://www.w3.org/2000/svg', 'path'); diff --git a/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js b/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js index 0a8ba78f643..52236e7df96 100644 --- a/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js +++ b/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js @@ -235,7 +235,7 @@ erpnext.HierarchyChartMobile = class { let me = this; return new Promise(resolve => { frappe.call({ - method: this.method, + method: me.method, args: { parent: node_id, company: me.company, @@ -286,8 +286,8 @@ erpnext.HierarchyChartMobile = class { } add_connector(parent_id, child_id) { - const parent_node = document.querySelector(`#${parent_id}`); - const child_node = document.querySelector(`#${child_id}`); + const parent_node = document.getElementById(`${parent_id}`); + const child_node = document.getElementById(`${child_id}`); const path = document.createElementNS('http://www.w3.org/2000/svg', 'path'); @@ -518,7 +518,8 @@ erpnext.HierarchyChartMobile = class { level.nextAll('li').remove(); let node_object = this.nodes[node.id]; - let current_node = level.find(`#${node.id}`).detach(); + let current_node = level.find(`[id="${node.id}"]`).detach(); + current_node.removeClass('active-child active-path'); node_object.expanded = 0; From 1e7df5d0c2b4a95787adce9a69cfb082c9ad084e Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Sat, 26 Feb 2022 11:07:44 +0530 Subject: [PATCH 37/75] fix(minor): student attendance tool query fix --- .../student_attendance_tool.js | 28 +++++++++++++------ .../student_attendance_tool.py | 18 ++++++------ .../public/js/education/student_button.html | 17 ----------- erpnext/public/js/erpnext.bundle.js | 1 - 4 files changed, 28 insertions(+), 36 deletions(-) delete mode 100644 erpnext/public/js/education/student_button.html diff --git a/erpnext/education/doctype/student_attendance_tool/student_attendance_tool.js b/erpnext/education/doctype/student_attendance_tool/student_attendance_tool.js index 68e7780039b..d8a03049419 100644 --- a/erpnext/education/doctype/student_attendance_tool/student_attendance_tool.js +++ b/erpnext/education/doctype/student_attendance_tool/student_attendance_tool.js @@ -163,16 +163,26 @@ education.StudentsEditor = class StudentsEditor { ); }); - var htmls = students.map(function(student) { - return frappe.render_template("student_button", { - student: student.student, - student_name: student.student_name, - group_roll_number: student.group_roll_number, - status: student.status - }) - }); + // make html grid of students + let student_html = ''; + for (let student of students) { + student_html += `
+
+ +
+
`; + } - $(htmls.join("")).appendTo(me.wrapper); + $(student_html).appendTo(me.wrapper); } show_empty_state() { diff --git a/erpnext/education/doctype/student_attendance_tool/student_attendance_tool.py b/erpnext/education/doctype/student_attendance_tool/student_attendance_tool.py index 7deb6b18da5..92bb20ca52b 100644 --- a/erpnext/education/doctype/student_attendance_tool/student_attendance_tool.py +++ b/erpnext/education/doctype/student_attendance_tool/student_attendance_tool.py @@ -24,24 +24,24 @@ def get_student_attendance_records(based_on, date=None, student_group=None, cour student_list = frappe.get_all("Student Group Student", fields=["student", "student_name", "group_roll_number"], filters={"parent": student_group, "active": 1}, order_by= "group_roll_number") - table = frappe.qb.DocType("Student Attendance") + StudentAttendance = frappe.qb.DocType("Student Attendance") if course_schedule: student_attendance_list = ( - frappe.qb.from_(table) - .select(table.student, table.status) + frappe.qb.from_(StudentAttendance) + .select(StudentAttendance.student, StudentAttendance.status) .where( - (table.course_schedule == course_schedule) + (StudentAttendance.course_schedule == course_schedule) ) ).run(as_dict=True) else: student_attendance_list = ( - frappe.qb.from_(table) - .select(table.student, table.status) + frappe.qb.from_(StudentAttendance) + .select(StudentAttendance.student, StudentAttendance.status) .where( - (table.student_group == student_group) - & (table.date == date) - & (table.course_schedule == "") | (table.course_schedule.isnull()) + (StudentAttendance.student_group == student_group) + & (StudentAttendance.date == date) + & ((StudentAttendance.course_schedule == "") | (StudentAttendance.course_schedule.isnull())) ) ).run(as_dict=True) diff --git a/erpnext/public/js/education/student_button.html b/erpnext/public/js/education/student_button.html deleted file mode 100644 index b64c73a43c7..00000000000 --- a/erpnext/public/js/education/student_button.html +++ /dev/null @@ -1,17 +0,0 @@ -
-
- -
-
diff --git a/erpnext/public/js/erpnext.bundle.js b/erpnext/public/js/erpnext.bundle.js index b3a68b38629..8409e78860b 100644 --- a/erpnext/public/js/erpnext.bundle.js +++ b/erpnext/public/js/erpnext.bundle.js @@ -16,7 +16,6 @@ import "./templates/item_quick_entry.html"; import "./utils/item_quick_entry"; import "./utils/customer_quick_entry"; import "./utils/supplier_quick_entry"; -import "./education/student_button.html"; import "./education/assessment_result_tool.html"; import "./call_popup/call_popup"; import "./utils/dimension_tree_filter"; From 77ffcd3aed9b6fb99bc6f508897d3ebe6880de15 Mon Sep 17 00:00:00 2001 From: Sagar Sharma Date: Sat, 26 Feb 2022 11:25:02 +0530 Subject: [PATCH 38/75] fix(ux): make "allow zero valuation rate" readonly if "s_warehouse" is set (#29681) * chore: make allow zero valuation rate readonly if s_warehouse is set * fix: setting the checkbox to zero whenever the source warehouse is set * fix: remove allow_on_submit and refresh trigger Co-authored-by: Ankush Menat --- erpnext/stock/doctype/stock_entry/stock_entry.js | 6 ++++++ .../stock_entry_detail/stock_entry_detail.json | 12 +++++++----- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.js b/erpnext/stock/doctype/stock_entry/stock_entry.js index 5c9da3a2052..324ca7ac599 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.js +++ b/erpnext/stock/doctype/stock_entry/stock_entry.js @@ -629,6 +629,12 @@ frappe.ui.form.on('Stock Entry Detail', { frm.events.set_serial_no(frm, cdt, cdn, () => { frm.events.get_warehouse_details(frm, cdt, cdn); }); + + // set allow_zero_valuation_rate to 0 if s_warehouse is selected. + let item = frappe.get_doc(cdt, cdn); + if (item.s_warehouse) { + item.allow_zero_valuation_rate = 0; + } }, t_warehouse: function(frm, cdt, cdn) { diff --git a/erpnext/stock/doctype/stock_entry_detail/stock_entry_detail.json b/erpnext/stock/doctype/stock_entry_detail/stock_entry_detail.json index df65706c39d..83aed904ddd 100644 --- a/erpnext/stock/doctype/stock_entry_detail/stock_entry_detail.json +++ b/erpnext/stock/doctype/stock_entry_detail/stock_entry_detail.json @@ -1,7 +1,7 @@ { "actions": [], "autoname": "hash", - "creation": "2013-03-29 18:22:12", + "creation": "2022-02-05 00:17:49.860824", "doctype": "DocType", "document_type": "Other", "editable_grid": 1, @@ -340,13 +340,13 @@ "label": "More Information" }, { - "allow_on_submit": 1, "default": "0", "fieldname": "allow_zero_valuation_rate", "fieldtype": "Check", "label": "Allow Zero Valuation Rate", "no_copy": 1, - "print_hide": 1 + "print_hide": 1, + "read_only_depends_on": "eval:doc.s_warehouse" }, { "allow_on_submit": 1, @@ -556,12 +556,14 @@ "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2021-06-22 16:47:11.268975", + "modified": "2022-02-26 00:51:24.963653", "modified_by": "Administrator", "module": "Stock", "name": "Stock Entry Detail", + "naming_rule": "Random", "owner": "Administrator", "permissions": [], "sort_field": "modified", - "sort_order": "ASC" + "sort_order": "ASC", + "states": [] } \ No newline at end of file From 2dabda03af4407d39c58c0074656048a0860ce8d Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Sat, 26 Feb 2022 11:32:54 +0530 Subject: [PATCH 39/75] fix(minor): student_attendance_tool.js fix fetching UX --- .../student_attendance_tool.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/erpnext/education/doctype/student_attendance_tool/student_attendance_tool.js b/erpnext/education/doctype/student_attendance_tool/student_attendance_tool.js index d8a03049419..45265851758 100644 --- a/erpnext/education/doctype/student_attendance_tool/student_attendance_tool.js +++ b/erpnext/education/doctype/student_attendance_tool/student_attendance_tool.js @@ -3,6 +3,10 @@ frappe.provide("education"); frappe.ui.form.on('Student Attendance Tool', { + setup: (frm) => { + frm.students_area = $('
') + .appendTo(frm.fields_dict.students_html.wrapper); + }, onload: function(frm) { frm.set_query("student_group", function() { return { @@ -34,6 +38,7 @@ frappe.ui.form.on('Student Attendance Tool', { student_group: function(frm) { if ((frm.doc.student_group && frm.doc.date) || frm.doc.course_schedule) { + frm.students_area.find('.student-attendance-checks').html(`
Fetching...
`); var method = "erpnext.education.doctype.student_attendance_tool.student_attendance_tool.get_student_attendance_records"; frappe.call({ @@ -62,10 +67,6 @@ frappe.ui.form.on('Student Attendance Tool', { }, get_students: function(frm, students) { - if (!frm.students_area) { - frm.students_area = $('
') - .appendTo(frm.fields_dict.students_html.wrapper); - } students = students || []; frm.students_editor = new education.StudentsEditor(frm, frm.students_area, students); } @@ -182,7 +183,7 @@ education.StudentsEditor = class StudentsEditor {
`; } - $(student_html).appendTo(me.wrapper); + $(`
${student_html}
`).appendTo(me.wrapper); } show_empty_state() { From 96e87fe3c9bb339b6e8046834b1fab6493113096 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Sat, 26 Feb 2022 12:54:13 +0530 Subject: [PATCH 40/75] fix: validate Work Order qty against Production Plan (#29721) (#30003) * fix: validate Work Order qty against Production Plan * chore: err msg when max_qty is 0 * test: add test for overproduction * fix: CI (cherry picked from commit 067ede76ea0851a29e270e150f482368e0afa194) Co-authored-by: Sagar Sharma --- .../production_plan/test_production_plan.py | 20 +++++++++++-------- .../doctype/work_order/work_order.py | 15 ++++++++++++++ 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/erpnext/manufacturing/doctype/production_plan/test_production_plan.py b/erpnext/manufacturing/doctype/production_plan/test_production_plan.py index d88e10a564c..2359815813d 100644 --- a/erpnext/manufacturing/doctype/production_plan/test_production_plan.py +++ b/erpnext/manufacturing/doctype/production_plan/test_production_plan.py @@ -9,6 +9,7 @@ from erpnext.manufacturing.doctype.production_plan.production_plan import ( get_sales_orders, get_warehouse_list, ) +from erpnext.manufacturing.doctype.work_order.work_order import OverProductionError from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order from erpnext.stock.doctype.item.test_item import create_item from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry @@ -466,26 +467,29 @@ class TestProductionPlan(ERPNextTestCase): bom = make_bom(item=item, raw_materials=raw_materials) # Create Production Plan - pln = create_production_plan(item_code=bom.item, planned_qty=10) + pln = create_production_plan(item_code=bom.item, planned_qty=5) # All the created Work Orders wo_list = [] - # Create and Submit 1st Work Order for 5 qty - create_work_order(item, pln, 5) + # Create and Submit 1st Work Order for 3 qty + create_work_order(item, pln, 3) + pln.reload() + self.assertEqual(pln.po_items[0].ordered_qty, 3) + + # Create and Submit 2nd Work Order for 2 qty + create_work_order(item, pln, 2) pln.reload() self.assertEqual(pln.po_items[0].ordered_qty, 5) - # Create and Submit 2nd Work Order for 3 qty - create_work_order(item, pln, 3) - pln.reload() - self.assertEqual(pln.po_items[0].ordered_qty, 8) + # Overproduction + self.assertRaises(OverProductionError, create_work_order, item=item, pln=pln, qty=2) # Cancel 1st Work Order wo1 = frappe.get_doc("Work Order", wo_list[0]) wo1.cancel() pln.reload() - self.assertEqual(pln.po_items[0].ordered_qty, 3) + self.assertEqual(pln.po_items[0].ordered_qty, 2) # Cancel 2nd Work Order wo2 = frappe.get_doc("Work Order", wo_list[1]) diff --git a/erpnext/manufacturing/doctype/work_order/work_order.py b/erpnext/manufacturing/doctype/work_order/work_order.py index ed6a0299efb..e1120c723d5 100644 --- a/erpnext/manufacturing/doctype/work_order/work_order.py +++ b/erpnext/manufacturing/doctype/work_order/work_order.py @@ -636,6 +636,21 @@ class WorkOrder(Document): if not self.qty > 0: frappe.throw(_("Quantity to Manufacture must be greater than 0.")) + if self.production_plan and self.production_plan_item: + qty_dict = frappe.db.get_value("Production Plan Item", self.production_plan_item, ["planned_qty", "ordered_qty"], as_dict=1) + + allowance_qty =flt(frappe.db.get_single_value("Manufacturing Settings", + "overproduction_percentage_for_work_order"))/100 * qty_dict.get("planned_qty", 0) + + max_qty = qty_dict.get("planned_qty", 0) + allowance_qty - qty_dict.get("ordered_qty", 0) + + if max_qty < 1: + frappe.throw(_("Cannot produce more item for {0}") + .format(self.production_item), OverProductionError) + elif self.qty > max_qty: + frappe.throw(_("Cannot produce more than {0} items for {1}") + .format(max_qty, self.production_item), OverProductionError) + def validate_transfer_against(self): if not self.docstatus == 1: # let user configure operations until they're ready to submit From 4e9a9f35a605f4f886cc9cc920ec4ab4262b9709 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Mon, 28 Feb 2022 12:41:59 +0530 Subject: [PATCH 41/75] test: add correct test case --- .../doctype/sales_invoice/test_sales_invoice.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index 941061f2a22..07591e7b1e0 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -2429,14 +2429,22 @@ class TestSalesInvoice(unittest.TestCase): def test_sales_commission(self): - si = frappe.copy_doc(test_records[0]) + si = frappe.copy_doc(test_records[2]) + + frappe.db.set_value('Item', si.get('items')[0].item_code, 'grant_commission', 1) + frappe.db.set_value('Item', si.get('items')[1].item_code, 'grant_commission', 0) + item = copy.deepcopy(si.get('items')[0]) item.update({ "qty": 1, "rate": 500, - "grant_commission": 1 }) - si.append("items", item) + + item = copy.deepcopy(si.get('items')[1]) + item.update({ + "qty": 1, + "rate": 500, + }) # Test valid values for commission_rate, total_commission in ((0, 0), (10, 50), (100, 500)): From 88a21ca7d2fd2944912bc3cd48c81185478f3cb3 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Wed, 26 Jan 2022 01:01:10 +0530 Subject: [PATCH 42/75] fix: only show child warehouses for transfer --- erpnext/stock/dashboard/item_dashboard.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/erpnext/stock/dashboard/item_dashboard.js b/erpnext/stock/dashboard/item_dashboard.js index 37e9e89a0a9..204d62355cc 100644 --- a/erpnext/stock/dashboard/item_dashboard.js +++ b/erpnext/stock/dashboard/item_dashboard.js @@ -213,7 +213,14 @@ erpnext.stock.move_item = function (item, source, target, actual_qty, rate, call label: __('Target Warehouse'), fieldtype: 'Link', options: 'Warehouse', - reqd: 1 + reqd: 1, + get_query() { + return { + filters: { + is_group: 0 + } + } + } }, { fieldname: 'qty', From 0bed5927779c823455e9cd819cba5281d297e1b3 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Wed, 26 Jan 2022 01:01:33 +0530 Subject: [PATCH 43/75] fix: open stock entry instead of submitting from item dashboard --- erpnext/stock/dashboard/item_dashboard.js | 61 ++++++----------------- 1 file changed, 15 insertions(+), 46 deletions(-) diff --git a/erpnext/stock/dashboard/item_dashboard.js b/erpnext/stock/dashboard/item_dashboard.js index 204d62355cc..1f259bd425a 100644 --- a/erpnext/stock/dashboard/item_dashboard.js +++ b/erpnext/stock/dashboard/item_dashboard.js @@ -259,52 +259,21 @@ erpnext.stock.move_item = function (item, source, target, actual_qty, rate, call dialog.get_field('target').refresh(); } - dialog.set_primary_action(__('Submit'), function () { - var values = dialog.get_values(); - if (!values) { - return; - } - if (source && values.qty > actual_qty) { - frappe.msgprint(__('Quantity must be less than or equal to {0}', [actual_qty])); - return; - } - if (values.source === values.target) { - frappe.msgprint(__('Source and target warehouse must be different')); - } - - frappe.call({ - method: 'erpnext.stock.doctype.stock_entry.stock_entry_utils.make_stock_entry', - args: values, - btn: dialog.get_primary_btn(), - freeze: true, - freeze_message: __('Creating Stock Entry'), - callback: function (r) { - frappe.show_alert(__('Stock Entry {0} created', - ['' + r.message.name + ''])); - dialog.hide(); - callback(r); - }, + dialog.set_primary_action(__('Create Stock Entry'), function () { + frappe.model.with_doctype('Stock Entry', function () { + let doc = frappe.model.get_new_doc('Stock Entry'); + doc.from_warehouse = dialog.get_value('source'); + doc.to_warehouse = dialog.get_value('target'); + doc.stock_entry_type = doc.from_warehouse ? "Material Transfer" : "Material Receipt"; + let row = frappe.model.add_child(doc, 'items'); + row.item_code = dialog.get_value('item_code'); + row.f_warehouse = dialog.get_value('target'); + row.t_warehouse = dialog.get_value('target'); + row.qty = dialog.get_value('qty'); + row.conversion_factor = 1; + row.transfer_qty = dialog.get_value('qty'); + row.basic_rate = dialog.get_value('rate'); + frappe.set_route('Form', doc.doctype, doc.name); }); }); - - $('

' + - __("Add more items or open full form") + '

') - .appendTo(dialog.body) - .find('.link-open') - .on('click', function () { - frappe.model.with_doctype('Stock Entry', function () { - var doc = frappe.model.get_new_doc('Stock Entry'); - doc.from_warehouse = dialog.get_value('source'); - doc.to_warehouse = dialog.get_value('target'); - var row = frappe.model.add_child(doc, 'items'); - row.item_code = dialog.get_value('item_code'); - row.f_warehouse = dialog.get_value('target'); - row.t_warehouse = dialog.get_value('target'); - row.qty = dialog.get_value('qty'); - row.conversion_factor = 1; - row.transfer_qty = dialog.get_value('qty'); - row.basic_rate = dialog.get_value('rate'); - frappe.set_route('Form', doc.doctype, doc.name); - }); - }); }; From 3cc47d5ba5b0b7a0a677e81bf4d092f85b36e969 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Mon, 28 Feb 2022 13:04:24 +0530 Subject: [PATCH 44/75] fix: correct fieldname for source warehouse --- erpnext/stock/dashboard/item_dashboard.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/stock/dashboard/item_dashboard.js b/erpnext/stock/dashboard/item_dashboard.js index 1f259bd425a..c9d5f61f22b 100644 --- a/erpnext/stock/dashboard/item_dashboard.js +++ b/erpnext/stock/dashboard/item_dashboard.js @@ -267,7 +267,7 @@ erpnext.stock.move_item = function (item, source, target, actual_qty, rate, call doc.stock_entry_type = doc.from_warehouse ? "Material Transfer" : "Material Receipt"; let row = frappe.model.add_child(doc, 'items'); row.item_code = dialog.get_value('item_code'); - row.f_warehouse = dialog.get_value('target'); + row.s_warehouse = dialog.get_value('source'); row.t_warehouse = dialog.get_value('target'); row.qty = dialog.get_value('qty'); row.conversion_factor = 1; From 1d1203d5eca07e40d8ce32248a0d81b0d7130627 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Mon, 28 Feb 2022 12:44:39 +0530 Subject: [PATCH 45/75] fix: dont fetch draft/cancelled BOMs --- .../manufacturing/doctype/production_plan/production_plan.js | 2 +- erpnext/manufacturing/doctype/work_order/work_order.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.js b/erpnext/manufacturing/doctype/production_plan/production_plan.js index 0babf875e75..c33e64674eb 100644 --- a/erpnext/manufacturing/doctype/production_plan/production_plan.js +++ b/erpnext/manufacturing/doctype/production_plan/production_plan.js @@ -49,7 +49,7 @@ frappe.ui.form.on('Production Plan', { if (d.item_code) { return { query: "erpnext.controllers.queries.bom", - filters:{'item': cstr(d.item_code)} + filters:{'item': cstr(d.item_code), 'docstatus': 1} } } else frappe.msgprint(__("Please enter Item first")); } diff --git a/erpnext/manufacturing/doctype/work_order/work_order.py b/erpnext/manufacturing/doctype/work_order/work_order.py index e1120c723d5..374ab86cadc 100644 --- a/erpnext/manufacturing/doctype/work_order/work_order.py +++ b/erpnext/manufacturing/doctype/work_order/work_order.py @@ -854,7 +854,7 @@ def get_item_details(item, project = None, skip_bom_info=False): res = res[0] if skip_bom_info: return res - filters = {"item": item, "is_default": 1} + filters = {"item": item, "is_default": 1, "docstatus": 1} if project: filters = {"item": item, "project": project} From 39d3f20d9b45939e1b7a5564a1c79ad99a304953 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Mon, 28 Feb 2022 14:19:48 +0530 Subject: [PATCH 46/75] fix: removed validation to check zero qty --- erpnext/controllers/subcontracting.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/erpnext/controllers/subcontracting.py b/erpnext/controllers/subcontracting.py index 3addb91aaa0..c52c688b73e 100644 --- a/erpnext/controllers/subcontracting.py +++ b/erpnext/controllers/subcontracting.py @@ -363,8 +363,6 @@ class Subcontracting(): return for row in self.get(self.raw_material_table): - self.__validate_consumed_qty(row) - key = (row.rm_item_code, row.main_item_code, row.purchase_order) if not self.__transferred_items or not self.__transferred_items.get(key): return @@ -372,12 +370,6 @@ class Subcontracting(): self.__validate_batch_no(row, key) self.__validate_serial_no(row, key) - def __validate_consumed_qty(self, row): - if self.backflush_based_on != 'BOM' and flt(row.consumed_qty) == 0.0: - msg = f'Row {row.idx}: the consumed qty cannot be zero for the item {frappe.bold(row.rm_item_code)}' - - frappe.throw(_(msg),title=_('Consumed Items Qty Check')) - def __validate_batch_no(self, row, key): if row.get('batch_no') and row.get('batch_no') not in self.__transferred_items.get(key).get('batch_no'): link = get_link_to_form('Purchase Order', row.purchase_order) From 292fe370dbb1d4c090c78f34bd70ddf95774fe5d Mon Sep 17 00:00:00 2001 From: marination Date: Mon, 28 Feb 2022 16:35:20 +0530 Subject: [PATCH 47/75] test: combine sub assembly items and make Production Plan tests atomic --- .../production_plan/test_production_plan.py | 45 ++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/erpnext/manufacturing/doctype/production_plan/test_production_plan.py b/erpnext/manufacturing/doctype/production_plan/test_production_plan.py index 2359815813d..8e34e1bca3e 100644 --- a/erpnext/manufacturing/doctype/production_plan/test_production_plan.py +++ b/erpnext/manufacturing/doctype/production_plan/test_production_plan.py @@ -20,7 +20,7 @@ from erpnext.tests.utils import ERPNextTestCase class TestProductionPlan(ERPNextTestCase): - def setUp(self): + def setUp(self) -> None: for item in ['Test Production Item 1', 'Subassembly Item 1', 'Raw Material Item 1', 'Raw Material Item 2']: create_item(item, valuation_rate=100) @@ -38,6 +38,9 @@ class TestProductionPlan(ERPNextTestCase): if not frappe.db.get_value('BOM', {'item': item}): make_bom(item = item, raw_materials = raw_materials) + def tearDown(self) -> None: + frappe.db.rollback() + def test_production_plan_mr_creation(self): "Test if MRs are created for unavailable raw materials." pln = create_production_plan(item_code='Test Production Item 1') @@ -258,6 +261,46 @@ class TestProductionPlan(ERPNextTestCase): pln.reload() pln.cancel() + def test_production_plan_combine_subassembly(self): + """ + Test combining Sub assembly items belonging to the same BOM in Prod Plan. + 1) Red-Car -> Wheel (sub assembly) > BOM-WHEEL-001 + 2) Green-Car -> Wheel (sub assembly) > BOM-WHEEL-001 + """ + from erpnext.manufacturing.doctype.bom.test_bom import create_nested_bom + + bom_tree_1 = { + "Red-Car": {"Wheel": {"Rubber": {}}} + } + bom_tree_2 = { + "Green-Car": {"Wheel": {"Rubber": {}}} + } + + parent_bom_1 = create_nested_bom(bom_tree_1, prefix="") + parent_bom_2 = create_nested_bom(bom_tree_2, prefix="") + + # make sure both boms use same subassembly bom + subassembly_bom = parent_bom_1.items[0].bom_no + frappe.db.set_value("BOM Item", parent_bom_2.items[0].name, "bom_no", subassembly_bom) + + plan = create_production_plan(item_code="Red-Car", use_multi_level_bom=1, do_not_save=True) + plan.append("po_items", { # Add Green-Car to Prod Plan + 'use_multi_level_bom': 1, + 'item_code': "Green-Car", + 'bom_no': frappe.db.get_value('Item', "Green-Car", 'default_bom'), + 'planned_qty': 1, + 'planned_start_date': now_datetime() + }) + plan.get_sub_assembly_items() + self.assertTrue(len(plan.sub_assembly_items), 2) + + plan.combine_sub_items = 1 + plan.get_sub_assembly_items() + + self.assertTrue(len(plan.sub_assembly_items), 1) # check if sub-assembly items merged + self.assertEqual(plan.sub_assembly_items[0].qty, 2.0) + self.assertEqual(plan.sub_assembly_items[0].stock_qty, 2.0) + def test_pp_to_mr_customer_provided(self): " Test Material Request from Production Plan for Customer Provided Item." create_item('CUST-0987', is_customer_provided_item = 1, customer = '_Test Customer', is_purchase_item = 0) From b0d1e6db54ea73af5a2b31d32cd5ba360d0dd7b1 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Mon, 28 Feb 2022 16:55:46 +0530 Subject: [PATCH 48/75] test(refactor): use FrappeTestCase --- .../test_opening_invoice_creation_tool.py | 4 +- .../shopping_cart/test_shopping_cart.py | 3 +- .../variant_selector/test_variant_selector.py | 6 +- .../blanket_order/test_blanket_order.py | 4 +- erpnext/manufacturing/doctype/bom/test_bom.py | 4 +- .../bom_update_tool/test_bom_update_tool.py | 4 +- .../doctype/job_card/test_job_card.py | 4 +- .../production_plan/test_production_plan.py | 4 +- .../doctype/routing/test_routing.py | 4 +- .../doctype/work_order/test_work_order.py | 4 +- .../doctype/workstation/test_workstation.py | 4 +- .../selling/doctype/customer/test_customer.py | 5 +- .../test_party_specific_item.py | 6 +- .../doctype/quotation/test_quotation.py | 5 +- .../doctype/sales_order/test_sales_order.py | 4 +- ...st_payment_terms_status_for_sales_order.py | 4 +- ...t_pending_so_items_for_purchase_request.py | 4 +- .../report/sales_analytics/test_analytics.py | 4 +- erpnext/stock/doctype/batch/test_batch.py | 4 +- erpnext/stock/doctype/bin/test_bin.py | 4 +- .../delivery_note/test_delivery_note.py | 4 +- .../delivery_trip/test_delivery_trip.py | 5 +- erpnext/stock/doctype/item/test_item.py | 4 +- .../item_alternative/test_item_alternative.py | 4 +- .../item_attribute/test_item_attribute.py | 5 +- .../doctype/item_price/test_item_price.py | 4 +- .../test_landed_cost_voucher.py | 4 +- .../material_request/test_material_request.py | 4 +- .../doctype/packed_item/test_packed_item.py | 4 +- .../doctype/packing_slip/test_packing_slip.py | 2 +- .../stock/doctype/pick_list/test_pick_list.py | 5 +- .../purchase_receipt/test_purchase_receipt.py | 4 +- .../doctype/putaway_rule/test_putaway_rule.py | 4 +- .../test_quality_inspection.py | 4 +- .../stock/doctype/serial_no/test_serial_no.py | 5 +- .../stock/doctype/shipment/test_shipment.py | 4 +- .../doctype/stock_entry/test_stock_entry.py | 4 +- .../test_stock_ledger_entry.py | 4 +- .../test_stock_reconciliation.py | 4 +- .../stock_settings/test_stock_settings.py | 5 +- .../stock/doctype/warehouse/test_warehouse.py | 4 +- .../report/stock_ageing/test_stock_ageing.py | 6 +- .../stock_analytics/test_stock_analytics.py | 5 +- erpnext/stock/tests/test_valuation.py | 4 +- erpnext/tests/utils.py | 78 ------------------- 45 files changed, 94 insertions(+), 171 deletions(-) diff --git a/erpnext/accounts/doctype/opening_invoice_creation_tool/test_opening_invoice_creation_tool.py b/erpnext/accounts/doctype/opening_invoice_creation_tool/test_opening_invoice_creation_tool.py index 3eaf6a28f37..77d54a605e5 100644 --- a/erpnext/accounts/doctype/opening_invoice_creation_tool/test_opening_invoice_creation_tool.py +++ b/erpnext/accounts/doctype/opening_invoice_creation_tool/test_opening_invoice_creation_tool.py @@ -2,6 +2,7 @@ # See license.txt import frappe +from frappe.tests.utils import FrappeTestCase from erpnext.accounts.doctype.accounting_dimension.test_accounting_dimension import ( create_dimension, @@ -10,11 +11,10 @@ from erpnext.accounts.doctype.accounting_dimension.test_accounting_dimension imp from erpnext.accounts.doctype.opening_invoice_creation_tool.opening_invoice_creation_tool import ( get_temporary_opening_account, ) -from erpnext.tests.utils import ERPNextTestCase test_dependencies = ["Customer", "Supplier", "Accounting Dimension"] -class TestOpeningInvoiceCreationTool(ERPNextTestCase): +class TestOpeningInvoiceCreationTool(FrappeTestCase): @classmethod def setUpClass(self): if not frappe.db.exists("Company", "_Test Opening Invoice Company"): diff --git a/erpnext/e_commerce/shopping_cart/test_shopping_cart.py b/erpnext/e_commerce/shopping_cart/test_shopping_cart.py index 37b3672806d..9c389d0d0b4 100644 --- a/erpnext/e_commerce/shopping_cart/test_shopping_cart.py +++ b/erpnext/e_commerce/shopping_cart/test_shopping_cart.py @@ -5,6 +5,7 @@ import unittest import frappe +from frappe.tests.utils import change_settings from frappe.utils import add_months, nowdate from erpnext.accounts.doctype.tax_rule.tax_rule import ConflictingTaxRule @@ -15,7 +16,7 @@ from erpnext.e_commerce.shopping_cart.cart import ( get_party, update_cart, ) -from erpnext.tests.utils import change_settings, create_test_contact_and_address +from erpnext.tests.utils import create_test_contact_and_address # test_dependencies = ['Payment Terms Template'] diff --git a/erpnext/e_commerce/variant_selector/test_variant_selector.py b/erpnext/e_commerce/variant_selector/test_variant_selector.py index 4d907c62216..ee098e16e7a 100644 --- a/erpnext/e_commerce/variant_selector/test_variant_selector.py +++ b/erpnext/e_commerce/variant_selector/test_variant_selector.py @@ -1,4 +1,5 @@ import frappe +from frappe.tests.utils import FrappeTestCase from erpnext.controllers.item_variant import create_variant from erpnext.e_commerce.doctype.e_commerce_settings.test_e_commerce_settings import ( @@ -7,11 +8,10 @@ from erpnext.e_commerce.doctype.e_commerce_settings.test_e_commerce_settings imp from erpnext.e_commerce.doctype.website_item.website_item import make_website_item from erpnext.e_commerce.variant_selector.utils import get_next_attribute_and_values from erpnext.stock.doctype.item.test_item import make_item -from erpnext.tests.utils import ERPNextTestCase test_dependencies = ["Item"] -class TestVariantSelector(ERPNextTestCase): +class TestVariantSelector(FrappeTestCase): @classmethod def setUpClass(cls): @@ -116,4 +116,4 @@ class TestVariantSelector(ERPNextTestCase): self.assertEqual(next_values["exact_match"][0],"Test-Tshirt-Temp-S-R") self.assertEqual(next_values["exact_match"][0],"Test-Tshirt-Temp-S-R") self.assertEqual(price_info["price_list_rate"], 100.0) - self.assertEqual(price_info["formatted_price_sales_uom"], "₹ 100.00") \ No newline at end of file + self.assertEqual(price_info["formatted_price_sales_uom"], "₹ 100.00") diff --git a/erpnext/manufacturing/doctype/blanket_order/test_blanket_order.py b/erpnext/manufacturing/doctype/blanket_order/test_blanket_order.py index eff2344e85c..d4d337d8412 100644 --- a/erpnext/manufacturing/doctype/blanket_order/test_blanket_order.py +++ b/erpnext/manufacturing/doctype/blanket_order/test_blanket_order.py @@ -1,15 +1,15 @@ # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt import frappe +from frappe.tests.utils import FrappeTestCase from frappe.utils import add_months, today from erpnext import get_company_currency -from erpnext.tests.utils import ERPNextTestCase from .blanket_order import make_order -class TestBlanketOrder(ERPNextTestCase): +class TestBlanketOrder(FrappeTestCase): def setUp(self): frappe.flags.args = frappe._dict() diff --git a/erpnext/manufacturing/doctype/bom/test_bom.py b/erpnext/manufacturing/doctype/bom/test_bom.py index 53437c80127..3cc91b341c6 100644 --- a/erpnext/manufacturing/doctype/bom/test_bom.py +++ b/erpnext/manufacturing/doctype/bom/test_bom.py @@ -7,6 +7,7 @@ from functools import partial import frappe from frappe.test_runner import make_test_records +from frappe.tests.utils import FrappeTestCase from frappe.utils import cstr, flt from erpnext.buying.doctype.purchase_order.test_purchase_order import create_purchase_order @@ -17,11 +18,10 @@ from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import create_stock_reconciliation, ) from erpnext.tests.test_subcontracting import set_backflush_based_on -from erpnext.tests.utils import ERPNextTestCase test_records = frappe.get_test_records('BOM') -class TestBOM(ERPNextTestCase): +class TestBOM(FrappeTestCase): def setUp(self): if not frappe.get_value('Item', '_Test Item'): make_test_records('Item') diff --git a/erpnext/manufacturing/doctype/bom_update_tool/test_bom_update_tool.py b/erpnext/manufacturing/doctype/bom_update_tool/test_bom_update_tool.py index 12576cbf322..b4c625d6108 100644 --- a/erpnext/manufacturing/doctype/bom_update_tool/test_bom_update_tool.py +++ b/erpnext/manufacturing/doctype/bom_update_tool/test_bom_update_tool.py @@ -2,15 +2,15 @@ # License: GNU General Public License v3. See license.txt import frappe +from frappe.tests.utils import FrappeTestCase from erpnext.manufacturing.doctype.bom_update_tool.bom_update_tool import update_cost from erpnext.manufacturing.doctype.production_plan.test_production_plan import make_bom from erpnext.stock.doctype.item.test_item import create_item -from erpnext.tests.utils import ERPNextTestCase test_records = frappe.get_test_records('BOM') -class TestBOMUpdateTool(ERPNextTestCase): +class TestBOMUpdateTool(FrappeTestCase): def test_replace_bom(self): current_bom = "BOM-_Test Item Home Desktop Manufactured-001" diff --git a/erpnext/manufacturing/doctype/job_card/test_job_card.py b/erpnext/manufacturing/doctype/job_card/test_job_card.py index bb5004ba86f..33425d23142 100644 --- a/erpnext/manufacturing/doctype/job_card/test_job_card.py +++ b/erpnext/manufacturing/doctype/job_card/test_job_card.py @@ -2,6 +2,7 @@ # See license.txt import frappe +from frappe.tests.utils import FrappeTestCase from frappe.utils import random_string from erpnext.manufacturing.doctype.job_card.job_card import OperationMismatchError, OverlapError @@ -11,10 +12,9 @@ from erpnext.manufacturing.doctype.job_card.job_card import ( from erpnext.manufacturing.doctype.work_order.test_work_order import make_wo_order_test_record from erpnext.manufacturing.doctype.workstation.test_workstation import make_workstation from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry -from erpnext.tests.utils import ERPNextTestCase -class TestJobCard(ERPNextTestCase): +class TestJobCard(FrappeTestCase): def setUp(self): make_bom_for_jc_tests() diff --git a/erpnext/manufacturing/doctype/production_plan/test_production_plan.py b/erpnext/manufacturing/doctype/production_plan/test_production_plan.py index 2359815813d..b2a41ff5b2a 100644 --- a/erpnext/manufacturing/doctype/production_plan/test_production_plan.py +++ b/erpnext/manufacturing/doctype/production_plan/test_production_plan.py @@ -1,6 +1,7 @@ # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt import frappe +from frappe.tests.utils import FrappeTestCase from frappe.utils import add_to_date, flt, now_datetime, nowdate from erpnext.controllers.item_variant import create_variant @@ -16,10 +17,9 @@ from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import ( create_stock_reconciliation, ) -from erpnext.tests.utils import ERPNextTestCase -class TestProductionPlan(ERPNextTestCase): +class TestProductionPlan(FrappeTestCase): def setUp(self): for item in ['Test Production Item 1', 'Subassembly Item 1', 'Raw Material Item 1', 'Raw Material Item 2']: diff --git a/erpnext/manufacturing/doctype/routing/test_routing.py b/erpnext/manufacturing/doctype/routing/test_routing.py index 8bd60ea4aca..696d9bca144 100644 --- a/erpnext/manufacturing/doctype/routing/test_routing.py +++ b/erpnext/manufacturing/doctype/routing/test_routing.py @@ -2,14 +2,14 @@ # See license.txt import frappe from frappe.test_runner import make_test_records +from frappe.tests.utils import FrappeTestCase from erpnext.manufacturing.doctype.job_card.job_card import OperationSequenceError from erpnext.manufacturing.doctype.work_order.test_work_order import make_wo_order_test_record from erpnext.stock.doctype.item.test_item import make_item -from erpnext.tests.utils import ERPNextTestCase -class TestRouting(ERPNextTestCase): +class TestRouting(FrappeTestCase): @classmethod def setUpClass(cls): cls.item_code = "Test Routing Item - A" diff --git a/erpnext/manufacturing/doctype/work_order/test_work_order.py b/erpnext/manufacturing/doctype/work_order/test_work_order.py index 67c47efb5b5..549ec7b4a66 100644 --- a/erpnext/manufacturing/doctype/work_order/test_work_order.py +++ b/erpnext/manufacturing/doctype/work_order/test_work_order.py @@ -2,6 +2,7 @@ # License: GNU General Public License v3. See license.txt import frappe +from frappe.tests.utils import FrappeTestCase, timeout from frappe.utils import add_days, add_months, cint, flt, now, today from erpnext.manufacturing.doctype.job_card.job_card import JobCardCancelError @@ -21,10 +22,9 @@ from erpnext.stock.doctype.item.test_item import create_item, make_item from erpnext.stock.doctype.stock_entry import test_stock_entry from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse from erpnext.stock.utils import get_bin -from erpnext.tests.utils import ERPNextTestCase, timeout -class TestWorkOrder(ERPNextTestCase): +class TestWorkOrder(FrappeTestCase): def setUp(self): self.warehouse = '_Test Warehouse 2 - _TC' self.item = '_Test Item' diff --git a/erpnext/manufacturing/doctype/workstation/test_workstation.py b/erpnext/manufacturing/doctype/workstation/test_workstation.py index c298c0a8dbb..dd51017bb75 100644 --- a/erpnext/manufacturing/doctype/workstation/test_workstation.py +++ b/erpnext/manufacturing/doctype/workstation/test_workstation.py @@ -2,6 +2,7 @@ # See license.txt import frappe from frappe.test_runner import make_test_records +from frappe.tests.utils import FrappeTestCase from erpnext.manufacturing.doctype.operation.test_operation import make_operation from erpnext.manufacturing.doctype.routing.test_routing import create_routing, setup_bom @@ -10,13 +11,12 @@ from erpnext.manufacturing.doctype.workstation.workstation import ( WorkstationHolidayError, check_if_within_operating_hours, ) -from erpnext.tests.utils import ERPNextTestCase test_dependencies = ["Warehouse"] test_records = frappe.get_test_records('Workstation') make_test_records('Workstation') -class TestWorkstation(ERPNextTestCase): +class TestWorkstation(FrappeTestCase): def test_validate_timings(self): check_if_within_operating_hours("_Test Workstation 1", "Operation 1", "2013-02-02 11:00:00", "2013-02-02 19:00:00") check_if_within_operating_hours("_Test Workstation 1", "Operation 1", "2013-02-02 10:00:00", "2013-02-02 20:00:00") diff --git a/erpnext/selling/doctype/customer/test_customer.py b/erpnext/selling/doctype/customer/test_customer.py index 5301fd0524d..165ee818729 100644 --- a/erpnext/selling/doctype/customer/test_customer.py +++ b/erpnext/selling/doctype/customer/test_customer.py @@ -4,12 +4,13 @@ import frappe from frappe.test_runner import make_test_records +from frappe.tests.utils import FrappeTestCase from frappe.utils import flt from erpnext.accounts.party import get_due_date from erpnext.exceptions import PartyDisabled, PartyFrozen from erpnext.selling.doctype.customer.customer import get_credit_limit, get_customer_outstanding -from erpnext.tests.utils import ERPNextTestCase, create_test_contact_and_address +from erpnext.tests.utils import create_test_contact_and_address test_ignore = ["Price List"] test_dependencies = ['Payment Term', 'Payment Terms Template'] @@ -17,7 +18,7 @@ test_records = frappe.get_test_records('Customer') -class TestCustomer(ERPNextTestCase): +class TestCustomer(FrappeTestCase): def setUp(self): if not frappe.get_value('Item', '_Test Item'): make_test_records('Item') diff --git a/erpnext/selling/doctype/party_specific_item/test_party_specific_item.py b/erpnext/selling/doctype/party_specific_item/test_party_specific_item.py index b951044f332..9b672b4b5d3 100644 --- a/erpnext/selling/doctype/party_specific_item/test_party_specific_item.py +++ b/erpnext/selling/doctype/party_specific_item/test_party_specific_item.py @@ -1,12 +1,10 @@ # Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -import unittest - import frappe +from frappe.tests.utils import FrappeTestCase from erpnext.controllers.queries import item_query -from erpnext.tests.utils import ERPNextTestCase test_dependencies = ['Item', 'Customer', 'Supplier'] @@ -18,7 +16,7 @@ def create_party_specific_item(**args): psi.based_on_value = args.get('based_on_value') psi.insert() -class TestPartySpecificItem(ERPNextTestCase): +class TestPartySpecificItem(FrappeTestCase): def setUp(self): self.customer = frappe.get_last_doc("Customer") self.supplier = frappe.get_last_doc("Supplier") diff --git a/erpnext/selling/doctype/quotation/test_quotation.py b/erpnext/selling/doctype/quotation/test_quotation.py index 4357201d23d..a749d9e1f1f 100644 --- a/erpnext/selling/doctype/quotation/test_quotation.py +++ b/erpnext/selling/doctype/quotation/test_quotation.py @@ -2,14 +2,13 @@ # License: GNU General Public License v3. See license.txt import frappe +from frappe.tests.utils import FrappeTestCase from frappe.utils import add_days, add_months, flt, getdate, nowdate -from erpnext.tests.utils import ERPNextTestCase - test_dependencies = ["Product Bundle"] -class TestQuotation(ERPNextTestCase): +class TestQuotation(FrappeTestCase): def test_make_quotation_without_terms(self): quotation = make_quotation(do_not_save=1) self.assertFalse(quotation.get('payment_schedule')) diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py index 73c5bd299a2..f5a34c0eec3 100644 --- a/erpnext/selling/doctype/sales_order/test_sales_order.py +++ b/erpnext/selling/doctype/sales_order/test_sales_order.py @@ -6,6 +6,7 @@ import json import frappe import frappe.permissions from frappe.core.doctype.user_permission.test_user_permission import create_user +from frappe.tests.utils import FrappeTestCase from frappe.utils import add_days, flt, getdate, nowdate, today from erpnext.controllers.accounts_controller import update_child_qty_rate @@ -27,10 +28,9 @@ from erpnext.selling.doctype.sales_order.sales_order import ( ) from erpnext.stock.doctype.item.test_item import make_item from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry -from erpnext.tests.utils import ERPNextTestCase -class TestSalesOrder(ERPNextTestCase): +class TestSalesOrder(FrappeTestCase): @classmethod def setUpClass(cls): diff --git a/erpnext/selling/report/payment_terms_status_for_sales_order/test_payment_terms_status_for_sales_order.py b/erpnext/selling/report/payment_terms_status_for_sales_order/test_payment_terms_status_for_sales_order.py index cad41e1dc03..f7f8a5dbce3 100644 --- a/erpnext/selling/report/payment_terms_status_for_sales_order/test_payment_terms_status_for_sales_order.py +++ b/erpnext/selling/report/payment_terms_status_for_sales_order/test_payment_terms_status_for_sales_order.py @@ -1,6 +1,7 @@ import datetime import frappe +from frappe.tests.utils import FrappeTestCase from frappe.utils import add_days from erpnext.selling.doctype.sales_order.sales_order import make_sales_invoice @@ -9,12 +10,11 @@ from erpnext.selling.report.payment_terms_status_for_sales_order.payment_terms_s execute, ) from erpnext.stock.doctype.item.test_item import create_item -from erpnext.tests.utils import ERPNextTestCase test_dependencies = ["Sales Order", "Item", "Sales Invoice", "Payment Terms Template"] -class TestPaymentTermsStatusForSalesOrder(ERPNextTestCase): +class TestPaymentTermsStatusForSalesOrder(FrappeTestCase): def create_payment_terms_template(self): # create template for 50-50 payments template = None diff --git a/erpnext/selling/report/pending_so_items_for_purchase_request/test_pending_so_items_for_purchase_request.py b/erpnext/selling/report/pending_so_items_for_purchase_request/test_pending_so_items_for_purchase_request.py index d62915fc66d..16162acc8f3 100644 --- a/erpnext/selling/report/pending_so_items_for_purchase_request/test_pending_so_items_for_purchase_request.py +++ b/erpnext/selling/report/pending_so_items_for_purchase_request/test_pending_so_items_for_purchase_request.py @@ -2,6 +2,7 @@ # For license information, please see license.txt +from frappe.tests.utils import FrappeTestCase from frappe.utils import add_months, nowdate from erpnext.selling.doctype.sales_order.sales_order import make_material_request @@ -9,10 +10,9 @@ from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_orde from erpnext.selling.report.pending_so_items_for_purchase_request.pending_so_items_for_purchase_request import ( execute, ) -from erpnext.tests.utils import ERPNextTestCase -class TestPendingSOItemsForPurchaseRequest(ERPNextTestCase): +class TestPendingSOItemsForPurchaseRequest(FrappeTestCase): def test_result_for_partial_material_request(self): so = make_sales_order() mr=make_material_request(so.name) diff --git a/erpnext/selling/report/sales_analytics/test_analytics.py b/erpnext/selling/report/sales_analytics/test_analytics.py index f56cce2dfdc..564f48fef3b 100644 --- a/erpnext/selling/report/sales_analytics/test_analytics.py +++ b/erpnext/selling/report/sales_analytics/test_analytics.py @@ -3,13 +3,13 @@ import frappe +from frappe.tests.utils import FrappeTestCase from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order from erpnext.selling.report.sales_analytics.sales_analytics import execute -from erpnext.tests.utils import ERPNextTestCase -class TestAnalytics(ERPNextTestCase): +class TestAnalytics(FrappeTestCase): def test_sales_analytics(self): frappe.db.sql("delete from `tabSales Order` where company='_Test Company 2'") diff --git a/erpnext/stock/doctype/batch/test_batch.py b/erpnext/stock/doctype/batch/test_batch.py index 613dd3f14d7..57637538531 100644 --- a/erpnext/stock/doctype/batch/test_batch.py +++ b/erpnext/stock/doctype/batch/test_batch.py @@ -5,6 +5,7 @@ import json import frappe from frappe.exceptions import ValidationError +from frappe.tests.utils import FrappeTestCase from frappe.utils import cint, flt from frappe.utils.data import add_to_date, getdate @@ -16,10 +17,9 @@ from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import ) from erpnext.stock.get_item_details import get_item_details from erpnext.stock.stock_ledger import get_valuation_rate -from erpnext.tests.utils import ERPNextTestCase -class TestBatch(ERPNextTestCase): +class TestBatch(FrappeTestCase): def test_item_has_batch_enabled(self): self.assertRaises(ValidationError, frappe.get_doc({ "doctype": "Batch", diff --git a/erpnext/stock/doctype/bin/test_bin.py b/erpnext/stock/doctype/bin/test_bin.py index 250126c6b98..ec0d8a88e3f 100644 --- a/erpnext/stock/doctype/bin/test_bin.py +++ b/erpnext/stock/doctype/bin/test_bin.py @@ -2,13 +2,13 @@ # See license.txt import frappe +from frappe.tests.utils import FrappeTestCase from erpnext.stock.doctype.item.test_item import make_item from erpnext.stock.utils import _create_bin -from erpnext.tests.utils import ERPNextTestCase -class TestBin(ERPNextTestCase): +class TestBin(FrappeTestCase): def test_concurrent_inserts(self): diff --git a/erpnext/stock/doctype/delivery_note/test_delivery_note.py b/erpnext/stock/doctype/delivery_note/test_delivery_note.py index bd18e788ba6..16c892128a6 100644 --- a/erpnext/stock/doctype/delivery_note/test_delivery_note.py +++ b/erpnext/stock/doctype/delivery_note/test_delivery_note.py @@ -6,6 +6,7 @@ import json import frappe +from frappe.tests.utils import FrappeTestCase from frappe.utils import cstr, flt, nowdate, nowtime from erpnext.accounts.doctype.account.test_account import get_inventory_account @@ -35,10 +36,9 @@ from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import ) from erpnext.stock.doctype.warehouse.test_warehouse import get_warehouse from erpnext.stock.stock_ledger import get_previous_sle -from erpnext.tests.utils import ERPNextTestCase -class TestDeliveryNote(ERPNextTestCase): +class TestDeliveryNote(FrappeTestCase): def test_over_billing_against_dn(self): frappe.db.set_value("Stock Settings", None, "allow_negative_stock", 1) diff --git a/erpnext/stock/doctype/delivery_trip/test_delivery_trip.py b/erpnext/stock/doctype/delivery_trip/test_delivery_trip.py index 321f48b2c59..dcdff4a0f1e 100644 --- a/erpnext/stock/doctype/delivery_trip/test_delivery_trip.py +++ b/erpnext/stock/doctype/delivery_trip/test_delivery_trip.py @@ -4,6 +4,7 @@ import unittest import frappe +from frappe.tests.utils import FrappeTestCase from frappe.utils import add_days, flt, now_datetime, nowdate import erpnext @@ -12,10 +13,10 @@ from erpnext.stock.doctype.delivery_trip.delivery_trip import ( make_expense_claim, notify_customers, ) -from erpnext.tests.utils import ERPNextTestCase, create_test_contact_and_address +from erpnext.tests.utils import create_test_contact_and_address -class TestDeliveryTrip(ERPNextTestCase): +class TestDeliveryTrip(FrappeTestCase): def setUp(self): super().setUp() driver = create_driver() diff --git a/erpnext/stock/doctype/item/test_item.py b/erpnext/stock/doctype/item/test_item.py index 9491e172593..d7671b1d714 100644 --- a/erpnext/stock/doctype/item/test_item.py +++ b/erpnext/stock/doctype/item/test_item.py @@ -6,6 +6,7 @@ import json import frappe from frappe.test_runner import make_test_objects +from frappe.tests.utils import FrappeTestCase, change_settings from frappe.utils import add_days, today from erpnext.controllers.item_variant import ( @@ -25,7 +26,6 @@ from erpnext.stock.doctype.item.item import ( ) from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry from erpnext.stock.get_item_details import get_item_details -from erpnext.tests.utils import ERPNextTestCase, change_settings test_ignore = ["BOM"] test_dependencies = ["Warehouse", "Item Group", "Item Tax Template", "Brand", "Item Attribute"] @@ -53,7 +53,7 @@ def make_item(item_code, properties=None): return item -class TestItem(ERPNextTestCase): +class TestItem(FrappeTestCase): def setUp(self): super().setUp() frappe.flags.attribute_values = None diff --git a/erpnext/stock/doctype/item_alternative/test_item_alternative.py b/erpnext/stock/doctype/item_alternative/test_item_alternative.py index 3976af4e88c..501c1c1ad3c 100644 --- a/erpnext/stock/doctype/item_alternative/test_item_alternative.py +++ b/erpnext/stock/doctype/item_alternative/test_item_alternative.py @@ -4,6 +4,7 @@ import json import frappe +from frappe.tests.utils import FrappeTestCase from frappe.utils import flt from erpnext.buying.doctype.purchase_order.purchase_order import ( @@ -18,10 +19,9 @@ from erpnext.stock.doctype.item.test_item import create_item from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import ( create_stock_reconciliation, ) -from erpnext.tests.utils import ERPNextTestCase -class TestItemAlternative(ERPNextTestCase): +class TestItemAlternative(FrappeTestCase): def setUp(self): super().setUp() make_items() diff --git a/erpnext/stock/doctype/item_attribute/test_item_attribute.py b/erpnext/stock/doctype/item_attribute/test_item_attribute.py index 0b7ca257151..055c22e0c5d 100644 --- a/erpnext/stock/doctype/item_attribute/test_item_attribute.py +++ b/erpnext/stock/doctype/item_attribute/test_item_attribute.py @@ -6,11 +6,12 @@ import frappe test_records = frappe.get_test_records('Item Attribute') +from frappe.tests.utils import FrappeTestCase + from erpnext.stock.doctype.item_attribute.item_attribute import ItemAttributeIncrementError -from erpnext.tests.utils import ERPNextTestCase -class TestItemAttribute(ERPNextTestCase): +class TestItemAttribute(FrappeTestCase): def setUp(self): super().setUp() if frappe.db.exists("Item Attribute", "_Test_Length"): diff --git a/erpnext/stock/doctype/item_price/test_item_price.py b/erpnext/stock/doctype/item_price/test_item_price.py index f81770e487d..6ceba3f8d3f 100644 --- a/erpnext/stock/doctype/item_price/test_item_price.py +++ b/erpnext/stock/doctype/item_price/test_item_price.py @@ -4,13 +4,13 @@ import frappe from frappe.test_runner import make_test_records_for_doctype +from frappe.tests.utils import FrappeTestCase from erpnext.stock.doctype.item_price.item_price import ItemPriceDuplicateItem from erpnext.stock.get_item_details import get_price_list_rate_for, process_args -from erpnext.tests.utils import ERPNextTestCase -class TestItemPrice(ERPNextTestCase): +class TestItemPrice(FrappeTestCase): def setUp(self): super().setUp() frappe.db.sql("delete from `tabItem Price`") diff --git a/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py b/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py index df8cadd7f86..dbaefc1e113 100644 --- a/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py +++ b/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py @@ -4,6 +4,7 @@ import frappe +from frappe.tests.utils import FrappeTestCase from frappe.utils import add_to_date, flt, now from erpnext.accounts.doctype.account.test_account import create_account, get_inventory_account @@ -14,10 +15,9 @@ from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import ( get_gl_entries, make_purchase_receipt, ) -from erpnext.tests.utils import ERPNextTestCase -class TestLandedCostVoucher(ERPNextTestCase): +class TestLandedCostVoucher(FrappeTestCase): def test_landed_cost_voucher(self): frappe.db.set_value("Buying Settings", None, "allow_multiple_items", 1) diff --git a/erpnext/stock/doctype/material_request/test_material_request.py b/erpnext/stock/doctype/material_request/test_material_request.py index 383b0ae806e..1cda7816170 100644 --- a/erpnext/stock/doctype/material_request/test_material_request.py +++ b/erpnext/stock/doctype/material_request/test_material_request.py @@ -6,6 +6,7 @@ import frappe +from frappe.tests.utils import FrappeTestCase from frappe.utils import flt, today from erpnext.stock.doctype.item.test_item import create_item @@ -15,10 +16,9 @@ from erpnext.stock.doctype.material_request.material_request import ( make_supplier_quotation, raise_work_orders, ) -from erpnext.tests.utils import ERPNextTestCase -class TestMaterialRequest(ERPNextTestCase): +class TestMaterialRequest(FrappeTestCase): def test_make_purchase_order(self): mr = frappe.copy_doc(test_records[0]).insert() diff --git a/erpnext/stock/doctype/packed_item/test_packed_item.py b/erpnext/stock/doctype/packed_item/test_packed_item.py index 2521ac9fe72..94268a8ef37 100644 --- a/erpnext/stock/doctype/packed_item/test_packed_item.py +++ b/erpnext/stock/doctype/packed_item/test_packed_item.py @@ -1,6 +1,7 @@ # Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt +from frappe.tests.utils import FrappeTestCase, change_settings from frappe.utils import add_to_date, nowdate from erpnext.selling.doctype.product_bundle.test_product_bundle import make_product_bundle @@ -9,10 +10,9 @@ from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_orde from erpnext.stock.doctype.item.test_item import make_item from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import get_gl_entries from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry -from erpnext.tests.utils import ERPNextTestCase, change_settings -class TestPackedItem(ERPNextTestCase): +class TestPackedItem(FrappeTestCase): "Test impact on Packed Items table in various scenarios." @classmethod def setUpClass(cls) -> None: diff --git a/erpnext/stock/doctype/packing_slip/test_packing_slip.py b/erpnext/stock/doctype/packing_slip/test_packing_slip.py index 5eb6b7399ae..bc405b20995 100644 --- a/erpnext/stock/doctype/packing_slip/test_packing_slip.py +++ b/erpnext/stock/doctype/packing_slip/test_packing_slip.py @@ -4,7 +4,7 @@ import unittest # test_records = frappe.get_test_records('Packing Slip') -from erpnext.tests.utils import ERPNextTestCase +from frappe.tests.utils import FrappeTestCase class TestPackingSlip(unittest.TestCase): diff --git a/erpnext/stock/doctype/pick_list/test_pick_list.py b/erpnext/stock/doctype/pick_list/test_pick_list.py index 41e3150f0d7..f3b6b89784a 100644 --- a/erpnext/stock/doctype/pick_list/test_pick_list.py +++ b/erpnext/stock/doctype/pick_list/test_pick_list.py @@ -6,16 +6,17 @@ from frappe import _dict test_dependencies = ['Item', 'Sales Invoice', 'Stock Entry', 'Batch'] +from frappe.tests.utils import FrappeTestCase + from erpnext.stock.doctype.item.test_item import create_item from erpnext.stock.doctype.pick_list.pick_list import create_delivery_note from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt from erpnext.stock.doctype.stock_reconciliation.stock_reconciliation import ( EmptyStockReconciliationItemsError, ) -from erpnext.tests.utils import ERPNextTestCase -class TestPickList(ERPNextTestCase): +class TestPickList(FrappeTestCase): def test_pick_list_picks_warehouse_for_each_item(self): try: diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py index d481689c130..a24acb1bd83 100644 --- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py @@ -7,6 +7,7 @@ import unittest from collections import defaultdict import frappe +from frappe.tests.utils import FrappeTestCase, change_settings from frappe.utils import add_days, cint, cstr, flt, today import erpnext @@ -17,10 +18,9 @@ from erpnext.stock.doctype.purchase_receipt.purchase_receipt import make_purchas from erpnext.stock.doctype.serial_no.serial_no import SerialNoDuplicateError, get_serial_nos from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse from erpnext.stock.stock_ledger import SerialNoExistsInFutureTransaction -from erpnext.tests.utils import ERPNextTestCase, change_settings -class TestPurchaseReceipt(ERPNextTestCase): +class TestPurchaseReceipt(FrappeTestCase): def setUp(self): frappe.db.set_value("Buying Settings", None, "allow_multiple_items", 1) diff --git a/erpnext/stock/doctype/putaway_rule/test_putaway_rule.py b/erpnext/stock/doctype/putaway_rule/test_putaway_rule.py index ff1c19a8275..4e8d71fe5e4 100644 --- a/erpnext/stock/doctype/putaway_rule/test_putaway_rule.py +++ b/erpnext/stock/doctype/putaway_rule/test_putaway_rule.py @@ -2,6 +2,7 @@ # See license.txt import frappe +from frappe.tests.utils import FrappeTestCase from erpnext.stock.doctype.batch.test_batch import make_new_batch from erpnext.stock.doctype.item.test_item import make_item @@ -9,10 +10,9 @@ from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_pu from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse from erpnext.stock.get_item_details import get_conversion_factor -from erpnext.tests.utils import ERPNextTestCase -class TestPutawayRule(ERPNextTestCase): +class TestPutawayRule(FrappeTestCase): def setUp(self): if not frappe.db.exists("Item", "_Rice"): make_item("_Rice", { diff --git a/erpnext/stock/doctype/quality_inspection/test_quality_inspection.py b/erpnext/stock/doctype/quality_inspection/test_quality_inspection.py index 308c62875d5..601ca054b53 100644 --- a/erpnext/stock/doctype/quality_inspection/test_quality_inspection.py +++ b/erpnext/stock/doctype/quality_inspection/test_quality_inspection.py @@ -2,6 +2,7 @@ # See license.txt import frappe +from frappe.tests.utils import FrappeTestCase from frappe.utils import nowdate from erpnext.controllers.stock_controller import ( @@ -13,12 +14,11 @@ from erpnext.controllers.stock_controller import ( from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note from erpnext.stock.doctype.item.test_item import create_item from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry -from erpnext.tests.utils import ERPNextTestCase # test_records = frappe.get_test_records('Quality Inspection') -class TestQualityInspection(ERPNextTestCase): +class TestQualityInspection(FrappeTestCase): def setUp(self): super().setUp() create_item("_Test Item with QA") diff --git a/erpnext/stock/doctype/serial_no/test_serial_no.py b/erpnext/stock/doctype/serial_no/test_serial_no.py index f8cea717251..057a7d4c01f 100644 --- a/erpnext/stock/doctype/serial_no/test_serial_no.py +++ b/erpnext/stock/doctype/serial_no/test_serial_no.py @@ -18,11 +18,12 @@ from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse test_dependencies = ["Item"] test_records = frappe.get_test_records('Serial No') +from frappe.tests.utils import FrappeTestCase + from erpnext.stock.doctype.serial_no.serial_no import * -from erpnext.tests.utils import ERPNextTestCase -class TestSerialNo(ERPNextTestCase): +class TestSerialNo(FrappeTestCase): def tearDown(self): frappe.db.rollback() diff --git a/erpnext/stock/doctype/shipment/test_shipment.py b/erpnext/stock/doctype/shipment/test_shipment.py index afe821845ae..317abb6d03e 100644 --- a/erpnext/stock/doctype/shipment/test_shipment.py +++ b/erpnext/stock/doctype/shipment/test_shipment.py @@ -4,12 +4,12 @@ from datetime import date, timedelta import frappe +from frappe.tests.utils import FrappeTestCase from erpnext.stock.doctype.delivery_note.delivery_note import make_shipment -from erpnext.tests.utils import ERPNextTestCase -class TestShipment(ERPNextTestCase): +class TestShipment(FrappeTestCase): def test_shipment_from_delivery_note(self): delivery_note = create_test_delivery_note() delivery_note.submit() diff --git a/erpnext/stock/doctype/stock_entry/test_stock_entry.py b/erpnext/stock/doctype/stock_entry/test_stock_entry.py index c5afa491666..54c0e43c5ed 100644 --- a/erpnext/stock/doctype/stock_entry/test_stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/test_stock_entry.py @@ -6,6 +6,7 @@ import unittest import frappe from frappe.permissions import add_user_permission, remove_user_permission +from frappe.tests.utils import FrappeTestCase, change_settings from frappe.utils import flt, nowdate, nowtime from erpnext.accounts.doctype.account.test_account import get_inventory_account @@ -28,7 +29,6 @@ from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import create_stock_reconciliation, ) from erpnext.stock.stock_ledger import NegativeStockError, get_previous_sle -from erpnext.tests.utils import ERPNextTestCase, change_settings def get_sle(**args): @@ -42,7 +42,7 @@ def get_sle(**args): order by timestamp(posting_date, posting_time) desc, creation desc limit 1"""% condition, values, as_dict=1) -class TestStockEntry(ERPNextTestCase): +class TestStockEntry(FrappeTestCase): def tearDown(self): frappe.db.rollback() frappe.set_user("Administrator") diff --git a/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py b/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py index 0864ece995f..01d25b2e864 100644 --- a/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py +++ b/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py @@ -7,6 +7,7 @@ from uuid import uuid4 import frappe from frappe.core.page.permission_manager.permission_manager import reset +from frappe.tests.utils import FrappeTestCase from frappe.utils import add_days, today from erpnext.stock.doctype.delivery_note.test_delivery_note import ( @@ -24,10 +25,9 @@ from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import create_stock_reconciliation, ) from erpnext.stock.stock_ledger import get_previous_sle -from erpnext.tests.utils import ERPNextTestCase -class TestStockLedgerEntry(ERPNextTestCase): +class TestStockLedgerEntry(FrappeTestCase): def setUp(self): items = create_items() reset('Stock Entry') diff --git a/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py index 2ffe127d9a5..e6b252e8562 100644 --- a/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py +++ b/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py @@ -6,6 +6,7 @@ import frappe +from frappe.tests.utils import FrappeTestCase, change_settings from frappe.utils import add_days, cstr, flt, nowdate, nowtime, random_string from erpnext.accounts.utils import get_stock_and_account_balance @@ -19,10 +20,9 @@ from erpnext.stock.doctype.stock_reconciliation.stock_reconciliation import ( from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse from erpnext.stock.stock_ledger import get_previous_sle, update_entries_after from erpnext.stock.utils import get_incoming_rate, get_stock_value_on, get_valuation_method -from erpnext.tests.utils import ERPNextTestCase, change_settings -class TestStockReconciliation(ERPNextTestCase): +class TestStockReconciliation(FrappeTestCase): @classmethod def setUpClass(cls): create_batch_or_serial_no_items() diff --git a/erpnext/stock/doctype/stock_settings/test_stock_settings.py b/erpnext/stock/doctype/stock_settings/test_stock_settings.py index 072b54b8205..13496718ead 100644 --- a/erpnext/stock/doctype/stock_settings/test_stock_settings.py +++ b/erpnext/stock/doctype/stock_settings/test_stock_settings.py @@ -4,11 +4,10 @@ import unittest import frappe - -from erpnext.tests.utils import ERPNextTestCase +from frappe.tests.utils import FrappeTestCase -class TestStockSettings(ERPNextTestCase): +class TestStockSettings(FrappeTestCase): def setUp(self): super().setUp() frappe.db.set_value("Stock Settings", None, "clean_description_html", 0) diff --git a/erpnext/stock/doctype/warehouse/test_warehouse.py b/erpnext/stock/doctype/warehouse/test_warehouse.py index 26db2642e4b..cdb771935b0 100644 --- a/erpnext/stock/doctype/warehouse/test_warehouse.py +++ b/erpnext/stock/doctype/warehouse/test_warehouse.py @@ -3,17 +3,17 @@ import frappe from frappe.test_runner import make_test_records +from frappe.tests.utils import FrappeTestCase from frappe.utils import cint import erpnext from erpnext.accounts.doctype.account.test_account import create_account, get_inventory_account from erpnext.stock.doctype.item.test_item import create_item from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry -from erpnext.tests.utils import ERPNextTestCase test_records = frappe.get_test_records('Warehouse') -class TestWarehouse(ERPNextTestCase): +class TestWarehouse(FrappeTestCase): def setUp(self): super().setUp() if not frappe.get_value('Item', '_Test Item'): diff --git a/erpnext/stock/report/stock_ageing/test_stock_ageing.py b/erpnext/stock/report/stock_ageing/test_stock_ageing.py index 3fc357e8d4f..2630805c626 100644 --- a/erpnext/stock/report/stock_ageing/test_stock_ageing.py +++ b/erpnext/stock/report/stock_ageing/test_stock_ageing.py @@ -2,12 +2,12 @@ # See license.txt import frappe +from frappe.tests.utils import FrappeTestCase from erpnext.stock.report.stock_ageing.stock_ageing import FIFOSlots, format_report_data -from erpnext.tests.utils import ERPNextTestCase -class TestStockAgeing(ERPNextTestCase): +class TestStockAgeing(FrappeTestCase): def setUp(self) -> None: self.filters = frappe._dict( company="_Test Company", @@ -610,4 +610,4 @@ def generate_item_and_item_wh_wise_slots(filters, sle): item_wh_wise_slots = FIFOSlots(filters, sle).generate() filters.show_warehouse_wise_stock = False - return item_wise_slots, item_wh_wise_slots \ No newline at end of file + return item_wise_slots, item_wh_wise_slots diff --git a/erpnext/stock/report/stock_analytics/test_stock_analytics.py b/erpnext/stock/report/stock_analytics/test_stock_analytics.py index 32df5859375..f6c98f914d2 100644 --- a/erpnext/stock/report/stock_analytics/test_stock_analytics.py +++ b/erpnext/stock/report/stock_analytics/test_stock_analytics.py @@ -1,14 +1,13 @@ import datetime -import unittest from frappe import _dict +from frappe.tests.utils import FrappeTestCase from erpnext.accounts.utils import get_fiscal_year from erpnext.stock.report.stock_analytics.stock_analytics import get_period_date_ranges -from erpnext.tests.utils import ERPNextTestCase -class TestStockAnalyticsReport(ERPNextTestCase): +class TestStockAnalyticsReport(FrappeTestCase): def test_get_period_date_ranges(self): filters = _dict(range="Monthly", from_date="2020-12-28", to_date="2021-02-06") diff --git a/erpnext/stock/tests/test_valuation.py b/erpnext/stock/tests/test_valuation.py index bdb768f1ade..b64ff8e28c8 100644 --- a/erpnext/stock/tests/test_valuation.py +++ b/erpnext/stock/tests/test_valuation.py @@ -2,13 +2,13 @@ import json import unittest import frappe +from frappe.tests.utils import FrappeTestCase from hypothesis import given from hypothesis import strategies as st from erpnext.stock.doctype.item.test_item import make_item from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry from erpnext.stock.valuation import FIFOValuation, LIFOValuation, round_off_if_near_zero -from erpnext.tests.utils import ERPNextTestCase qty_gen = st.floats(min_value=-1e6, max_value=1e6) value_gen = st.floats(min_value=1, max_value=1e6) @@ -290,7 +290,7 @@ class TestLIFOValuation(unittest.TestCase): self.assertTotalQty(total_qty) self.assertTotalValue(total_value) -class TestLIFOValuationSLE(ERPNextTestCase): +class TestLIFOValuationSLE(FrappeTestCase): ITEM_CODE = "_Test LIFO item" WAREHOUSE = "_Test Warehouse - _TC" diff --git a/erpnext/tests/utils.py b/erpnext/tests/utils.py index 40c95eb7a3a..d795253665d 100644 --- a/erpnext/tests/utils.py +++ b/erpnext/tests/utils.py @@ -1,10 +1,6 @@ # Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -import copy -import signal -import unittest -from contextlib import contextmanager from typing import Any, Dict, NewType, Optional import frappe @@ -13,22 +9,6 @@ from frappe.core.doctype.report.report import get_report_module_dotted_path ReportFilters = Dict[str, Any] ReportName = NewType("ReportName", str) - -class ERPNextTestCase(unittest.TestCase): - """A sane default test class for ERPNext tests.""" - - - @classmethod - def setUpClass(cls) -> None: - frappe.db.commit() - return super().setUpClass() - - @classmethod - def tearDownClass(cls) -> None: - frappe.db.rollback() - return super().tearDownClass() - - def create_test_contact_and_address(): frappe.db.sql('delete from tabContact') frappe.db.sql('delete from `tabContact Email`') @@ -81,43 +61,6 @@ def create_test_contact_and_address(): contact_two.insert() -@contextmanager -def change_settings(doctype, settings_dict): - """ A context manager to ensure that settings are changed before running - function and restored after running it regardless of exceptions occured. - This is useful in tests where you want to make changes in a function but - don't retain those changes. - import and use as decorator to cover full function or using `with` statement. - - example: - @change_settings("Stock Settings", {"item_naming_by": "Naming Series"}) - def test_case(self): - ... - """ - - try: - settings = frappe.get_doc(doctype) - # remember setting - previous_settings = copy.deepcopy(settings_dict) - for key in previous_settings: - previous_settings[key] = getattr(settings, key) - - # change setting - for key, value in settings_dict.items(): - setattr(settings, key, value) - settings.save() - # singles are cached by default, clear to avoid flake - frappe.db.value_cache[settings] = {} - yield # yield control to calling function - - finally: - # restore settings - settings = frappe.get_doc(doctype) - for key, value in previous_settings.items(): - setattr(settings, key, value) - settings.save() - - def execute_script_report( report_name: ReportName, module: str, @@ -157,24 +100,3 @@ def execute_script_report( except Exception: print(f"Report failed to execute with filters: {test_filter}") raise - - - -def timeout(seconds=30, error_message="Test timed out."): - """ Timeout decorator to ensure a test doesn't run for too long. - - adapted from https://stackoverflow.com/a/2282656""" - def decorator(func): - def _handle_timeout(signum, frame): - raise Exception(error_message) - - def wrapper(*args, **kwargs): - signal.signal(signal.SIGALRM, _handle_timeout) - signal.alarm(seconds) - try: - result = func(*args, **kwargs) - finally: - signal.alarm(0) - return result - return wrapper - return decorator From 829c453cb616107471ed5fd6b0ef7b75bb0420e7 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Mon, 28 Feb 2022 17:12:51 +0530 Subject: [PATCH 49/75] test: remove transaction commits from buying module --- erpnext/buying/doctype/purchase_order/test_purchase_order.py | 4 ++-- .../request_for_quotation/test_request_for_quotation.py | 4 ++-- erpnext/buying/doctype/supplier/test_supplier.py | 5 +++-- .../doctype/supplier_quotation/test_supplier_quotation.py | 4 ++-- .../doctype/supplier_scorecard/test_supplier_scorecard.py | 4 ++-- .../test_supplier_scorecard_criteria.py | 4 ++-- .../test_supplier_scorecard_variable.py | 4 ++-- .../report/procurement_tracker/test_procurement_tracker.py | 4 ++-- .../test_subcontracted_item_to_be_received.py | 4 ++-- .../test_subcontracted_raw_materials_to_be_transferred.py | 4 ++-- 10 files changed, 21 insertions(+), 20 deletions(-) diff --git a/erpnext/buying/doctype/purchase_order/test_purchase_order.py b/erpnext/buying/doctype/purchase_order/test_purchase_order.py index 645e97ee7c8..efa2ab12685 100644 --- a/erpnext/buying/doctype/purchase_order/test_purchase_order.py +++ b/erpnext/buying/doctype/purchase_order/test_purchase_order.py @@ -3,9 +3,9 @@ import json -import unittest import frappe +from frappe.tests.utils import FrappeTestCase from frappe.utils import add_days, flt, getdate, nowdate from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry @@ -27,7 +27,7 @@ from erpnext.stock.doctype.purchase_receipt.purchase_receipt import ( from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry -class TestPurchaseOrder(unittest.TestCase): +class TestPurchaseOrder(FrappeTestCase): def test_make_purchase_receipt(self): po = create_purchase_order(do_not_submit=True) self.assertRaises(frappe.ValidationError, make_purchase_receipt, po.name) diff --git a/erpnext/buying/doctype/request_for_quotation/test_request_for_quotation.py b/erpnext/buying/doctype/request_for_quotation/test_request_for_quotation.py index 51901991b5a..5b2112424c9 100644 --- a/erpnext/buying/doctype/request_for_quotation/test_request_for_quotation.py +++ b/erpnext/buying/doctype/request_for_quotation/test_request_for_quotation.py @@ -1,9 +1,9 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -import unittest import frappe +from frappe.tests.utils import FrappeTestCase from frappe.utils import nowdate from erpnext.buying.doctype.request_for_quotation.request_for_quotation import ( @@ -16,7 +16,7 @@ from erpnext.stock.doctype.item.test_item import make_item from erpnext.templates.pages.rfq import check_supplier_has_docname_access -class TestRequestforQuotation(unittest.TestCase): +class TestRequestforQuotation(FrappeTestCase): def test_quote_status(self): rfq = make_request_for_quotation() diff --git a/erpnext/buying/doctype/supplier/test_supplier.py b/erpnext/buying/doctype/supplier/test_supplier.py index 0fb81b2578d..7358e2af223 100644 --- a/erpnext/buying/doctype/supplier/test_supplier.py +++ b/erpnext/buying/doctype/supplier/test_supplier.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -import unittest import frappe from frappe.test_runner import make_test_records @@ -12,8 +11,10 @@ from erpnext.exceptions import PartyDisabled test_dependencies = ['Payment Term', 'Payment Terms Template'] test_records = frappe.get_test_records('Supplier') +from frappe.tests.utils import FrappeTestCase -class TestSupplier(unittest.TestCase): + +class TestSupplier(FrappeTestCase): def test_get_supplier_group_details(self): doc = frappe.new_doc("Supplier Group") doc.supplier_group_name = "_Testing Supplier Group" diff --git a/erpnext/buying/doctype/supplier_quotation/test_supplier_quotation.py b/erpnext/buying/doctype/supplier_quotation/test_supplier_quotation.py index d48ac7eb3b4..a4d45975c30 100644 --- a/erpnext/buying/doctype/supplier_quotation/test_supplier_quotation.py +++ b/erpnext/buying/doctype/supplier_quotation/test_supplier_quotation.py @@ -3,12 +3,12 @@ -import unittest import frappe +from frappe.tests.utils import FrappeTestCase -class TestPurchaseOrder(unittest.TestCase): +class TestPurchaseOrder(FrappeTestCase): def test_make_purchase_order(self): from erpnext.buying.doctype.supplier_quotation.supplier_quotation import make_purchase_order diff --git a/erpnext/buying/doctype/supplier_scorecard/test_supplier_scorecard.py b/erpnext/buying/doctype/supplier_scorecard/test_supplier_scorecard.py index 7908c35cbbe..8ecc2cd4667 100644 --- a/erpnext/buying/doctype/supplier_scorecard/test_supplier_scorecard.py +++ b/erpnext/buying/doctype/supplier_scorecard/test_supplier_scorecard.py @@ -1,12 +1,12 @@ # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -import unittest import frappe +from frappe.tests.utils import FrappeTestCase -class TestSupplierScorecard(unittest.TestCase): +class TestSupplierScorecard(FrappeTestCase): def test_create_scorecard(self): doc = make_supplier_scorecard().insert() diff --git a/erpnext/buying/doctype/supplier_scorecard_criteria/test_supplier_scorecard_criteria.py b/erpnext/buying/doctype/supplier_scorecard_criteria/test_supplier_scorecard_criteria.py index dacc982420e..7ff84c15e52 100644 --- a/erpnext/buying/doctype/supplier_scorecard_criteria/test_supplier_scorecard_criteria.py +++ b/erpnext/buying/doctype/supplier_scorecard_criteria/test_supplier_scorecard_criteria.py @@ -1,12 +1,12 @@ # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -import unittest import frappe +from frappe.tests.utils import FrappeTestCase -class TestSupplierScorecardCriteria(unittest.TestCase): +class TestSupplierScorecardCriteria(FrappeTestCase): def test_variables_exist(self): delete_test_scorecards() for d in test_good_criteria: diff --git a/erpnext/buying/doctype/supplier_scorecard_variable/test_supplier_scorecard_variable.py b/erpnext/buying/doctype/supplier_scorecard_variable/test_supplier_scorecard_variable.py index 4d75981125f..32005a37dc7 100644 --- a/erpnext/buying/doctype/supplier_scorecard_variable/test_supplier_scorecard_variable.py +++ b/erpnext/buying/doctype/supplier_scorecard_variable/test_supplier_scorecard_variable.py @@ -1,16 +1,16 @@ # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -import unittest import frappe +from frappe.tests.utils import FrappeTestCase from erpnext.buying.doctype.supplier_scorecard_variable.supplier_scorecard_variable import ( VariablePathNotFound, ) -class TestSupplierScorecardVariable(unittest.TestCase): +class TestSupplierScorecardVariable(FrappeTestCase): def test_variable_exist(self): for d in test_existing_variables: my_doc = frappe.get_doc("Supplier Scorecard Variable", d.get("name")) diff --git a/erpnext/buying/report/procurement_tracker/test_procurement_tracker.py b/erpnext/buying/report/procurement_tracker/test_procurement_tracker.py index 84de8c67438..44524527e3a 100644 --- a/erpnext/buying/report/procurement_tracker/test_procurement_tracker.py +++ b/erpnext/buying/report/procurement_tracker/test_procurement_tracker.py @@ -2,10 +2,10 @@ # For license information, please see license.txt -import unittest from datetime import datetime import frappe +from frappe.tests.utils import FrappeTestCase from erpnext.buying.doctype.purchase_order.purchase_order import make_purchase_receipt from erpnext.buying.report.procurement_tracker.procurement_tracker import execute @@ -14,7 +14,7 @@ from erpnext.stock.doctype.material_request.test_material_request import make_ma from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse -class TestProcurementTracker(unittest.TestCase): +class TestProcurementTracker(FrappeTestCase): def test_result_for_procurement_tracker(self): filters = { 'company': '_Test Procurement Company', diff --git a/erpnext/buying/report/subcontracted_item_to_be_received/test_subcontracted_item_to_be_received.py b/erpnext/buying/report/subcontracted_item_to_be_received/test_subcontracted_item_to_be_received.py index 144523ad522..c2b38d38e18 100644 --- a/erpnext/buying/report/subcontracted_item_to_be_received/test_subcontracted_item_to_be_received.py +++ b/erpnext/buying/report/subcontracted_item_to_be_received/test_subcontracted_item_to_be_received.py @@ -3,9 +3,9 @@ # Compiled at: 2019-05-06 09:51:46 # Decompiled by https://python-decompiler.com -import unittest import frappe +from frappe.tests.utils import FrappeTestCase from erpnext.buying.doctype.purchase_order.purchase_order import make_purchase_receipt from erpnext.buying.doctype.purchase_order.test_purchase_order import create_purchase_order @@ -15,7 +15,7 @@ from erpnext.buying.report.subcontracted_item_to_be_received.subcontracted_item_ from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry -class TestSubcontractedItemToBeReceived(unittest.TestCase): +class TestSubcontractedItemToBeReceived(FrappeTestCase): def test_pending_and_received_qty(self): po = create_purchase_order(item_code='_Test FG Item', is_subcontracted='Yes') diff --git a/erpnext/buying/report/subcontracted_raw_materials_to_be_transferred/test_subcontracted_raw_materials_to_be_transferred.py b/erpnext/buying/report/subcontracted_raw_materials_to_be_transferred/test_subcontracted_raw_materials_to_be_transferred.py index 3c203ac23fa..fc9acabc81d 100644 --- a/erpnext/buying/report/subcontracted_raw_materials_to_be_transferred/test_subcontracted_raw_materials_to_be_transferred.py +++ b/erpnext/buying/report/subcontracted_raw_materials_to_be_transferred/test_subcontracted_raw_materials_to_be_transferred.py @@ -4,9 +4,9 @@ # Decompiled by https://python-decompiler.com import json -import unittest import frappe +from frappe.tests.utils import FrappeTestCase from erpnext.buying.doctype.purchase_order.purchase_order import make_rm_stock_entry from erpnext.buying.doctype.purchase_order.test_purchase_order import create_purchase_order @@ -16,7 +16,7 @@ from erpnext.buying.report.subcontracted_raw_materials_to_be_transferred.subcont from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry -class TestSubcontractedItemToBeTransferred(unittest.TestCase): +class TestSubcontractedItemToBeTransferred(FrappeTestCase): def test_pending_and_transferred_qty(self): po = create_purchase_order(item_code='_Test FG Item', is_subcontracted='Yes', supplier_warehouse="_Test Warehouse 1 - _TC") From 19fb7ead9f249d28403f618297009d498675d224 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Mon, 28 Feb 2022 18:05:58 +0530 Subject: [PATCH 50/75] test: Add test case for payment entry taxes --- .../doctype/payment_entry/payment_entry.py | 8 ++-- .../payment_entry/test_payment_entry.py | 39 +++++++++++++++++++ 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py index 6ec15e1e879..eb2019bdf03 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.py +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py @@ -946,11 +946,11 @@ class PaymentEntry(AccountsController): tax.base_total = tax.total * self.source_exchange_rate if self.payment_type == 'Pay': - self.base_total_taxes_and_charges += current_tax_amount * self.source_exchange_rate - self.total_taxes_and_charges += current_tax_amount * self.target_exchange_rate + self.base_total_taxes_and_charges += flt(current_tax_amount / self.source_exchange_rate) + self.total_taxes_and_charges += flt(current_tax_amount / self.target_exchange_rate) else: - self.base_total_taxes_and_charges += current_tax_amount * self.target_exchange_rate - self.total_taxes_and_charges += current_tax_amount * self.source_exchange_rate + self.base_total_taxes_and_charges += flt(current_tax_amount / self.target_exchange_rate) + self.total_taxes_and_charges += flt(current_tax_amount / self.source_exchange_rate) if self.get('taxes'): self.paid_amount_after_tax = self.get('taxes')[-1].base_total diff --git a/erpnext/accounts/doctype/payment_entry/test_payment_entry.py b/erpnext/accounts/doctype/payment_entry/test_payment_entry.py index cc3528e9aaa..349b8bb5b1b 100644 --- a/erpnext/accounts/doctype/payment_entry/test_payment_entry.py +++ b/erpnext/accounts/doctype/payment_entry/test_payment_entry.py @@ -633,6 +633,45 @@ class TestPaymentEntry(unittest.TestCase): self.assertEqual(flt(expected_party_balance), party_balance) self.assertEqual(flt(expected_party_account_balance), party_account_balance) + def test_multi_currency_payment_entry_with_taxes(self): + payment_entry = create_payment_entry(party='_Test Supplier USD', paid_to = '_Test Payable USD - _TC', + save=True) + payment_entry.append('taxes', { + 'account_head': '_Test Account Service Tax - _TC', + 'charge_type': 'Actual', + 'tax_amount': 10, + 'add_deduct_tax': 'Add', + 'description': 'Test' + }) + + payment_entry.save() + self.assertEqual(payment_entry.base_total_taxes_and_charges, 10) + self.assertEqual(flt(payment_entry.total_taxes_and_charges, 2), flt(10 / payment_entry.target_exchange_rate, 2)) + +def create_payment_entry(**args): + payment_entry = frappe.new_doc('Payment Entry') + payment_entry.company = args.get('company') or '_Test Company' + payment_entry.payment_type = args.get('payment_type') or 'Pay' + payment_entry.party_type = args.get('party_type') or 'Supplier' + payment_entry.party = args.get('party') or '_Test Supplier' + payment_entry.paid_from = args.get('paid_from') or '_Test Bank - _TC' + payment_entry.paid_to = args.get('paid_to') or 'Creditors - _TC' + payment_entry.paid_amount = args.get('paid_amount') or 1000 + + payment_entry.setup_party_account_field() + payment_entry.set_missing_values() + payment_entry.set_exchange_rate() + payment_entry.received_amount = payment_entry.paid_amount / payment_entry.target_exchange_rate + payment_entry.reference_no = 'Test001' + payment_entry.reference_date = nowdate() + + if args.get('save'): + payment_entry.save() + if args.get('submit'): + payment_entry.submit() + + return payment_entry + def create_payment_terms_template(): create_payment_term('Basic Amount Receivable') From 4e2c284be7904f9d553a6eb8e93e100edcd909e6 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Tue, 1 Mar 2022 08:52:42 +0530 Subject: [PATCH 51/75] fix(minor): nix the ugly banner --- .../includes/footer/footer_powered.html | 28 +------------------ 1 file changed, 1 insertion(+), 27 deletions(-) diff --git a/erpnext/templates/includes/footer/footer_powered.html b/erpnext/templates/includes/footer/footer_powered.html index 82b2716a924..faf5e9278c7 100644 --- a/erpnext/templates/includes/footer/footer_powered.html +++ b/erpnext/templates/includes/footer/footer_powered.html @@ -1,27 +1 @@ -{% set domains = frappe.get_doc("Domain Settings").active_domains %} -{% set links = { - 'Manufacturing': '/manufacturing', - 'Services': '/services', - 'Retail': '/retail', - 'Distribution': '/distribution', - 'Non Profit': '/non-profit', - 'Education': '/education', - 'Healthcare': '/healthcare', - 'Agriculture': '/agriculture', - 'Hospitality': '' -} %} - -{% set link = '' %} -{% set label = '' %} -{% if domains %} - {% set label = domains[0].domain %} - {% set link = links[label] %} -{% endif %} - -{% if label == "Services" %} - {% set label = "Service" %} -{% endif %} - - - -Powered by ERPNext - {{ '' if domains else 'Open Source' }} ERP Software {{ ('for ' + label + ' Companies') if domains else '' }} +Powered by ERPNext From 366120ffeed36c68b9ceb1f677cc4497673b4289 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Tue, 1 Mar 2022 11:56:20 +0530 Subject: [PATCH 52/75] fix: Deferred revenue booking --- erpnext/accounts/deferred_revenue.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/erpnext/accounts/deferred_revenue.py b/erpnext/accounts/deferred_revenue.py index 9e2cdfffd9a..ab1061beeb3 100644 --- a/erpnext/accounts/deferred_revenue.py +++ b/erpnext/accounts/deferred_revenue.py @@ -120,6 +120,7 @@ def get_booking_dates(doc, item, posting_date=None): prev_gl_entry = frappe.db.sql(''' select name, posting_date from `tabGL Entry` where company=%s and account=%s and voucher_type=%s and voucher_no=%s and voucher_detail_no=%s + and is_cancelled = 0 order by posting_date desc limit 1 ''', (doc.company, item.get(deferred_account), doc.doctype, doc.name, item.name), as_dict=True) @@ -227,6 +228,7 @@ def get_already_booked_amount(doc, item): gl_entries_details = frappe.db.sql(''' select sum({0}) as total_credit, sum({1}) as total_credit_in_account_currency, voucher_detail_no from `tabGL Entry` where company=%s and account=%s and voucher_type=%s and voucher_no=%s and voucher_detail_no=%s + and is_cancelled = 0 group by voucher_detail_no '''.format(total_credit_debit, total_credit_debit_currency), (doc.company, item.get(deferred_account), doc.doctype, doc.name, item.name), as_dict=True) @@ -282,7 +284,7 @@ def book_deferred_income_or_expense(doc, deferred_process, posting_date=None): return # check if books nor frozen till endate: - if getdate(end_date) >= getdate(accounts_frozen_upto): + if accounts_frozen_upto and (end_date) <= getdate(accounts_frozen_upto): end_date = get_last_day(add_days(accounts_frozen_upto, 1)) if via_journal_entry: From 25fa6344a6c3dc3af7ecea250d30a421f4016afc Mon Sep 17 00:00:00 2001 From: marination Date: Tue, 1 Mar 2022 12:24:45 +0530 Subject: [PATCH 53/75] test: Adjust test as per teardown - make tests use multi level bom in WO, as BOM at setup is used - earlier, an intermediate BOM made in a test would override the BOM at setup --- .../doctype/production_plan/test_production_plan.py | 4 +++- erpnext/manufacturing/doctype/work_order/test_work_order.py | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/erpnext/manufacturing/doctype/production_plan/test_production_plan.py b/erpnext/manufacturing/doctype/production_plan/test_production_plan.py index 85ecec2f692..ca8cc7a47e1 100644 --- a/erpnext/manufacturing/doctype/production_plan/test_production_plan.py +++ b/erpnext/manufacturing/doctype/production_plan/test_production_plan.py @@ -154,7 +154,7 @@ class TestProductionPlan(FrappeTestCase): use_multi_level_bom=0, ignore_existing_ordered_qty=0 ) - self.assertTrue(len(pln.mr_items), 0) + self.assertTrue(len(pln.mr_items)) sr1.cancel() sr2.cancel() @@ -575,6 +575,7 @@ class TestProductionPlan(FrappeTestCase): wip_warehouse='Work In Progress - _TC', fg_warehouse='Finished Goods - _TC', skip_transfer=1, + use_multi_level_bom=1, do_not_submit=True ) wo.production_plan = pln.name @@ -619,6 +620,7 @@ class TestProductionPlan(FrappeTestCase): wip_warehouse='Work In Progress - _TC', fg_warehouse='Finished Goods - _TC', skip_transfer=1, + use_multi_level_bom=1, do_not_submit=True ) wo.production_plan = pln.name diff --git a/erpnext/manufacturing/doctype/work_order/test_work_order.py b/erpnext/manufacturing/doctype/work_order/test_work_order.py index 549ec7b4a66..bc07d22e83a 100644 --- a/erpnext/manufacturing/doctype/work_order/test_work_order.py +++ b/erpnext/manufacturing/doctype/work_order/test_work_order.py @@ -1040,7 +1040,7 @@ def make_wo_order_test_record(**args): wo_order.scrap_warehouse = args.fg_warehouse or "_Test Scrap Warehouse - _TC" wo_order.company = args.company or "_Test Company" wo_order.stock_uom = args.stock_uom or "_Test UOM" - wo_order.use_multi_level_bom=0 + wo_order.use_multi_level_bom= args.use_multi_level_bom or 0 wo_order.skip_transfer=args.skip_transfer or 0 wo_order.get_items_and_operations_from_bom() wo_order.sales_order = args.sales_order or None From ffbb2c831152686b9ec0b230b3c72b94edce0c6a Mon Sep 17 00:00:00 2001 From: marination Date: Tue, 1 Mar 2022 12:57:09 +0530 Subject: [PATCH 54/75] fix: Assert False for test that is anticipating an empty table and remove second arg to assertTrue --- .../doctype/production_plan/test_production_plan.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/manufacturing/doctype/production_plan/test_production_plan.py b/erpnext/manufacturing/doctype/production_plan/test_production_plan.py index ca8cc7a47e1..59cc17a5eee 100644 --- a/erpnext/manufacturing/doctype/production_plan/test_production_plan.py +++ b/erpnext/manufacturing/doctype/production_plan/test_production_plan.py @@ -113,7 +113,7 @@ class TestProductionPlan(FrappeTestCase): item_code='Test Production Item 1', ignore_existing_ordered_qty=1 ) - self.assertTrue(len(pln.mr_items), 1) + self.assertTrue(len(pln.mr_items)) self.assertTrue(flt(pln.mr_items[0].quantity), 1.0) sr1.cancel() @@ -154,7 +154,7 @@ class TestProductionPlan(FrappeTestCase): use_multi_level_bom=0, ignore_existing_ordered_qty=0 ) - self.assertTrue(len(pln.mr_items)) + self.assertFalse(len(pln.mr_items)) sr1.cancel() sr2.cancel() From d22a1d440c96d5a476ce466074a264362a4c814a Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Tue, 1 Mar 2022 13:06:40 +0530 Subject: [PATCH 55/75] fix: track changes on warehouse --- erpnext/stock/doctype/warehouse/warehouse.json | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/erpnext/stock/doctype/warehouse/warehouse.json b/erpnext/stock/doctype/warehouse/warehouse.json index 05076b51a3e..c695d541bf9 100644 --- a/erpnext/stock/doctype/warehouse/warehouse.json +++ b/erpnext/stock/doctype/warehouse/warehouse.json @@ -244,7 +244,7 @@ "idx": 1, "is_tree": 1, "links": [], - "modified": "2021-12-03 04:40:06.414630", + "modified": "2022-03-01 02:37:48.034944", "modified_by": "Administrator", "module": "Stock", "name": "Warehouse", @@ -301,5 +301,7 @@ "show_name_in_global_search": 1, "sort_field": "modified", "sort_order": "DESC", - "title_field": "warehouse_name" + "states": [], + "title_field": "warehouse_name", + "track_changes": 1 } \ No newline at end of file From ad2c64f3ff3cafa0abcee35639c9e5d4952bccdf Mon Sep 17 00:00:00 2001 From: Saqib Ansari Date: Tue, 1 Mar 2022 13:32:34 +0530 Subject: [PATCH 56/75] fix: debit credit difference case with rounding adjustment --- .../sales_invoice/test_sales_invoice.py | 50 +++++++++++++++++++ erpnext/accounts/general_ledger.py | 2 +- 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index 941061f2a22..83caab43b45 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -1595,6 +1595,56 @@ class TestSalesInvoice(unittest.TestCase): self.assertEqual(expected_values[gle.account][1], gle.debit) self.assertEqual(expected_values[gle.account][2], gle.credit) + def test_rounding_adjustment_3(self): + si = create_sales_invoice(do_not_save=True) + si.items = [] + for d in [(1122, 2), (1122.01, 1), (1122.01, 1)]: + si.append("items", { + "item_code": "_Test Item", + "gst_hsn_code": "999800", + "warehouse": "_Test Warehouse - _TC", + "qty": d[1], + "rate": d[0], + "income_account": "Sales - _TC", + "cost_center": "_Test Cost Center - _TC" + }) + for tax_account in ["_Test Account VAT - _TC", "_Test Account Service Tax - _TC"]: + si.append("taxes", { + "charge_type": "On Net Total", + "account_head": tax_account, + "description": tax_account, + "rate": 6, + "cost_center": "_Test Cost Center - _TC", + "included_in_print_rate": 1 + }) + si.save() + si.submit() + self.assertEqual(si.net_total, 4007.16) + self.assertEqual(si.grand_total, 4488.02) + self.assertEqual(si.total_taxes_and_charges, 480.86) + self.assertEqual(si.rounding_adjustment, -0.02) + + expected_values = dict((d[0], d) for d in [ + [si.debit_to, 4488.0, 0.0], + ["_Test Account Service Tax - _TC", 0.0, 240.43], + ["_Test Account VAT - _TC", 0.0, 240.43], + ["Sales - _TC", 0.0, 4007.15], + ["Round Off - _TC", 0.01, 0] + ]) + + gl_entries = frappe.db.sql("""select account, debit, credit + from `tabGL Entry` where voucher_type='Sales Invoice' and voucher_no=%s + order by account asc""", si.name, as_dict=1) + + debit_credit_diff = 0 + for gle in gl_entries: + self.assertEqual(expected_values[gle.account][0], gle.account) + self.assertEqual(expected_values[gle.account][1], gle.debit) + self.assertEqual(expected_values[gle.account][2], gle.credit) + debit_credit_diff += (gle.debit - gle.credit) + + self.assertEqual(debit_credit_diff, 0) + def test_sales_invoice_with_shipping_rule(self): from erpnext.accounts.doctype.shipping_rule.test_shipping_rule import create_shipping_rule diff --git a/erpnext/accounts/general_ledger.py b/erpnext/accounts/general_ledger.py index d24d56b4bbb..0cd5e86a8cf 100644 --- a/erpnext/accounts/general_ledger.py +++ b/erpnext/accounts/general_ledger.py @@ -274,7 +274,7 @@ def make_round_off_gle(gl_map, debit_credit_diff, precision): debit_credit_diff += flt(d.credit) round_off_account_exists = True - if round_off_account_exists and abs(debit_credit_diff) <= (1.0 / (10**precision)): + if round_off_account_exists and abs(debit_credit_diff) < (1.0 / (10**precision)): gl_map.remove(round_off_gle) return From 47fe87a72f40d1651951cecc97e9ae2ae0115fa4 Mon Sep 17 00:00:00 2001 From: Saqib Ansari Date: Tue, 1 Mar 2022 14:56:24 +0530 Subject: [PATCH 57/75] fix(test): flaky test_point_of_sale --- erpnext/tests/test_point_of_sale.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/tests/test_point_of_sale.py b/erpnext/tests/test_point_of_sale.py index 3299c8885f2..38f2c16d939 100644 --- a/erpnext/tests/test_point_of_sale.py +++ b/erpnext/tests/test_point_of_sale.py @@ -25,7 +25,7 @@ class TestPointOfSale(unittest.TestCase): Test Stock and Service Item Search. """ - pos_profile = make_pos_profile() + pos_profile = make_pos_profile(name="Test POS Profile for Search") item1 = make_item("Test Search Stock Item", {"is_stock_item": 1}) make_stock_entry( item_code="Test Search Stock Item", From 1d1d586d4dd356cf84edaed8a51f934194219d11 Mon Sep 17 00:00:00 2001 From: marination Date: Tue, 1 Mar 2022 15:42:34 +0530 Subject: [PATCH 58/75] test: Included sub assembly non-merging in test case --- .../doctype/production_plan/test_production_plan.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/erpnext/manufacturing/doctype/production_plan/test_production_plan.py b/erpnext/manufacturing/doctype/production_plan/test_production_plan.py index 59cc17a5eee..eeab788d5c5 100644 --- a/erpnext/manufacturing/doctype/production_plan/test_production_plan.py +++ b/erpnext/manufacturing/doctype/production_plan/test_production_plan.py @@ -301,6 +301,11 @@ class TestProductionPlan(FrappeTestCase): self.assertEqual(plan.sub_assembly_items[0].qty, 2.0) self.assertEqual(plan.sub_assembly_items[0].stock_qty, 2.0) + # change warehouse in one row, sub-assemblies should not merge + plan.po_items[0].warehouse = "Finished Goods - _TC" + plan.get_sub_assembly_items() + self.assertTrue(len(plan.sub_assembly_items), 2) + def test_pp_to_mr_customer_provided(self): " Test Material Request from Production Plan for Customer Provided Item." create_item('CUST-0987', is_customer_provided_item = 1, customer = '_Test Customer', is_purchase_item = 0) From 65bb72703029a38fedc02f2ad8f03ebfadf0b223 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Tue, 1 Mar 2022 17:25:42 +0530 Subject: [PATCH 59/75] fix: dont validate empty category --- .../sales_taxes_and_charges_template.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/erpnext/accounts/doctype/sales_taxes_and_charges_template/sales_taxes_and_charges_template.py b/erpnext/accounts/doctype/sales_taxes_and_charges_template/sales_taxes_and_charges_template.py index 1d30934df92..8043a1b66f2 100644 --- a/erpnext/accounts/doctype/sales_taxes_and_charges_template/sales_taxes_and_charges_template.py +++ b/erpnext/accounts/doctype/sales_taxes_and_charges_template/sales_taxes_and_charges_template.py @@ -55,5 +55,8 @@ def validate_disabled(doc): frappe.throw(_("Disabled template must not be default template")) def validate_for_tax_category(doc): + if not doc.tax_category: + return + if frappe.db.exists(doc.doctype, {"company": doc.company, "tax_category": doc.tax_category, "disabled": 0, "name": ["!=", doc.name]}): frappe.throw(_("A template with tax category {0} already exists. Only one template is allowed with each tax category").format(frappe.bold(doc.tax_category))) From 57f92df108ae6c33567a95be22a43015fe3178e5 Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Tue, 1 Mar 2022 20:50:36 +0530 Subject: [PATCH 60/75] fix: flake8 issues --- erpnext/hr/doctype/expense_claim/expense_claim.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/erpnext/hr/doctype/expense_claim/expense_claim.py b/erpnext/hr/doctype/expense_claim/expense_claim.py index 5146a5be907..fe04efbbab0 100644 --- a/erpnext/hr/doctype/expense_claim/expense_claim.py +++ b/erpnext/hr/doctype/expense_claim/expense_claim.py @@ -345,10 +345,10 @@ def get_advances(employee, advance_id=None): query = ( frappe.qb.from_(advance) - .select( - advance.name, advance.posting_date, advance.paid_amount, - advance.claimed_amount, advance.advance_account - ) + .select( + advance.name, advance.posting_date, advance.paid_amount, + advance.claimed_amount, advance.advance_account + ) ) if not advance_id: From 9988ec697f056b476ead3be1a371a82c6337be8e Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Tue, 1 Mar 2022 21:40:39 +0530 Subject: [PATCH 61/75] test: test advance filters in expense claim and cancelled status --- .../employee_advance/employee_advance.py | 1 + .../employee_advance/test_employee_advance.py | 38 +++++++++++++++++-- 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/erpnext/hr/doctype/employee_advance/employee_advance.py b/erpnext/hr/doctype/employee_advance/employee_advance.py index f63bb86129b..79d389d440c 100644 --- a/erpnext/hr/doctype/employee_advance/employee_advance.py +++ b/erpnext/hr/doctype/employee_advance/employee_advance.py @@ -27,6 +27,7 @@ class EmployeeAdvance(Document): def on_cancel(self): self.ignore_linked_doctypes = ('GL Entry') + self.set_status(update=True) def set_status(self, update=False): precision = self.precision("paid_amount") diff --git a/erpnext/hr/doctype/employee_advance/test_employee_advance.py b/erpnext/hr/doctype/employee_advance/test_employee_advance.py index 5f3a66a04fa..e3c1487ca2a 100644 --- a/erpnext/hr/doctype/employee_advance/test_employee_advance.py +++ b/erpnext/hr/doctype/employee_advance/test_employee_advance.py @@ -24,6 +24,9 @@ from erpnext.payroll.doctype.salary_structure.test_salary_structure import make_ class TestEmployeeAdvance(unittest.TestCase): + def setUp(self): + frappe.db.delete("Employee Advance") + def test_paid_amount_and_status(self): employee_name = make_employee("_T@employe.advance") advance = make_employee_advance(employee_name) @@ -58,8 +61,12 @@ class TestEmployeeAdvance(unittest.TestCase): self.assertEqual(advance.paid_amount, 0) self.assertEqual(advance.status, "Unpaid") - def test_claimed_and_returned_status(self): - # Claimed Status check, full amount claimed + advance.cancel() + advance.reload() + self.assertEqual(advance.status, "Cancelled") + + def test_claimed_status(self): + # CLAIMED Status check, full amount claimed payable_account = get_payable_account("_Test Company") claim = make_expense_claim(payable_account, 1000, 1000, "_Test Company", "Travel Expenses - _TC", do_not_submit=True) @@ -75,13 +82,26 @@ class TestEmployeeAdvance(unittest.TestCase): self.assertEqual(advance.claimed_amount, 1000) self.assertEqual(advance.status, "Claimed") + # advance should not be shown in claims + advances = get_advances(claim.employee) + advances = [entry.name for entry in advances] + self.assertTrue(advance.name not in advances) + # cancel claim; status should be Paid claim.cancel() advance.reload() self.assertEqual(advance.claimed_amount, 0) self.assertEqual(advance.status, "Paid") - # Partly Claimed and Returned status check + def test_partly_claimed_and_returned_status(self): + payable_account = get_payable_account("_Test Company") + claim = make_expense_claim(payable_account, 1000, 1000, "_Test Company", "Travel Expenses - _TC", do_not_submit=True) + + advance = make_employee_advance(claim.employee) + pe = make_payment_entry(advance) + pe.submit() + + # PARTLY CLAIMED AND RETURNED status check # 500 Claimed, 500 Returned claim = make_expense_claim(payable_account, 500, 500, "_Test Company", "Travel Expenses - _TC", do_not_submit=True) @@ -116,12 +136,22 @@ class TestEmployeeAdvance(unittest.TestCase): self.assertEqual(advance.return_amount, 500) self.assertEqual(advance.status, "Partly Claimed and Returned") - # Cancel return entry; status should change to Paid + # advance should not be shown in claims + advances = get_advances(claim.employee) + advances = [entry.name for entry in advances] + self.assertTrue(advance.name not in advances) + + # Cancel return entry; status should change to PAID entry.cancel() advance.reload() self.assertEqual(advance.return_amount, 0) self.assertEqual(advance.status, "Paid") + # advance should be shown in claims + advances = get_advances(claim.employee) + advances = [entry.name for entry in advances] + self.assertTrue(advance.name in advances) + def test_repay_unclaimed_amount_from_salary(self): employee_name = make_employee("_T@employe.advance") advance = make_employee_advance(employee_name, {"repay_unclaimed_amount_from_salary": 1}) From efc4b943f8f250de20c806a6dc923710b0f21885 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Wed, 2 Mar 2022 11:19:12 +0530 Subject: [PATCH 62/75] fix: ignore serial no during landed cost voucher --- .../test_landed_cost_voucher.py | 48 +++++++++++++++++++ erpnext/stock/stock_ledger.py | 2 +- 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py b/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py index dbaefc1e113..6dc4fee5697 100644 --- a/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py +++ b/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py @@ -11,6 +11,7 @@ from erpnext.accounts.doctype.account.test_account import create_account, get_in from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice from erpnext.accounts.utils import update_gl_entries_after from erpnext.assets.doctype.asset.test_asset import create_asset_category, create_fixed_asset_item +from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import ( get_gl_entries, make_purchase_receipt, @@ -177,6 +178,53 @@ class TestLandedCostVoucher(FrappeTestCase): self.assertEqual(serial_no.purchase_rate - serial_no_rate, 5.0) self.assertEqual(serial_no.warehouse, "Stores - TCP1") + def test_serialized_lcv_delivered(self): + """In some cases you'd want to deliver before you can know all the + landed costs, this should be allowed for serial nos too. + + Case: + - receipt a serial no @ X rate + - delivery the serial no @ X rate + - add LCV to receipt X + Y + - LCV should be successful + - delivery should reflect X+Y valuation. + """ + serial_no = "LCV_TEST_SR_NO" + item_code = "_Test Serialized Item" + warehouse = "Stores - TCP1" + + pr = make_purchase_receipt(company="_Test Company with perpetual inventory", + warehouse=warehouse, qty=1, rate=200, + item_code=item_code, serial_no=serial_no) + + serial_no_rate = frappe.db.get_value("Serial No", serial_no, "purchase_rate") + + # deliver it before creating LCV + dn = create_delivery_note(item_code=item_code, + company='_Test Company with perpetual inventory', warehouse='Stores - TCP1', + serial_no=serial_no, qty=1, rate=500, + cost_center = 'Main - TCP1', expense_account = "Cost of Goods Sold - TCP1") + + charges = 10 + create_landed_cost_voucher("Purchase Receipt", pr.name, pr.company, charges=charges) + + new_purchase_rate = serial_no_rate + charges + + serial_no = frappe.db.get_value("Serial No", serial_no, + ["warehouse", "purchase_rate"], as_dict=1) + + self.assertEqual(serial_no.purchase_rate, new_purchase_rate) + + stock_value_difference = frappe.db.get_value("Stock Ledger Entry", + filters={ + "voucher_no": dn.name, + "voucher_type": dn.doctype, + "is_cancelled": 0 # LCV cancels with same name. + }, + fieldname="stock_value_difference") + + # reposting should update the purchase rate in future delivery + self.assertEqual(stock_value_difference, -new_purchase_rate) def test_landed_cost_voucher_for_odd_numbers (self): pr = make_purchase_receipt(company="_Test Company with perpetual inventory", warehouse = "Stores - TCP1", supplier_warehouse = "Work in Progress - TCP1", do_not_save=True) diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py index 1b90086440f..1a80d93c674 100644 --- a/erpnext/stock/stock_ledger.py +++ b/erpnext/stock/stock_ledger.py @@ -39,7 +39,7 @@ def make_sl_entries(sl_entries, allow_negative_stock=False, via_landed_cost_vouc future_sle_exists(args, sl_entries) for sle in sl_entries: - if sle.serial_no: + if sle.serial_no and not via_landed_cost_voucher: validate_serial_no(sle) if cancel: From eb8495a401ceb9f1118bdb50f80a836a07994b9b Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Wed, 2 Mar 2022 12:01:51 +0530 Subject: [PATCH 63/75] docs: explain make_sl_entries arguments --- erpnext/stock/stock_ledger.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py index 1a80d93c674..69755529e5a 100644 --- a/erpnext/stock/stock_ledger.py +++ b/erpnext/stock/stock_ledger.py @@ -28,6 +28,16 @@ class SerialNoExistsInFutureTransaction(frappe.ValidationError): def make_sl_entries(sl_entries, allow_negative_stock=False, via_landed_cost_voucher=False): + """ Create SL entries from SL entry dicts + + args: + - allow_negative_stock: disable negative stock valiations if true + - via_landed_cost_voucher: landed cost voucher cancels and reposts + entries of purchase document. This flag is used to identify if + cancellation and repost is happening via landed cost voucher, in + such cases certain validations need to be ignored (like negative + stock) + """ from erpnext.controllers.stock_controller import future_sle_exists if sl_entries: cancel = sl_entries[0].get("is_cancelled") From 5d85b35f41d792879e47d63ec2bf45696ee6553c Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Wed, 2 Mar 2022 12:29:03 +0530 Subject: [PATCH 64/75] test: fix flaky bin value test --- .../doctype/purchase_receipt/test_purchase_receipt.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py index a24acb1bd83..fa28f2252de 100644 --- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py @@ -161,6 +161,15 @@ class TestPurchaseReceipt(FrappeTestCase): qty=abs(existing_bin_qty) ) + existing_bin_qty, existing_bin_stock_value = frappe.db.get_value( + "Bin", + { + "item_code": "_Test Item", + "warehouse": "_Test Warehouse - _TC" + }, + ["actual_qty", "stock_value"] + ) + pr = make_purchase_receipt() stock_value_difference = frappe.db.get_value( From 98f26e9cbb24c13657e357060f817f6ab3b58780 Mon Sep 17 00:00:00 2001 From: Sagar Vora Date: Wed, 2 Mar 2022 12:28:22 +0530 Subject: [PATCH 65/75] fix: handle `ImportError` when installing country fixtures --- erpnext/setup/doctype/company/company.py | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/erpnext/setup/doctype/company/company.py b/erpnext/setup/doctype/company/company.py index 95b1e8b9c63..158952484c6 100644 --- a/erpnext/setup/doctype/company/company.py +++ b/erpnext/setup/doctype/company/company.py @@ -3,7 +3,6 @@ import json -import os import frappe import frappe.defaults @@ -422,14 +421,14 @@ def get_name_with_abbr(name, company): return " - ".join(parts) def install_country_fixtures(company, country): - path = frappe.get_app_path('erpnext', 'regional', frappe.scrub(country)) - if os.path.exists(path.encode("utf-8")): - try: - module_name = "erpnext.regional.{0}.setup.setup".format(frappe.scrub(country)) - frappe.get_attr(module_name)(company, False) - except Exception as e: - frappe.log_error() - frappe.throw(_("Failed to setup defaults for country {0}. Please contact support.").format(frappe.bold(country))) + try: + module_name = "erpnext.regional.{0}.setup.setup".format(frappe.scrub(country)) + frappe.get_attr(module_name)(company, False) + except ImportError: + pass + except Exception: + frappe.log_error() + frappe.throw(_("Failed to setup defaults for country {0}. Please contact support.").format(frappe.bold(country))) def update_company_current_month_sales(company): From 89368ece4120411af5dd6cace9128e42cfd51f13 Mon Sep 17 00:00:00 2001 From: Sagar Vora Date: Wed, 2 Mar 2022 12:40:25 +0530 Subject: [PATCH 66/75] style: use f-string --- erpnext/setup/doctype/company/company.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/setup/doctype/company/company.py b/erpnext/setup/doctype/company/company.py index 158952484c6..36ad8fec9fd 100644 --- a/erpnext/setup/doctype/company/company.py +++ b/erpnext/setup/doctype/company/company.py @@ -422,7 +422,7 @@ def get_name_with_abbr(name, company): def install_country_fixtures(company, country): try: - module_name = "erpnext.regional.{0}.setup.setup".format(frappe.scrub(country)) + module_name = f"erpnext.regional.{frappe.scrub(country)}.setup.setup" frappe.get_attr(module_name)(company, False) except ImportError: pass From b3b7cdfb49cdc67e2dc3688b472deb5c2294addc Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Tue, 1 Mar 2022 14:33:46 +0530 Subject: [PATCH 67/75] test: FIFO transfer for multi-batch transaction --- .../test_stock_ledger_entry.py | 45 +++++++++++++++++-- 1 file changed, 42 insertions(+), 3 deletions(-) diff --git a/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py b/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py index 01d25b2e864..a182a6d7ef4 100644 --- a/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py +++ b/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py @@ -389,10 +389,13 @@ class TestStockLedgerEntry(FrappeTestCase): ) - def assertSLEs(self, doc, expected_sles): + def assertSLEs(self, doc, expected_sles, sle_filters=None): """ Compare sorted SLEs, useful for vouchers that create multiple SLEs for same line""" - sles = frappe.get_all("Stock Ledger Entry", fields=["*"], - filters={"voucher_no": doc.name, "voucher_type": doc.doctype, "is_cancelled":0}, + + filters = {"voucher_no": doc.name, "voucher_type": doc.doctype, "is_cancelled":0} + if sle_filters: + filters.update(sle_filters) + sles = frappe.get_all("Stock Ledger Entry", fields=["*"], filters=filters, order_by="timestamp(posting_date, posting_time), creation") for exp_sle, act_sle in zip(expected_sles, sles): @@ -665,6 +668,42 @@ class TestStockLedgerEntry(FrappeTestCase): {"actual_qty": -10, "stock_value_difference": -10*40, "stock_queue": []}, ])) + def test_fifo_dependent_consumption(self): + item = make_item("_TestFifoTransferRates") + source = "_Test Warehouse - _TC" + target = "Stores - _TC" + + rates = [10 * i for i in range(1, 20)] + + receipt = make_stock_entry(item_code=item.name, target=source, qty=10, do_not_save=True, rate=10) + for rate in rates[1:]: + row = frappe.copy_doc(receipt.items[0], ignore_no_copy=False) + row.basic_rate = rate + receipt.append("items", row) + + receipt.save() + receipt.submit() + + expected_queues = [] + for idx, rate in enumerate(rates, start=1): + expected_queues.append( + {"stock_queue": [[10, 10 * i] for i in range(1, idx + 1)]} + ) + self.assertSLEs(receipt, expected_queues) + + transfer = make_stock_entry(item_code=item.name, source=source, target=target, qty=10, do_not_save=True, rate=10) + for rate in rates[1:]: + row = frappe.copy_doc(transfer.items[0], ignore_no_copy=False) + row.basic_rate = rate + transfer.append("items", row) + + transfer.save() + transfer.submit() + + # same exact queue should be transferred + self.assertSLEs(transfer, expected_queues, sle_filters={"warehouse": target}) + + def create_repack_entry(**args): args = frappe._dict(args) repack = frappe.new_doc("Stock Entry") From ccd2ce56b1d6e24005e5a24b11c72e78adb0a4e4 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Tue, 1 Mar 2022 14:04:02 +0530 Subject: [PATCH 68/75] fix: FIFO valuation in case of multi-item entries --- erpnext/stock/stock_ledger.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py index 69755529e5a..97d54f8984e 100644 --- a/erpnext/stock/stock_ledger.py +++ b/erpnext/stock/stock_ledger.py @@ -448,8 +448,8 @@ class update_entries_after(object): return # Get dynamic incoming/outgoing rate - if not self.args.get("sle_id"): - self.get_dynamic_incoming_outgoing_rate(sle) + # XXX: performance regression + self.get_dynamic_incoming_outgoing_rate(sle) if get_serial_nos(sle.serial_no): self.get_serialized_values(sle) @@ -492,8 +492,8 @@ class update_entries_after(object): sle.doctype="Stock Ledger Entry" frappe.get_doc(sle).db_update() - if not self.args.get("sle_id"): - self.update_outgoing_rate_on_transaction(sle) + # XXX: performance regression + self.update_outgoing_rate_on_transaction(sle) def validate_negative_stock(self, sle): @@ -576,9 +576,8 @@ class update_entries_after(object): def update_rate_on_stock_entry(self, sle, outgoing_rate): frappe.db.set_value("Stock Entry Detail", sle.voucher_detail_no, "basic_rate", outgoing_rate) - # Update outgoing item's rate, recalculate FG Item's rate and total incoming/outgoing amount - if not sle.dependant_sle_voucher_detail_no: - self.recalculate_amounts_in_stock_entry(sle.voucher_no) + # XXX: performance regression + self.recalculate_amounts_in_stock_entry(sle.voucher_no) def recalculate_amounts_in_stock_entry(self, voucher_no): stock_entry = frappe.get_doc("Stock Entry", voucher_no, for_update=True) From 2f71c5bccaad5924a3047912761240681698d0ee Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Tue, 1 Mar 2022 17:04:10 +0530 Subject: [PATCH 69/75] test: repack FIFO rates --- .../test_stock_ledger_entry.py | 40 ++++++++++++++++++- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py b/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py index a182a6d7ef4..684a8d4d7c4 100644 --- a/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py +++ b/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py @@ -392,7 +392,7 @@ class TestStockLedgerEntry(FrappeTestCase): def assertSLEs(self, doc, expected_sles, sle_filters=None): """ Compare sorted SLEs, useful for vouchers that create multiple SLEs for same line""" - filters = {"voucher_no": doc.name, "voucher_type": doc.doctype, "is_cancelled":0} + filters = {"voucher_no": doc.name, "voucher_type": doc.doctype, "is_cancelled": 0} if sle_filters: filters.update(sle_filters) sles = frappe.get_all("Stock Ledger Entry", fields=["*"], filters=filters, @@ -694,7 +694,6 @@ class TestStockLedgerEntry(FrappeTestCase): transfer = make_stock_entry(item_code=item.name, source=source, target=target, qty=10, do_not_save=True, rate=10) for rate in rates[1:]: row = frappe.copy_doc(transfer.items[0], ignore_no_copy=False) - row.basic_rate = rate transfer.append("items", row) transfer.save() @@ -703,6 +702,43 @@ class TestStockLedgerEntry(FrappeTestCase): # same exact queue should be transferred self.assertSLEs(transfer, expected_queues, sle_filters={"warehouse": target}) + def test_fifo_multi_item_repack_consumption(self): + rm = make_item("_TestFifoRepackRM") + packed = make_item("_TestFifoRepackFinished") + warehouse = "_Test Warehouse - _TC" + + rates = [10 * i for i in range(1, 5)] + + receipt = make_stock_entry(item_code=rm.name, target=warehouse, qty=10, do_not_save=True, rate=10) + for rate in rates[1:]: + row = frappe.copy_doc(receipt.items[0], ignore_no_copy=False) + row.basic_rate = rate + receipt.append("items", row) + + receipt.save() + receipt.submit() + + repack = make_stock_entry(item_code=rm.name, source=warehouse, qty=10, + do_not_save=True, rate=10, purpose="Repack") + for rate in rates[1:]: + row = frappe.copy_doc(repack.items[0], ignore_no_copy=False) + repack.append("items", row) + + repack.append("items", { + "item_code": packed.name, + "t_warehouse": warehouse, + "qty": 1, + "transfer_qty": 1, + }) + + repack.save() + repack.submit() + + # same exact queue should be transferred + self.assertSLEs(repack, [ + {"incoming_rate": sum(rates) * 10} + ], sle_filters={"item_code": packed.name}) + def create_repack_entry(**args): args = frappe._dict(args) From 701878f60b4a9b60035295f23ae65973680b03e5 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Tue, 1 Mar 2022 18:08:29 +0530 Subject: [PATCH 70/75] revert "fix: FIFO valuation in case of multi-item entries" This reverts commit b8ee193d1a124668691b3d8181ce4e3bf612afe0. This is huge performance regression for large docs. --- erpnext/stock/stock_ledger.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py index 97d54f8984e..69755529e5a 100644 --- a/erpnext/stock/stock_ledger.py +++ b/erpnext/stock/stock_ledger.py @@ -448,8 +448,8 @@ class update_entries_after(object): return # Get dynamic incoming/outgoing rate - # XXX: performance regression - self.get_dynamic_incoming_outgoing_rate(sle) + if not self.args.get("sle_id"): + self.get_dynamic_incoming_outgoing_rate(sle) if get_serial_nos(sle.serial_no): self.get_serialized_values(sle) @@ -492,8 +492,8 @@ class update_entries_after(object): sle.doctype="Stock Ledger Entry" frappe.get_doc(sle).db_update() - # XXX: performance regression - self.update_outgoing_rate_on_transaction(sle) + if not self.args.get("sle_id"): + self.update_outgoing_rate_on_transaction(sle) def validate_negative_stock(self, sle): @@ -576,8 +576,9 @@ class update_entries_after(object): def update_rate_on_stock_entry(self, sle, outgoing_rate): frappe.db.set_value("Stock Entry Detail", sle.voucher_detail_no, "basic_rate", outgoing_rate) - # XXX: performance regression - self.recalculate_amounts_in_stock_entry(sle.voucher_no) + # Update outgoing item's rate, recalculate FG Item's rate and total incoming/outgoing amount + if not sle.dependant_sle_voucher_detail_no: + self.recalculate_amounts_in_stock_entry(sle.voucher_no) def recalculate_amounts_in_stock_entry(self, voucher_no): stock_entry = frappe.get_doc("Stock Entry", voucher_no, for_update=True) From 3638fbf06bfc492515096e4b4a065a52a495420a Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Tue, 1 Mar 2022 18:17:14 +0530 Subject: [PATCH 71/75] fix: repost items with repeating item-warehouses --- erpnext/controllers/stock_controller.py | 30 ++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py index c8e5eddfeac..8972c328796 100644 --- a/erpnext/controllers/stock_controller.py +++ b/erpnext/controllers/stock_controller.py @@ -507,13 +507,41 @@ class StockController(AccountsController): "voucher_no": self.name, "company": self.company }) - if future_sle_exists(args): + + if future_sle_exists(args) or repost_required_for_queue(self): item_based_reposting = cint(frappe.db.get_single_value("Stock Reposting Settings", "item_based_reposting")) if item_based_reposting: create_item_wise_repost_entries(voucher_type=self.doctype, voucher_no=self.name) else: create_repost_item_valuation_entry(args) +def repost_required_for_queue(doc: StockController) -> bool: + """check if stock document contains repeated item-warehouse with queue based valuation. + + if queue exists for repeated items then SLEs need to reprocessed in background again. + """ + + consuming_sles = frappe.db.get_all("Stock Ledger Entry", + filters={ + "voucher_type": doc.doctype, + "voucher_no": doc.name, + "actual_qty": ("<", 0), + "is_cancelled": 0 + }, + fields=["item_code", "warehouse", "stock_queue"] + ) + item_warehouses = [(sle.item_code, sle.warehouse) for sle in consuming_sles] + + unique_item_warehouses = set(item_warehouses) + + if len(unique_item_warehouses) == len(item_warehouses): + return False + + for sle in consuming_sles: + if sle.stock_queue != "[]": # using FIFO/LIFO valuation + return True + return False + @frappe.whitelist() def make_quality_inspections(doctype, docname, items): From b988046082b97e41c8b07eeaae35cfc2829e2bf3 Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Wed, 2 Mar 2022 14:15:22 +0530 Subject: [PATCH 72/75] fix(Timesheet): fetch exchange rate only if currency is set (#30057) --- erpnext/projects/doctype/timesheet/timesheet.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/projects/doctype/timesheet/timesheet.js b/erpnext/projects/doctype/timesheet/timesheet.js index f615f051f0c..453d46c7c4e 100644 --- a/erpnext/projects/doctype/timesheet/timesheet.js +++ b/erpnext/projects/doctype/timesheet/timesheet.js @@ -116,7 +116,7 @@ frappe.ui.form.on("Timesheet", { currency: function(frm) { let base_currency = frappe.defaults.get_global_default('currency'); - if (base_currency != frm.doc.currency) { + if (frm.doc.currency && (base_currency != frm.doc.currency)) { frappe.call({ method: "erpnext.setup.utils.get_exchange_rate", args: { From 55a966ec4137a5d60ef4351ea401e0fcbc5dff91 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Wed, 2 Mar 2022 14:49:45 +0530 Subject: [PATCH 73/75] chore: get stock reco qty from SR instead of SLE (#30059) [skip ci] --- .../stock_ledger_invariant_check.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/erpnext/stock/report/stock_ledger_invariant_check/stock_ledger_invariant_check.py b/erpnext/stock/report/stock_ledger_invariant_check/stock_ledger_invariant_check.py index 7826d344225..1ba2482935c 100644 --- a/erpnext/stock/report/stock_ledger_invariant_check/stock_ledger_invariant_check.py +++ b/erpnext/stock/report/stock_ledger_invariant_check/stock_ledger_invariant_check.py @@ -21,6 +21,7 @@ SLE_FIELDS = ( "stock_value", "stock_value_difference", "valuation_rate", + "voucher_detail_no", ) @@ -66,7 +67,9 @@ def add_invariant_check_fields(sles): balance_qty += sle.actual_qty balance_stock_value += sle.stock_value_difference if sle.voucher_type == "Stock Reconciliation" and not sle.batch_no: - balance_qty = sle.qty_after_transaction + balance_qty = frappe.db.get_value("Stock Reconciliation Item", sle.voucher_detail_no, "qty") + if balance_qty is None: + balance_qty = sle.qty_after_transaction sle.fifo_queue_qty = fifo_qty sle.fifo_stock_value = fifo_value From f8ac4c082a8512349187cecf058c8945231e7d52 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Wed, 2 Mar 2022 16:25:18 +0530 Subject: [PATCH 74/75] fix: remove dead dashboard links --- .../manufacturing/doctype/operation/operation_dashboard.py | 2 +- .../doctype/workstation/workstation_dashboard.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/erpnext/manufacturing/doctype/operation/operation_dashboard.py b/erpnext/manufacturing/doctype/operation/operation_dashboard.py index 4fbcf4954ec..9f7efa2b383 100644 --- a/erpnext/manufacturing/doctype/operation/operation_dashboard.py +++ b/erpnext/manufacturing/doctype/operation/operation_dashboard.py @@ -7,7 +7,7 @@ def get_data(): 'transactions': [ { 'label': _('Manufacture'), - 'items': ['BOM', 'Work Order', 'Job Card', 'Timesheet'] + 'items': ['BOM', 'Work Order', 'Job Card'] } ] } diff --git a/erpnext/manufacturing/doctype/workstation/workstation_dashboard.py b/erpnext/manufacturing/doctype/workstation/workstation_dashboard.py index bc481ca1926..1fa14940a40 100644 --- a/erpnext/manufacturing/doctype/workstation/workstation_dashboard.py +++ b/erpnext/manufacturing/doctype/workstation/workstation_dashboard.py @@ -11,9 +11,9 @@ def get_data(): }, { 'label': _('Transaction'), - 'items': ['Work Order', 'Job Card', 'Timesheet'] + 'items': ['Work Order', 'Job Card',] } ], 'disable_create_buttons': ['BOM', 'Routing', 'Operation', - 'Work Order', 'Job Card', 'Timesheet'] + 'Work Order', 'Job Card',] } From 9ef35ef7735683041d412f25eed9d7b59e2e8dd7 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Wed, 2 Mar 2022 16:32:48 +0530 Subject: [PATCH 75/75] fix: dont hardcode precision in routing Co-Authored-By: Suraj Shetty --- erpnext/manufacturing/doctype/routing/routing.js | 2 +- erpnext/manufacturing/doctype/routing/routing.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/erpnext/manufacturing/doctype/routing/routing.js b/erpnext/manufacturing/doctype/routing/routing.js index 33a313e32f5..b480c70ad56 100644 --- a/erpnext/manufacturing/doctype/routing/routing.js +++ b/erpnext/manufacturing/doctype/routing/routing.js @@ -17,7 +17,7 @@ frappe.ui.form.on('Routing', { }, calculate_operating_cost: function(frm, child) { - const operating_cost = flt(flt(child.hour_rate) * flt(child.time_in_mins) / 60, 2); + const operating_cost = flt(flt(child.hour_rate) * flt(child.time_in_mins) / 60, precision("operating_cost", child)); frappe.model.set_value(child.doctype, child.name, "operating_cost", operating_cost); } }); diff --git a/erpnext/manufacturing/doctype/routing/routing.py b/erpnext/manufacturing/doctype/routing/routing.py index 1c76634646d..b207906c5e3 100644 --- a/erpnext/manufacturing/doctype/routing/routing.py +++ b/erpnext/manufacturing/doctype/routing/routing.py @@ -20,7 +20,8 @@ class Routing(Document): for operation in self.operations: if not operation.hour_rate: operation.hour_rate = frappe.db.get_value("Workstation", operation.workstation, 'hour_rate') - operation.operating_cost = flt(flt(operation.hour_rate) * flt(operation.time_in_mins) / 60, 2) + operation.operating_cost = flt(flt(operation.hour_rate) * flt(operation.time_in_mins) / 60, + operation.precision("operating_cost")) def set_routing_id(self): sequence_id = 0