feat(Non Profit): 80G Certificates and Donations (#24848)

* feat(Non Profit): 80G Certificates and Donations

* fix(Membership): Generate Invoice for membership webhook only if automation is enabled (#24849)
diff --git a/erpnext/regional/doctype/tax_exemption_80g_certificate/__init__.py b/erpnext/regional/doctype/tax_exemption_80g_certificate/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/regional/doctype/tax_exemption_80g_certificate/__init__.py
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
new file mode 100644
index 0000000..54cde9c
--- /dev/null
+++ b/erpnext/regional/doctype/tax_exemption_80g_certificate/tax_exemption_80g_certificate.js
@@ -0,0 +1,67 @@
+// 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
new file mode 100644
index 0000000..9eee722
--- /dev/null
+++ b/erpnext/regional/doctype/tax_exemption_80g_certificate/tax_exemption_80g_certificate.json
@@ -0,0 +1,297 @@
+{
+ "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
new file mode 100644
index 0000000..d734a18
--- /dev/null
+++ b/erpnext/regional/doctype/tax_exemption_80g_certificate/tax_exemption_80g_certificate.py
@@ -0,0 +1,89 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe import _
+from frappe.model.document import Document
+from frappe.utils import getdate, flt, get_link_to_form
+from erpnext.accounts.utils import get_fiscal_year
+from frappe.contacts.doctype.address.address import get_company_address
+
+class TaxExemption80GCertificate(Document):
+	def validate(self):
+		self.validate_date()
+		self.validate_duplicates()
+		self.validate_company_details()
+		self.set_company_address()
+		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})
+			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)))
+
+	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 set_title(self):
+		if self.recipient == "Member":
+			self.title = self.member_name
+		else:
+			self.title = self.donor_name
+
+	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)],
+			'to_date': ['between', (fiscal_year.year_start_date, fiscal_year.year_end_date)],
+			'membership_status': ('!=', 'Cancelled')
+		}, ['from_date', 'amount', 'name', 'invoice', 'payment_id'])
+
+		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
new file mode 100644
index 0000000..346ebbf
--- /dev/null
+++ b/erpnext/regional/doctype/tax_exemption_80g_certificate/test_tax_exemption_80g_certificate.py
@@ -0,0 +1,101 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+import frappe
+import unittest
+from frappe.utils import getdate
+from erpnext.accounts.utils import get_fiscal_year
+from erpnext.non_profit.doctype.donation.test_donation import create_donor, create_mode_of_payment, create_donor_type
+from erpnext.non_profit.doctype.donation.donation import create_donation
+from erpnext.non_profit.doctype.membership.test_membership import setup_membership, make_membership
+from erpnext.non_profit.doctype.member.member import create_member
+
+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.assertEquals(certificate.company_pan_number, 'BBBTI3374C')
+		self.assertEquals(certificate.company_80g_number, 'NQ.CIT(E)I2018-19/DEL-IE28615-27062018/10087')
+
+		# check donation details
+		self.assertEquals(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.assertEquals(len(certificate.payments), 1)
+		self.assertEquals(certificate.payments[0].amount, membership.amount)
+		self.assertEquals(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
\ No newline at end of file
diff --git a/erpnext/regional/doctype/tax_exemption_80g_certificate_detail/__init__.py b/erpnext/regional/doctype/tax_exemption_80g_certificate_detail/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/regional/doctype/tax_exemption_80g_certificate_detail/__init__.py
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
new file mode 100644
index 0000000..dfa817d
--- /dev/null
+++ b/erpnext/regional/doctype/tax_exemption_80g_certificate_detail/tax_exemption_80g_certificate_detail.json
@@ -0,0 +1,66 @@
+{
+ "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
new file mode 100644
index 0000000..bdad798
--- /dev/null
+++ b/erpnext/regional/doctype/tax_exemption_80g_certificate_detail/tax_exemption_80g_certificate_detail.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+# import frappe
+from frappe.model.document import Document
+
+class TaxExemption80GCertificateDetail(Document):
+	pass
diff --git a/erpnext/regional/india/setup.py b/erpnext/regional/india/setup.py
index 5261984..40247f7 100644
--- a/erpnext/regional/india/setup.py
+++ b/erpnext/regional/india/setup.py
@@ -398,9 +398,9 @@
 	si_einvoice_fields = [
 		dict(fieldname='irn', label='IRN', fieldtype='Data', read_only=1, insert_after='customer', no_copy=1, print_hide=1,
 			depends_on='eval:in_list(["Registered Regular", "SEZ", "Overseas", "Deemed Export"], doc.gst_category) && doc.irn_cancelled === 0'),
-		
+
 		dict(fieldname='ack_no', label='Ack. No.', fieldtype='Data', read_only=1, hidden=1, insert_after='irn', no_copy=1, print_hide=1),
-		
+
 		dict(fieldname='ack_date', label='Ack. Date', fieldtype='Data', read_only=1, hidden=1, insert_after='ack_no', no_copy=1, print_hide=1),
 
 		dict(fieldname='irn_cancelled', label='IRN Cancelled', fieldtype='Check', no_copy=1, print_hide=1,
@@ -498,6 +498,14 @@
 				fieldtype='Link', options='Salary Component', insert_after='basic_component'),
 			dict(fieldname='arrear_component', label='Arrear Component',
 				fieldtype='Link', options='Salary Component', insert_after='hra_component'),
+			dict(fieldname='non_profit_section', label='Non Profit Settings',
+				fieldtype='Section Break', insert_after='asset_received_but_not_billed', 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='pan_details', label='PAN Number',
+				fieldtype='Data', insert_after='with_effect_from')
 		],
 		'Employee Tax Exemption Declaration':[
 			dict(fieldname='hra_section', label='HRA Exemption',
@@ -580,7 +588,15 @@
 				'options': '\nWith Payment of Tax\nWithout Payment of Tax'
 			}
 		],
-		"Member": [
+		'Member': [
+			{
+				'fieldname': 'pan_number',
+				'label': 'PAN Details',
+				'fieldtype': 'Data',
+				'insert_after': 'email_id'
+			}
+		],
+		'Donor': [
 			{
 				'fieldname': 'pan_number',
 				'label': 'PAN Details',
@@ -642,7 +658,7 @@
 		pass
 
 	docs = get_tds_details(accounts, fiscal_year)
-	
+
 	for d in docs:
 		try:
 			doc = frappe.get_doc(d)
@@ -660,7 +676,7 @@
 				fy_exist = [k for k in doc.get('rates') if k.get('fiscal_year')==fiscal_year]
 				if not fy_exist:
 					doc.append("rates", d.get('rates')[0])
-					
+
 			doc.flags.ignore_permissions = True
 			doc.flags.ignore_mandatory = True
 			doc.save()
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
new file mode 100644
index 0000000..a8da0bd
--- /dev/null
+++ b/erpnext/regional/print_format/80g_certificate_for_donation/80g_certificate_for_donation.json
@@ -0,0 +1,26 @@
+{
+ "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    <div class=\"letter-head\">{{ letter_head }}</div>\n{%- endif %}\n\n<div>\n    <h3 class=\"text-center\">{{ doc.company }} 80G Donor Certificate</h3>\n</div>\n<br><br>\n\n<div class=\"details\">\n    <p> <b>{{ _(\"Certificate No. : \") }}</b> {{ doc.name }} </p>\n    <p>\n    \t<b>{{ _(\"Date\") }} :</b> {{ doc.get_formatted(\"date\") }}<br>\n    </p>\n    <br><br>\n    \n    <div>\n\n        This is to confirm that the {{ doc.company }} received an amount of <b>{{doc.get_formatted(\"amount\")}}</b>\n        from <b>{{ doc.donor_name }}</b>\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        <br><br>\n        \n        <p>\n            We thank you for your contribution towards the corpus of the {{ doc.company }} and helping support our work.\n        </p>\n\n    </div>\n</div>\n\n<br><br>\n<p class=\"company-address text-left\"> {{doc.company_address_display }}</p>\n\n<div class=\"certificate-footer text-center\">\n    <p><i>Computer generated receipt - Does not require signature</i></p><br>\n    \n    {% if doc.company_pan_number %}\n    <p>\n        <b>{{ doc.company }}'s PAN Account No :</b> {{ doc.company_pan_number }}\n    <p><br>\n    {% endif %}\n    \n    <p>\n        <b>80G Number : </b> {{ doc.company_80g_number }}\n        {% if doc.company_80g_wef %}\n            ( w.e.f. {{ doc.get_formatted('company_80g_wef') }} )\n        {% endif %}\n    </p><br>\n</div>",
+ "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
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/regional/print_format/80g_certificate_for_donation/__init__.py
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
new file mode 100644
index 0000000..f1b15aa
--- /dev/null
+++ b/erpnext/regional/print_format/80g_certificate_for_membership/80g_certificate_for_membership.json
@@ -0,0 +1,26 @@
+{
+ "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    <div class=\"letter-head\">{{ letter_head }}</div>\n{%- endif %}\n\n<div>\n    <h3 class=\"text-center\">{{ doc.company }} Members 80G Donor Certificate</h3>\n    <h3 class=\"text-center\">Financial Cycle {{ doc.fiscal_year }}</h3>\n</div>\n<br><br>\n\n<div class=\"details\">\n    <p> <b>{{ _(\"Certificate No. : \") }}</b> {{ doc.name }} </p>\n    <p>\n    \t<b>{{ _(\"Date\") }} :</b> {{ doc.get_formatted(\"date\") }}<br>\n    </p>\n    <br><br>\n    \n    <div>\n        This is to confirm that the {{ doc.company }} received a total amount of <b>{{doc.get_formatted(\"total\")}}</b>\n        from <b>{{ doc.member_name }}</b>\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        <br><br>\n        <table class=\"table table-bordered table-condensed\">\n        \t<thead>\n        \t\t<tr>\n        \t\t\t<th >{{ _(\"Date\") }}</th>\n        \t\t\t<th class=\"text-right\">{{ _(\"Amount\") }}</th>\n        \t\t\t<th class=\"text-right\">{{ _(\"Invoice ID\") }}</th>\n        \t\t</tr>\n        \t</thead>\n        \t<tbody>\n        \t\t{%- for payment in doc.payments -%}\n        \t\t<tr>\n        \t\t\t<td> {{ payment.date }} </td>\n        \t\t\t<td class=\"text-right\">{{ payment.get_formatted(\"amount\") }}</td>\n        \t\t\t<td class=\"text-right\">{{ payment.invoice_id }}</td>\n        \t\t</tr>\n        \t\t{%- endfor -%}\n        \t</tbody>\n        </table>\n        \n        <br>\n        \n        <p>\n            We thank you for your contribution towards the corpus of the {{ doc.company }} and helping support our work.\n        </p>\n\n    </div>\n</div>\n\n<br><br>\n<p class=\"company-address text-left\"> {{doc.company_address_display }}</p>\n\n<div class=\"certificate-footer text-center\">\n    <p><i>Computer generated receipt - Does not require signature</i></p><br>\n    \n    {% if doc.company_pan_number %}\n    <p>\n        <b>{{ doc.company }}'s PAN Account No :</b> {{ doc.company_pan_number }}\n    <p><br>\n    {% endif %}\n    \n    <p>\n        <b>80G Number : </b> {{ doc.company_80g_number }}\n        {% if doc.company_80g_wef %}\n            ( w.e.f. {{ doc.get_formatted('company_80g_wef') }} )\n        {% endif %}\n    </p><br>\n</div>",
+ "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
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/regional/print_format/80g_certificate_for_membership/__init__.py