From 513099d6240d253b83ca3fb993cd33f3becc4a2a Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Sun, 17 May 2020 23:26:37 +0530 Subject: [PATCH 01/30] fix: Description for various fields --- .../loan_management/loan_management.json | 4 +- .../loan_application/loan_application.js | 23 ++++--- .../loan_interest_accrual.py | 65 ++++++++++--------- .../loan_repayment/loan_repayment.json | 4 +- .../loan_security_pledge.js | 23 ++++--- .../loan_security_type.json | 4 +- .../doctype/loan_type/loan_type.json | 7 +- 7 files changed, 72 insertions(+), 58 deletions(-) diff --git a/erpnext/loan_management/desk_page/loan_management/loan_management.json b/erpnext/loan_management/desk_page/loan_management/loan_management.json index f9ea978ed6..6cabff9443 100644 --- a/erpnext/loan_management/desk_page/loan_management/loan_management.json +++ b/erpnext/loan_management/desk_page/loan_management/loan_management.json @@ -3,7 +3,7 @@ { "hidden": 0, "label": "Loan", - "links": "[\n {\n \"description\": \"Loan Type for interest and penalty rates\",\n \"label\": \"Loan Type\",\n \"name\": \"Loan Type\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Loan Applications from customers and employees.\",\n \"label\": \"Loan Application\",\n \"name\": \"Loan Application\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Loans provided to customers and employees.\",\n \"label\": \"Loan\",\n \"name\": \"Loan\",\n \"type\": \"doctype\"\n }\n]" + "links": "[\n {\n \"description\": \"Loan Type for interest and penalty rates\",\n \"label\": \"Loan Type\",\n \"name\": \"Loan Type\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Loan Applications from customers and employees.\",\n \"label\": \"Loan Application\",\n \"name\": \"Loan Application\",\n \"type\": \"doctype\"\n },\n { \"dependencies\": [\n \"Loan Type\"\n ],\n \"description\": \"Loans provided to customers and employees.\",\n \"label\": \"Loan\",\n \"name\": \"Loan\",\n \"type\": \"doctype\"\n }\n]" }, { "hidden": 0, @@ -37,7 +37,7 @@ "idx": 0, "is_standard": 1, "label": "Loan Management", - "modified": "2020-04-02 11:28:51.380509", + "modified": "2020-05-16 08:01:27.784621", "modified_by": "Administrator", "module": "Loan Management", "name": "Loan Management", diff --git a/erpnext/loan_management/doctype/loan_application/loan_application.js b/erpnext/loan_management/doctype/loan_application/loan_application.js index 6cf47bf85c..b56fce1d7c 100644 --- a/erpnext/loan_management/doctype/loan_application/loan_application.js +++ b/erpnext/loan_management/doctype/loan_application/loan_application.js @@ -112,16 +112,19 @@ frappe.ui.form.on('Loan Application', { frappe.ui.form.on("Proposed Pledge", { loan_security: function(frm, cdt, cdn) { let row = locals[cdt][cdn]; - frappe.call({ - method: "erpnext.loan_management.doctype.loan_security_price.loan_security_price.get_loan_security_price", - args: { - loan_security: row.loan_security - }, - callback: function(r) { - frappe.model.set_value(cdt, cdn, 'loan_security_price', r.message); - frm.events.calculate_amounts(frm, cdt, cdn); - } - }) + + if (row.loan_security) { + frappe.call({ + method: "erpnext.loan_management.doctype.loan_security_price.loan_security_price.get_loan_security_price", + args: { + loan_security: row.loan_security + }, + callback: function(r) { + frappe.model.set_value(cdt, cdn, 'loan_security_price', r.message); + frm.events.calculate_amounts(frm, cdt, cdn); + } + }) + } }, amount: function(frm, cdt, cdn) { diff --git a/erpnext/loan_management/doctype/loan_interest_accrual/loan_interest_accrual.py b/erpnext/loan_management/doctype/loan_interest_accrual/loan_interest_accrual.py index 094b9c698c..9b486e805d 100644 --- a/erpnext/loan_management/doctype/loan_interest_accrual/loan_interest_accrual.py +++ b/erpnext/loan_management/doctype/loan_interest_accrual/loan_interest_accrual.py @@ -19,8 +19,8 @@ class LoanInterestAccrual(AccountsController): if not self.posting_date: self.posting_date = nowdate() - if not self.interest_amount: - frappe.throw(_("Interest Amount is mandatory")) + if not self.interest_amount and not self.payable_principal_amount: + frappe.throw(_("Interest Amount or Principal Amount is mandatory")) def on_submit(self): @@ -38,37 +38,38 @@ class LoanInterestAccrual(AccountsController): def make_gl_entries(self, cancel=0, adv_adj=0): gle_map = [] - gle_map.append( - self.get_gl_dict({ - "account": self.loan_account, - "party_type": self.applicant_type, - "party": self.applicant, - "against": self.interest_income_account, - "debit": self.interest_amount, - "debit_in_account_currency": self.interest_amount, - "against_voucher_type": "Loan", - "against_voucher": self.loan, - "remarks": _("Against Loan:") + self.loan, - "cost_center": erpnext.get_default_cost_center(self.company), - "posting_date": self.posting_date - }) - ) + if self.interest_amount: + gle_map.append( + self.get_gl_dict({ + "account": self.loan_account, + "party_type": self.applicant_type, + "party": self.applicant, + "against": self.interest_income_account, + "debit": self.interest_amount, + "debit_in_account_currency": self.interest_amount, + "against_voucher_type": "Loan", + "against_voucher": self.loan, + "remarks": _("Against Loan:") + self.loan, + "cost_center": erpnext.get_default_cost_center(self.company), + "posting_date": self.posting_date + }) + ) - gle_map.append( - self.get_gl_dict({ - "account": self.interest_income_account, - "party_type": self.applicant_type, - "party": self.applicant, - "against": self.loan_account, - "credit": self.interest_amount, - "credit_in_account_currency": self.interest_amount, - "against_voucher_type": "Loan", - "against_voucher": self.loan, - "remarks": _("Against Loan:") + self.loan, - "cost_center": erpnext.get_default_cost_center(self.company), - "posting_date": self.posting_date - }) - ) + gle_map.append( + self.get_gl_dict({ + "account": self.interest_income_account, + "party_type": self.applicant_type, + "party": self.applicant, + "against": self.loan_account, + "credit": self.interest_amount, + "credit_in_account_currency": self.interest_amount, + "against_voucher_type": "Loan", + "against_voucher": self.loan, + "remarks": _("Against Loan:") + self.loan, + "cost_center": erpnext.get_default_cost_center(self.company), + "posting_date": self.posting_date + }) + ) if gle_map: make_gl_entries(gle_map, cancel=cancel, adv_adj=adv_adj) diff --git a/erpnext/loan_management/doctype/loan_repayment/loan_repayment.json b/erpnext/loan_management/doctype/loan_repayment/loan_repayment.json index 789c129946..5942455919 100644 --- a/erpnext/loan_management/doctype/loan_repayment/loan_repayment.json +++ b/erpnext/loan_management/doctype/loan_repayment/loan_repayment.json @@ -173,7 +173,7 @@ { "fieldname": "references_section", "fieldtype": "Section Break", - "label": "References" + "label": "Payment References" }, { "fieldname": "reference_number", @@ -221,7 +221,7 @@ ], "is_submittable": 1, "links": [], - "modified": "2020-04-16 18:14:45.166754", + "modified": "2020-05-16 09:40:15.581165", "modified_by": "Administrator", "module": "Loan Management", "name": "Loan Repayment", diff --git a/erpnext/loan_management/doctype/loan_security_pledge/loan_security_pledge.js b/erpnext/loan_management/doctype/loan_security_pledge/loan_security_pledge.js index 82837b3dac..11c932ff1c 100644 --- a/erpnext/loan_management/doctype/loan_security_pledge/loan_security_pledge.js +++ b/erpnext/loan_management/doctype/loan_security_pledge/loan_security_pledge.js @@ -22,16 +22,19 @@ frappe.ui.form.on('Loan Security Pledge', { frappe.ui.form.on("Pledge", { loan_security: function(frm, cdt, cdn) { let row = locals[cdt][cdn]; - frappe.call({ - method: "erpnext.loan_management.doctype.loan_security_price.loan_security_price.get_loan_security_price", - args: { - loan_security: row.loan_security - }, - callback: function(r) { - frappe.model.set_value(cdt, cdn, 'loan_security_price', r.message); - frm.events.calculate_amounts(frm, cdt, cdn); - } - }); + + if (row.loan_security) { + frappe.call({ + method: "erpnext.loan_management.doctype.loan_security_price.loan_security_price.get_loan_security_price", + args: { + loan_security: row.loan_security + }, + callback: function(r) { + frappe.model.set_value(cdt, cdn, 'loan_security_price', r.message); + frm.events.calculate_amounts(frm, cdt, cdn); + } + }); + } }, qty: function(frm, cdt, cdn) { diff --git a/erpnext/loan_management/doctype/loan_security_type/loan_security_type.json b/erpnext/loan_management/doctype/loan_security_type/loan_security_type.json index f46b88cbca..871e82563a 100644 --- a/erpnext/loan_management/doctype/loan_security_type/loan_security_type.json +++ b/erpnext/loan_management/doctype/loan_security_type/loan_security_type.json @@ -29,6 +29,7 @@ "unique": 1 }, { + "description": "Haircut percentage is the percentage difference between market value of the Loan Security and the value ascribed to that Loan Security when used as collateral for that loan.", "fieldname": "haircut", "fieldtype": "Percent", "label": "Haircut %" @@ -46,13 +47,14 @@ "fieldtype": "Column Break" }, { + "description": "Loan To Value Ratio expresses the ratio of the loan amount to the value of the security pledged. A loan security shortfall will be triggered if this falls below the specified value for any loan ", "fieldname": "loan_to_value_ratio", "fieldtype": "Percent", "label": "Loan To Value Ratio" } ], "links": [], - "modified": "2020-04-28 14:06:49.046177", + "modified": "2020-05-16 09:38:45.988080", "modified_by": "Administrator", "module": "Loan Management", "name": "Loan Security Type", diff --git a/erpnext/loan_management/doctype/loan_type/loan_type.json b/erpnext/loan_management/doctype/loan_type/loan_type.json index 51c5cb98a6..90ae3b01bd 100644 --- a/erpnext/loan_management/doctype/loan_type/loan_type.json +++ b/erpnext/loan_management/doctype/loan_type/loan_type.json @@ -75,6 +75,7 @@ "reqd": 1 }, { + "description": "This account is used for booking loan repayments from the borrower and also disbursing loans to the borrower", "fieldname": "payment_account", "fieldtype": "Link", "label": "Payment Account", @@ -82,6 +83,7 @@ "reqd": 1 }, { + "description": "This account is capital account which is used to allocate capital for loan disbursal account ", "fieldname": "loan_account", "fieldtype": "Link", "label": "Loan Account", @@ -93,6 +95,7 @@ "fieldtype": "Column Break" }, { + "description": "This account will be used for booking loan interest accruals", "fieldname": "interest_income_account", "fieldtype": "Link", "label": "Interest Income Account", @@ -100,6 +103,7 @@ "reqd": 1 }, { + "description": "This account will be used for booking penalties levied due to delayed repayments", "fieldname": "penalty_income_account", "fieldtype": "Link", "label": "Penalty Income Account", @@ -108,6 +112,7 @@ }, { "default": "0", + "description": "If this is not checked the loan by default will be considered as a Demand Loan", "fieldname": "is_term_loan", "fieldtype": "Check", "label": "Is Term Loan" @@ -143,7 +148,7 @@ ], "is_submittable": 1, "links": [], - "modified": "2020-04-15 00:24:43.259963", + "modified": "2020-05-16 09:08:09.029921", "modified_by": "Administrator", "module": "Loan Management", "name": "Loan Type", From 5ccefdc08a1bbbfc0ff24b8f1ca3de835a4f52a9 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Sun, 17 May 2020 23:26:59 +0530 Subject: [PATCH 02/30] fix: Patch to update old loans --- erpnext/patches.txt | 1 + erpnext/patches/v13_0/update_old_loans.py | 83 +++++++++++++++++++++++ 2 files changed, 84 insertions(+) create mode 100644 erpnext/patches/v13_0/update_old_loans.py diff --git a/erpnext/patches.txt b/erpnext/patches.txt index ce0e4ac471..f3907f4b17 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -680,3 +680,4 @@ erpnext.patches.v12_0.fix_quotation_expired_status erpnext.patches.v12_0.update_appointment_reminder_scheduler_entry erpnext.patches.v12_0.retain_permission_rules_for_video_doctype erpnext.patches.v13_0.patch_to_fix_reverse_linking_in_additional_salary_encashment_and_incentive +erpnext.patches.v13_0.update_old_loans diff --git a/erpnext/patches/v13_0/update_old_loans.py b/erpnext/patches/v13_0/update_old_loans.py new file mode 100644 index 0000000000..e924f6234b --- /dev/null +++ b/erpnext/patches/v13_0/update_old_loans.py @@ -0,0 +1,83 @@ +from __future__ import unicode_literals +import frappe +from frappe.utils import nowdate +from erpnext.accounts.doctype.account.test_account import create_account +from erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual import process_loan_interest_accrual_for_term_loans +from erpnext.loan_management.doctype.loan.loan import make_repayment_entry + +def execute(): + + # Create a penalty account for loan types + + frappe.reload_doc('loan_management', 'doctype', 'loan_type') + frappe.reload_doc('loan_management', 'doctype', 'loan') + frappe.reload_doc('loan_management', 'doctype', 'repayment_schedule') + frappe.reload_doc('loan_management', 'doctype', 'process_loan_interest_accrual') + frappe.reload_doc('loan_management', 'doctype', 'loan_repayment') + frappe.reload_doc('loan_management', 'doctype', 'loan_repayment_detail') + frappe.reload_doc('loan_management', 'doctype', 'loan_interest_accrual') + frappe.reload_doc('accounts', 'doctype', 'gl_entry') + + updated_loan_types = [] + + loans = frappe.get_all('Loan', fields=['name', 'loan_type', 'company', 'status', 'mode_of_payment', + 'applicant_type', 'applicant', 'loan_account', 'payment_account', 'interest_income_account']) + + for loan in loans: + # Update details in Loan Types and Loan + loan_type_company = frappe.db.get_value('Loan Type', loan.loan_type, 'company') + + parent_income = frappe.get_value('Account', {'company': loan.company, + 'is_group': 1, 'root_type': 'Income'}) + + penalty_account = create_account(company=loan.company, account_type='Income Account', + account_name='Penalty Account', parent_account=parent_income) + + if not loan_type_company: + loan_type_doc = frappe.get_doc('Loan Type', loan.loan_type) + loan_type_doc.is_term_loan = 1 + loan_type_doc.company = loan.company + loan_type_doc.mode_of_payment = loan.mode_of_payment + loan_type_doc.payment_account = loan.payment_account + loan_type_doc.loan_account = loan.loan_account + loan_type_doc.interest_income_account = loan.interest_income_account + loan_type_doc.penalty_income_account = penalty_account + loan_type_doc.submit() + updated_loan_types.append(loan.loan_type) + + if loan.loan_type in updated_loan_types: + if loan.status == 'Fully Disbursed': + status = 'Disbursed' + elif loan.status == 'Repaid/Closed': + status = 'Closed' + else: + status = loan.status + + frappe.db.set_value('Loan', loan.name, { + 'is_term_loan': 1, + 'penalty_income_account': penalty_account, + 'status': status + }) + + process_loan_interest_accrual_for_term_loans(posting_date=nowdate(), loan_type=loan.loan_type, + loan=loan.name) + + payments = frappe.db.sql(''' SELECT j.name, a.debit, a.debit_in_account_currency, j.posting_date + FROM `tabJournal Entry` j, `tabJournal Entry Account` a + WHERE a.parent = j.name and a.reference_type='Loan' and a.reference_name = %s + and account = %s + ''', (loan.name, loan.loan_account), as_dict=1) + + for payment in payments: + repayment_entry = make_repayment_entry(loan.name, loan.loan_applicant_type, loan.applicant, + loan.loan_type, loan.company) + + repayment_entry.amount_paid = payment.debit_in_account_currency + repayment_entry.posting_date = payment.posting_date + repayment_entry.save() + repayment_entry.submit() + + jv = frappe.get_doc('Journal Entry', payment.name) + jv.flags.ignore_links = True + jv.cancel() + From 8cfa00920ed53f44bc9cb8ba05b46ca5778b376d Mon Sep 17 00:00:00 2001 From: Saqib Ansari Date: Wed, 29 Jul 2020 15:24:03 +0530 Subject: [PATCH 03/30] fix: cannot submit value adjustment with custom dimension --- .../asset_value_adjustment.py | 25 ++++++++++++++++--- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py b/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py index 155597e856..fd702c74c7 100644 --- a/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py +++ b/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py @@ -8,6 +8,7 @@ from frappe import _ from frappe.utils import flt, getdate, cint, date_diff, formatdate from erpnext.assets.doctype.asset.depreciation import get_depreciation_accounts from frappe.model.document import Document +from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_checks_for_pl_and_bs_accounts class AssetValueAdjustment(Document): def validate(self): @@ -53,17 +54,33 @@ class AssetValueAdjustment(Document): je.company = self.company je.remark = "Depreciation Entry against {0} worth {1}".format(self.asset, self.difference_amount) - je.append("accounts", { + credit_entry = { "account": accumulated_depreciation_account, "credit_in_account_currency": self.difference_amount, "cost_center": depreciation_cost_center or self.cost_center - }) + } - je.append("accounts", { + debit_entry = { "account": depreciation_expense_account, "debit_in_account_currency": self.difference_amount, "cost_center": depreciation_cost_center or self.cost_center - }) + } + + accounting_dimensions = get_checks_for_pl_and_bs_accounts() + + for dimension in accounting_dimensions: + if dimension.get('mandatory_for_bs'): + credit_entry.update({ + dimension['fieldname']: self.get(dimension['fieldname']) or dimension.get('default_dimension') + }) + + if dimension.get('mandatory_for_pl'): + debit_entry.update({ + dimension['fieldname']: self.get(dimension['fieldname']) or dimension.get('default_dimension') + }) + + je.append("accounts", credit_entry) + je.append("accounts", debit_entry) je.flags.ignore_permissions = True je.submit() From ab611d5fd8a4a87b0a07469e09e1efcdd97f89a7 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Fri, 7 Aug 2020 14:47:40 +0530 Subject: [PATCH 04/30] fix: GSTR 1 report for exports without payment of Tax --- erpnext/regional/report/gstr_1/gstr_1.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/erpnext/regional/report/gstr_1/gstr_1.py b/erpnext/regional/report/gstr_1/gstr_1.py index 8885b88c2a..282efe4790 100644 --- a/erpnext/regional/report/gstr_1/gstr_1.py +++ b/erpnext/regional/report/gstr_1/gstr_1.py @@ -131,6 +131,9 @@ class Gstr1Report(object): taxable_value += abs(net_amount) elif tax_rate: taxable_value += abs(net_amount) + elif not tax_rate and self.filters.get('type_of_business') == 'EXPORT' \ + and invoice_details.get('export_type') == "Without Payment of Tax": + taxable_value += abs(net_amount) row += [tax_rate or 0, taxable_value] From 8118dd9e62971db02c44183c7574bd730dc18eff Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Fri, 7 Aug 2020 14:52:50 +0530 Subject: [PATCH 05/30] fix: escape company field --- erpnext/accounts/party.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/accounts/party.py b/erpnext/accounts/party.py index 28a6519650..6f043a012e 100644 --- a/erpnext/accounts/party.py +++ b/erpnext/accounts/party.py @@ -611,7 +611,7 @@ def get_partywise_advanced_payment_amount(party_type, posting_date = None, futur cond = "posting_date <= '{0}'".format(posting_date) if company: - cond += "and company = '{0}'".format(company) + cond += "and company = '{0}'".format(frappe.db.escape(company)) data = frappe.db.sql(""" SELECT party, sum({0}) as amount FROM `tabGL Entry` From 1f3cc7553cab51571290ce1481ec43b5265cad15 Mon Sep 17 00:00:00 2001 From: Afshan Date: Fri, 7 Aug 2020 15:57:31 +0530 Subject: [PATCH 06/30] fix: grand_total assigment before reference --- erpnext/accounts/doctype/dunning/dunning.py | 1 + 1 file changed, 1 insertion(+) diff --git a/erpnext/accounts/doctype/dunning/dunning.py b/erpnext/accounts/doctype/dunning/dunning.py index 3e372affa1..1a6dbedf56 100644 --- a/erpnext/accounts/doctype/dunning/dunning.py +++ b/erpnext/accounts/doctype/dunning/dunning.py @@ -93,6 +93,7 @@ def resolve_dunning(doc, state): def calculate_interest_and_amount(posting_date, outstanding_amount, rate_of_interest, dunning_fee, overdue_days): interest_amount = 0 + grand_total = 0 if rate_of_interest: interest_per_year = flt(outstanding_amount) * flt(rate_of_interest) / 100 interest_amount = (interest_per_year * cint(overdue_days)) / 365 From bad269c3549adcef9021bd4c034d370ffae87257 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Fri, 7 Aug 2020 16:21:41 +0530 Subject: [PATCH 07/30] fix: Parent income account check --- erpnext/patches/v13_0/update_old_loans.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/erpnext/patches/v13_0/update_old_loans.py b/erpnext/patches/v13_0/update_old_loans.py index e924f6234b..77239429c5 100644 --- a/erpnext/patches/v13_0/update_old_loans.py +++ b/erpnext/patches/v13_0/update_old_loans.py @@ -1,5 +1,6 @@ from __future__ import unicode_literals import frappe +from frappe import _ from frappe.utils import nowdate from erpnext.accounts.doctype.account.test_account import create_account from erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual import process_loan_interest_accrual_for_term_loans @@ -27,11 +28,15 @@ def execute(): # Update details in Loan Types and Loan loan_type_company = frappe.db.get_value('Loan Type', loan.loan_type, 'company') - parent_income = frappe.get_value('Account', {'company': loan.company, - 'is_group': 1, 'root_type': 'Income'}) + group_income_account = frappe.get_value('Account', {'company': loan.company, + 'is_group': 1, 'root_type': 'Income', 'account_name': _('Indirect Income')}) + + if not group_income_account: + group_income_account = frappe.get_value('Account', {'company': loan.company, + 'is_group': 1, 'root_type': 'Income'}) penalty_account = create_account(company=loan.company, account_type='Income Account', - account_name='Penalty Account', parent_account=parent_income) + account_name='Penalty Account', parent_account=group_income_account) if not loan_type_company: loan_type_doc = frappe.get_doc('Loan Type', loan.loan_type) From 5ac2fd94f0fa361d496bcd2137a36c9433435261 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Sat, 8 Aug 2020 22:28:13 +0530 Subject: [PATCH 08/30] fix: Taxable value for RCM --- .../doctype/gstr_3b_report/gstr_3b_report.py | 24 +++++++++---------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.py b/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.py index 2d306ba172..fa5f5811eb 100644 --- a/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.py +++ b/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.py @@ -234,9 +234,6 @@ class GSTR3BReport(Document): self.report_dict[supply_type][supply_category][account_map.get(account_type)] += \ flt(tax_details.get((account_name, gst_category), {}).get("amount"), 2) - for k, v in iteritems(account_map): - txval -= self.report_dict.get(supply_type, {}).get(supply_category, {}).get(v, 0) - self.report_dict[supply_type][supply_category]["txval"] += flt(txval, 2) def set_inter_state_supply(self, inter_state_supply): @@ -256,7 +253,7 @@ class GSTR3BReport(Document): def get_total_taxable_value(self, doctype, reverse_charge): return frappe._dict(frappe.db.sql(""" - select gst_category, sum(base_grand_total) as total + select gst_category, sum(net_total) as total from `tab{doctype}` where docstatus = 1 and month(posting_date) = %s and year(posting_date) = %s and reverse_charge = %s @@ -309,26 +306,27 @@ class GSTR3BReport(Document): inter_state_supply_tax_mapping.setdefault(d.name, { 'place_of_supply': d.place_of_supply, 'taxable_value': d.net_total, + 'gst_category': d.gst_category, 'camt': 0.0, 'samt': 0.0, 'iamt': 0.0, 'csamt': 0.0 }) - if d.account_head in [d.cgst_account for d in self.account_heads]: + if d.account_head in [a.cgst_account for a in self.account_heads]: inter_state_supply_tax_mapping[d.name]['camt'] += d.tax_amount - if d.account_head in [d.sgst_account for d in self.account_heads]: + if d.account_head in [a.sgst_account for a in self.account_heads]: inter_state_supply_tax_mapping[d.name]['samt'] += d.tax_amount - if d.account_head in [d.igst_account for d in self.account_heads]: + if d.account_head in [a.igst_account for a in self.account_heads]: inter_state_supply_tax_mapping[d.name]['iamt'] += d.tax_amount - if d.account_head in [d.cess_account for d in self.account_heads]: + if d.account_head in [a.cess_account for a in self.account_heads]: inter_state_supply_tax_mapping[d.name]['csamt'] += d.tax_amount for key, value in iteritems(inter_state_supply_tax_mapping): - if d.place_of_supply: + if value.get('place_of_supply'): osup_det = self.report_dict["sup_details"]["osup_det"] osup_det["txval"] = flt(osup_det["txval"] + value['taxable_value'], 2) osup_det["iamt"] = flt(osup_det["iamt"] + value['iamt'], 2) @@ -336,15 +334,15 @@ class GSTR3BReport(Document): osup_det["samt"] = flt(osup_det["samt"] + value['samt'], 2) osup_det["csamt"] = flt(osup_det["csamt"] + value['csamt'], 2) - if state_number != d.place_of_supply.split("-")[0]: - inter_state_supply_details.setdefault((d.gst_category, d.place_of_supply), { + if state_number != value.get('place_of_supply').split("-")[0]: + inter_state_supply_details.setdefault((value.get('gst_category'), value.get('place_of_supply')), { "txval": 0.0, "pos": d.place_of_supply.split("-")[0], "iamt": 0.0 }) - inter_state_supply_details[(d.gst_category, d.place_of_supply)]['txval'] += value['taxable_value'] - inter_state_supply_details[(d.gst_category, d.place_of_supply)]['iamt'] += value['iamt'] + inter_state_supply_details[(value.get('gst_category'), value.get('place_of_supply'))]['txval'] += value['taxable_value'] + inter_state_supply_details[(value.get('gst_category'), value.get('place_of_supply'))]['iamt'] += value['iamt'] return inter_state_supply_details From d4ecf426b713f683cfc50df55384e9c79163903b Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Sat, 8 Aug 2020 22:33:18 +0530 Subject: [PATCH 09/30] fix: Place of supply fix --- erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.py b/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.py index fa5f5811eb..787d557e80 100644 --- a/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.py +++ b/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.py @@ -337,7 +337,7 @@ class GSTR3BReport(Document): if state_number != value.get('place_of_supply').split("-")[0]: inter_state_supply_details.setdefault((value.get('gst_category'), value.get('place_of_supply')), { "txval": 0.0, - "pos": d.place_of_supply.split("-")[0], + "pos": value.get('place_of_supply').split("-")[0], "iamt": 0.0 }) From a53f15ca35fd5c832885f975868014b7c30648e4 Mon Sep 17 00:00:00 2001 From: Mangesh-Khairnar Date: Sun, 9 Aug 2020 13:12:47 +0530 Subject: [PATCH 10/30] fix: remove mentions of display items in stock (#22963) --- erpnext/selling/page/point_of_sale/point_of_sale.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/erpnext/selling/page/point_of_sale/point_of_sale.py b/erpnext/selling/page/point_of_sale/point_of_sale.py index 9f8410f40b..83bd71d5f3 100644 --- a/erpnext/selling/page/point_of_sale/point_of_sale.py +++ b/erpnext/selling/page/point_of_sale/point_of_sale.py @@ -14,10 +14,9 @@ from six import string_types def get_items(start, page_length, price_list, item_group, search_value="", pos_profile=None): data = dict() warehouse = "" - display_items_in_stock = 0 if pos_profile: - warehouse, display_items_in_stock = frappe.db.get_value('POS Profile', pos_profile, ['warehouse', 'display_items_in_stock']) + warehouse = frappe.db.get_value('POS Profile', pos_profile, ['warehouse']) if not frappe.db.exists('Item Group', item_group): item_group = get_root_of('Item Group') @@ -85,7 +84,7 @@ def get_items(start, page_length, price_list, item_group, search_value="", pos_p item_price = item_prices.get(item_code) or {} item_stock_qty = get_stock_availability(item_code, warehouse) - if display_items_in_stock and not item_stock_qty: + if not item_stock_qty: pass else: row = {} From bc8a281f83640ccbefa9c8d2b99b05db6b9c25b2 Mon Sep 17 00:00:00 2001 From: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com> Date: Mon, 10 Aug 2020 11:00:08 +0530 Subject: [PATCH 11/30] fix: Subscripition link in Customer dashboard (#22960) Co-authored-by: Rucha Mahabal --- erpnext/selling/doctype/customer/customer_dashboard.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/erpnext/selling/doctype/customer/customer_dashboard.py b/erpnext/selling/doctype/customer/customer_dashboard.py index 22e30e3113..09e474dc2e 100644 --- a/erpnext/selling/doctype/customer/customer_dashboard.py +++ b/erpnext/selling/doctype/customer/customer_dashboard.py @@ -12,7 +12,8 @@ def get_data(): 'Payment Entry': 'party', 'Quotation': 'party_name', 'Opportunity': 'party_name', - 'Bank Account': 'party' + 'Bank Account': 'party', + 'Subscription': 'party' }, 'dynamic_links': { 'party_name': ['Customer', 'quotation_to'] From 5c0439f768d179f43e3169004fca14fe6e00a65d Mon Sep 17 00:00:00 2001 From: Prssanna Desai Date: Mon, 10 Aug 2020 11:12:52 +0530 Subject: [PATCH 12/30] fix: set correct default value from from date in downtime analysis report (#22903) Co-authored-by: Rucha Mahabal --- .../manufacturing/report/downtime_analysis/downtime_analysis.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/manufacturing/report/downtime_analysis/downtime_analysis.js b/erpnext/manufacturing/report/downtime_analysis/downtime_analysis.js index ff32dbed98..f6486743aa 100644 --- a/erpnext/manufacturing/report/downtime_analysis/downtime_analysis.js +++ b/erpnext/manufacturing/report/downtime_analysis/downtime_analysis.js @@ -8,7 +8,7 @@ frappe.query_reports["Downtime Analysis"] = { label: __("From Date"), fieldname:"from_date", fieldtype: "Datetime", - default: frappe.datetime.add_months(frappe.datetime.now_datetime(), -1), + default: frappe.datetime.convert_to_system_tz(frappe.datetime.add_months(frappe.datetime.now_datetime(), -1)), reqd: 1 }, { From 97ecf52d6fcba8c1be5e0a6fecc011e99b44e58f Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Mon, 10 Aug 2020 12:13:35 +0530 Subject: [PATCH 13/30] fix: failing Fees test --- erpnext/education/doctype/fees/test_fees.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/erpnext/education/doctype/fees/test_fees.py b/erpnext/education/doctype/fees/test_fees.py index b182992922..eedc2ae730 100644 --- a/erpnext/education/doctype/fees/test_fees.py +++ b/erpnext/education/doctype/fees/test_fees.py @@ -7,7 +7,7 @@ import frappe import unittest from frappe.utils import nowdate from frappe.utils.make_random import get_random - +from erpnext.education.doctype.program.test_program import make_program_and_linked_courses # test_records = frappe.get_test_records('Fees') @@ -15,6 +15,7 @@ class TestFees(unittest.TestCase): def test_fees(self): student = get_random("Student") + program = make_program_and_linked_courses("_Test Program 1", ["_Test Course 1", "_Test Course 2"]) fee = frappe.new_doc("Fees") fee.posting_date = nowdate() fee.due_date = nowdate() @@ -23,6 +24,7 @@ class TestFees(unittest.TestCase): fee.income_account = "Sales - _TC" fee.cost_center = "_Test Cost Center - _TC" fee.company = "_Test Company" + fee.program = program.name fee.extend("components", [ { From a07973cfa57f6bc0ebf367fa32af89e0ec8d4008 Mon Sep 17 00:00:00 2001 From: marination Date: Mon, 10 Aug 2020 12:39:42 +0530 Subject: [PATCH 14/30] fix: Creating opportunity from email --- erpnext/crm/doctype/opportunity/opportunity.py | 2 +- erpnext/public/js/communication.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/crm/doctype/opportunity/opportunity.py b/erpnext/crm/doctype/opportunity/opportunity.py index 1b071ea1b7..efaeca0e93 100644 --- a/erpnext/crm/doctype/opportunity/opportunity.py +++ b/erpnext/crm/doctype/opportunity/opportunity.py @@ -330,7 +330,7 @@ def make_opportunity_from_communication(communication, ignore_communication_link opportunity = frappe.get_doc({ "doctype": "Opportunity", "opportunity_from": opportunity_from, - "lead": lead + "party_name": lead }).insert(ignore_permissions=True) link_communication_to_document(doc, "Opportunity", opportunity.name, ignore_communication_links) diff --git a/erpnext/public/js/communication.js b/erpnext/public/js/communication.js index 5316eb45b5..9432d42175 100644 --- a/erpnext/public/js/communication.js +++ b/erpnext/public/js/communication.js @@ -13,7 +13,7 @@ frappe.ui.form.on("Communication", { frappe.confirm(__(confirm_msg, [__("Issue")]), () => { frm.trigger('make_issue_from_communication'); }) - }, "Make"); + }, "Create"); } if(!in_list(["Lead", "Opportunity"], frm.doc.reference_doctype)) { From d3d3db654ef4bedf308ee5563ccca55090fdf070 Mon Sep 17 00:00:00 2001 From: Anoop Date: Mon, 10 Aug 2020 13:21:12 +0530 Subject: [PATCH 15/30] fix: Inpatient Record - Transfer check-in time validation (#22958) * fix: inpatient transfer should not allow future checkin time * Update erpnext/healthcare/doctype/inpatient_record/inpatient_record.js Error message corrected Co-authored-by: Rucha Mahabal Co-authored-by: Rucha Mahabal --- .../doctype/inpatient_record/inpatient_record.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/erpnext/healthcare/doctype/inpatient_record/inpatient_record.js b/erpnext/healthcare/doctype/inpatient_record/inpatient_record.js index 971e166067..60f0f9d56d 100644 --- a/erpnext/healthcare/doctype/inpatient_record/inpatient_record.js +++ b/erpnext/healthcare/doctype/inpatient_record/inpatient_record.js @@ -134,7 +134,7 @@ let transfer_patient_dialog = function(frm) { {fieldtype: 'Link', label: 'Leave From', fieldname: 'leave_from', options: 'Healthcare Service Unit', reqd: 1, read_only:1}, {fieldtype: 'Link', label: 'Service Unit Type', fieldname: 'service_unit_type', options: 'Healthcare Service Unit Type'}, {fieldtype: 'Link', label: 'Transfer To', fieldname: 'service_unit', options: 'Healthcare Service Unit', reqd: 1}, - {fieldtype: 'Datetime', label: 'Check In', fieldname: 'check_in', reqd: 1} + {fieldtype: 'Datetime', label: 'Check In', fieldname: 'check_in', reqd: 1, default: frappe.datetime.now_datetime()} ], primary_action_label: __('Transfer'), primary_action : function() { @@ -147,7 +147,12 @@ let transfer_patient_dialog = function(frm) { if(dialog.get_value('service_unit')){ service_unit = dialog.get_value('service_unit'); } - if(!check_in){ + if(check_in > frappe.datetime.now_datetime()){ + frappe.msgprint({ + title: __('Not Allowed'), + message: __('Check-in time cannot be greater than the current time'), + indicator: 'red' + }); return; } frappe.call({ From f1091534cd5f269f7554dde44e5e453f0f8a068c Mon Sep 17 00:00:00 2001 From: Saqib Ansari Date: Mon, 10 Aug 2020 14:45:58 +0530 Subject: [PATCH 16/30] fix: [pos] minor bugs --- erpnext/accounts/doctype/pos_profile/pos_profile.js | 7 +------ erpnext/selling/page/point_of_sale/pos_controller.js | 7 ++++--- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/erpnext/accounts/doctype/pos_profile/pos_profile.js b/erpnext/accounts/doctype/pos_profile/pos_profile.js index ef431d7d41..8ec6a53626 100755 --- a/erpnext/accounts/doctype/pos_profile/pos_profile.js +++ b/erpnext/accounts/doctype/pos_profile/pos_profile.js @@ -31,8 +31,7 @@ frappe.ui.form.on('POS Profile', { frm.set_query("print_format", function() { return { filters: [ - ['Print Format', 'doc_type', '=', 'Sales Invoice'], - ['Print Format', 'print_format_type', '=', 'Jinja'], + ['Print Format', 'doc_type', '=', 'POS Invoice'] ] }; }); @@ -45,10 +44,6 @@ frappe.ui.form.on('POS Profile', { }; }); - frm.set_query("print_format", function() { - return { filters: { doc_type: "Sales Invoice", print_format_type: "JS"} }; - }); - frm.set_query('company_address', function(doc) { if(!doc.company) { frappe.throw(__('Please set Company')); diff --git a/erpnext/selling/page/point_of_sale/pos_controller.js b/erpnext/selling/page/point_of_sale/pos_controller.js index 483ef78d64..ae5471b900 100644 --- a/erpnext/selling/page/point_of_sale/pos_controller.js +++ b/erpnext/selling/page/point_of_sale/pos_controller.js @@ -35,7 +35,8 @@ erpnext.PointOfSale.Controller = class { create_opening_voucher() { const table_fields = [ { fieldname: "mode_of_payment", fieldtype: "Link", in_list_view: 1, label: "Mode of Payment", options: "Mode of Payment", reqd: 1 }, - { fieldname: "opening_amount", fieldtype: "Currency", in_list_view: 1, label: "Opening Amount", options: "company:company_currency", reqd: 1 } + { fieldname: "opening_amount", fieldtype: "Currency", default: 0, in_list_view: 1, label: "Opening Amount", + options: "company:company_currency", reqd: 1 } ]; const dialog = new frappe.ui.Dialog({ @@ -66,7 +67,7 @@ erpnext.PointOfSale.Controller = class { frappe.db.get_doc("POS Closing Entry", pos_closing_entry.name).then(({ payment_reconciliation }) => { dialog.fields_dict.balance_details.df.data = []; payment_reconciliation.forEach(pay => { - const { mode_of_payment, closing_amount } = pay; + const { mode_of_payment } = pay; dialog.fields_dict.balance_details.df.data.push({ mode_of_payment: mode_of_payment }); @@ -152,7 +153,7 @@ erpnext.PointOfSale.Controller = class { }, () => this.make_new_invoice(), () => frappe.dom.unfreeze(), - () => this.page.set_title(__('Point of Sale Beta')), + () => this.page.set_title(__('Point of Sale')), ]); } From 0fcb05a3aa399db7066637fd43576aa12f5df85c Mon Sep 17 00:00:00 2001 From: Marica Date: Mon, 10 Aug 2020 14:48:13 +0530 Subject: [PATCH 17/30] fix: Misleading filters on Item tax Template Link field (#22918) Co-authored-by: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com> Co-authored-by: Rucha Mahabal --- erpnext/controllers/queries.py | 5 ++++- erpnext/public/js/controllers/transaction.js | 3 +-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/erpnext/controllers/queries.py b/erpnext/controllers/queries.py index babc5bdd79..37b7e31e61 100644 --- a/erpnext/controllers/queries.py +++ b/erpnext/controllers/queries.py @@ -613,9 +613,12 @@ def get_tax_template(doctype, txt, searchfield, start, page_len, filters): if not taxes: return frappe.db.sql(""" SELECT name FROM `tabItem Tax Template` """) else: + valid_from = filters.get('valid_from') + valid_from = valid_from[1] if isinstance(valid_from, list) else valid_from + args = { 'item_code': filters.get('item_code'), - 'posting_date': filters.get('valid_from'), + 'posting_date': valid_from, 'tax_category': filters.get('tax_category'), 'company': filters.get('company') } diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js index 4e50f3d7f6..436a232a55 100644 --- a/erpnext/public/js/controllers/transaction.js +++ b/erpnext/public/js/controllers/transaction.js @@ -1821,7 +1821,6 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ }, set_query_for_item_tax_template: function(doc, cdt, cdn) { - var item = frappe.get_doc(cdt, cdn); if(!item.item_code) { frappe.throw(__("Please enter Item Code to get item taxes")); @@ -1829,7 +1828,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ let filters = { 'item_code': item.item_code, - 'valid_from': doc.transaction_date || doc.bill_date || doc.posting_date, + 'valid_from': ["<=", doc.transaction_date || doc.bill_date || doc.posting_date], 'item_group': item.item_group, } From 0f27500197f3fa4dbcd165626f7307d094126f39 Mon Sep 17 00:00:00 2001 From: marination Date: Mon, 10 Aug 2020 15:17:58 +0530 Subject: [PATCH 18/30] fix: Susbcription in Sales Taxes and Charges Dashboard --- .../sales_taxes_and_charges_template_dashboard.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/sales_taxes_and_charges_template/sales_taxes_and_charges_template_dashboard.py b/erpnext/accounts/doctype/sales_taxes_and_charges_template/sales_taxes_and_charges_template_dashboard.py index 0e9c808608..d825c6fd32 100644 --- a/erpnext/accounts/doctype/sales_taxes_and_charges_template/sales_taxes_and_charges_template_dashboard.py +++ b/erpnext/accounts/doctype/sales_taxes_and_charges_template/sales_taxes_and_charges_template_dashboard.py @@ -8,7 +8,7 @@ def get_data(): 'fieldname': 'taxes_and_charges', 'non_standard_fieldnames': { 'Tax Rule': 'sales_tax_template', - 'Subscription': 'tax_template', + 'Subscription': 'sales_tax_template', 'Restaurant': 'default_tax_template' }, 'transactions': [ From dbbb864ba511a3029389a2b16e7854c90bf5b53d Mon Sep 17 00:00:00 2001 From: Jai Chavan <40264279+jaichavan@users.noreply.github.com> Date: Mon, 10 Aug 2020 16:55:03 +0530 Subject: [PATCH 19/30] fix: Consistent capitalization --- erpnext/setup/doctype/company/company.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/setup/doctype/company/company.json b/erpnext/setup/doctype/company/company.json index 221044df3a..03703fd82e 100644 --- a/erpnext/setup/doctype/company/company.json +++ b/erpnext/setup/doctype/company/company.json @@ -242,7 +242,7 @@ { "fieldname": "default_warehouse_for_sales_return", "fieldtype": "Link", - "label": "Default warehouse for Sales Return", + "label": "Default Warehouse for Sales Return", "options": "Warehouse" }, { @@ -801,4 +801,4 @@ "sort_field": "modified", "sort_order": "ASC", "track_changes": 1 -} \ No newline at end of file +} From 19b51762efdf8602be556833344d759e67e940d6 Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Tue, 11 Aug 2020 13:12:00 +0530 Subject: [PATCH 20/30] fix: escape fields for Payroll Entry (#22994) --- erpnext/payroll/doctype/payroll_entry/payroll_entry.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/payroll/doctype/payroll_entry/payroll_entry.py b/erpnext/payroll/doctype/payroll_entry/payroll_entry.py index 554484febb..30ea432678 100644 --- a/erpnext/payroll/doctype/payroll_entry/payroll_entry.py +++ b/erpnext/payroll/doctype/payroll_entry/payroll_entry.py @@ -90,7 +90,7 @@ class PayrollEntry(Document): cond = '' for f in ['company', 'branch', 'department', 'designation']: if self.get(f): - cond += " and t1." + f + " = '" + self.get(f).replace("'", "\'") + "'" + cond += " and t1." + f + " = " + frappe.db.escape(self.get(f)) return cond From acc3d42cf0d208f0295c09ee36a18b82f705c076 Mon Sep 17 00:00:00 2001 From: Afshan <33727827+AfshanKhan@users.noreply.github.com> Date: Tue, 11 Aug 2020 14:40:44 +0530 Subject: [PATCH 21/30] fix: escape apostrophe in company name if exist (#22956) Co-authored-by: Rucha Mahabal --- erpnext/accounts/party.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/accounts/party.py b/erpnext/accounts/party.py index 6f043a012e..2f800bb2ab 100644 --- a/erpnext/accounts/party.py +++ b/erpnext/accounts/party.py @@ -611,7 +611,7 @@ def get_partywise_advanced_payment_amount(party_type, posting_date = None, futur cond = "posting_date <= '{0}'".format(posting_date) if company: - cond += "and company = '{0}'".format(frappe.db.escape(company)) + cond += "and company = {0}".format(frappe.db.escape(company)) data = frappe.db.sql(""" SELECT party, sum({0}) as amount FROM `tabGL Entry` From c992616d3514d8ba7994d1f01d4f85e563f4db1e Mon Sep 17 00:00:00 2001 From: Abhishek Balam Date: Tue, 11 Aug 2020 15:22:54 +0530 Subject: [PATCH 22/30] fix: change opportunity to 'Converted' when items not selected in opportunity itself for making quotation and sales order --- erpnext/crm/doctype/opportunity/opportunity.py | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/erpnext/crm/doctype/opportunity/opportunity.py b/erpnext/crm/doctype/opportunity/opportunity.py index efaeca0e93..e152850f17 100644 --- a/erpnext/crm/doctype/opportunity/opportunity.py +++ b/erpnext/crm/doctype/opportunity/opportunity.py @@ -119,11 +119,19 @@ class Opportunity(TransactionBase): and q.status not in ('Lost', 'Closed')""", self.name) def has_ordered_quotation(self): - return frappe.db.sql(""" - select q.name - from `tabQuotation` q, `tabQuotation Item` qi - where q.name = qi.parent and q.docstatus=1 and qi.prevdoc_docname =%s - and q.status = 'Ordered'""", self.name) + if not self.with_items: + return frappe.get_all('Quotation', + { + 'opportunity': self.name, + 'status': 'Ordered', + 'docstatus': 1 + }, 'name') + else: + return frappe.db.sql(""" + select q.name + from `tabQuotation` q, `tabQuotation Item` qi + where q.name = qi.parent and q.docstatus=1 and qi.prevdoc_docname =%s + and q.status = 'Ordered'""", self.name) def has_lost_quotation(self): lost_quotation = frappe.db.sql(""" From 3325be1d8760e004fc562908afe1690d9bf815a0 Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Tue, 11 Aug 2020 10:33:46 +0000 Subject: [PATCH 23/30] fix: spacing for slideshow (#22996) --- erpnext/public/less/website.less | 4 ++++ erpnext/templates/generators/item_group.html | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/erpnext/public/less/website.less b/erpnext/public/less/website.less index 57a0a332a9..ac878de105 100644 --- a/erpnext/public/less/website.less +++ b/erpnext/public/less/website.less @@ -297,6 +297,10 @@ margin-top: 30px; } +.item-group-slideshow { + margin-bottom: 1rem; +} + .product-image-img { border: 1px solid @light-border-color; border-radius: 3px; diff --git a/erpnext/templates/generators/item_group.html b/erpnext/templates/generators/item_group.html index 3f98453603..40a064fc76 100644 --- a/erpnext/templates/generators/item_group.html +++ b/erpnext/templates/generators/item_group.html @@ -4,7 +4,7 @@ {% block page_content %}
-
+
{% if slideshow %} {% include "templates/includes/slideshow.html" %} {% endif %} From ef3b82dae2e94e45ec88e0784975675bd8d8ef2d Mon Sep 17 00:00:00 2001 From: Abhishek Balam Date: Tue, 11 Aug 2020 16:05:02 +0530 Subject: [PATCH 24/30] fix(CRM): Move Source section above Follow Up section In Opportunity (#22974) * fix: move source section above follow up * fix: only moving source field to 1st section --- erpnext/crm/doctype/opportunity/opportunity.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/crm/doctype/opportunity/opportunity.json b/erpnext/crm/doctype/opportunity/opportunity.json index 545e2324ac..219ed890f5 100644 --- a/erpnext/crm/doctype/opportunity/opportunity.json +++ b/erpnext/crm/doctype/opportunity/opportunity.json @@ -16,6 +16,7 @@ "opportunity_from", "party_name", "customer_name", + "source", "column_break0", "title", "opportunity_type", @@ -49,7 +50,6 @@ "contact_email", "contact_mobile", "more_info", - "source", "campaign", "column_break1", "company", @@ -424,7 +424,7 @@ "icon": "fa fa-info-sign", "idx": 195, "links": [], - "modified": "2020-07-14 16:49:15.888503", + "modified": "2020-08-11 14:49:13.496297", "modified_by": "Administrator", "module": "CRM", "name": "Opportunity", From 2621016884a208d164e2b478e7945b1324872bec Mon Sep 17 00:00:00 2001 From: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com> Date: Tue, 11 Aug 2020 16:06:13 +0530 Subject: [PATCH 25/30] fix: Allocated advance amount for multi-currency payment (#22923) * fix: Allocated advance amount for multicurrency payment * fix: Get grand total based on party currency * fix: Remove unwanted code --- erpnext/controllers/accounts_controller.py | 36 +++++++++++++++++++--- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index 89c38c710b..66b5f3035d 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -479,7 +479,11 @@ class AccountsController(TransactionBase): if d.against_order: allocated_amount = flt(d.amount) else: - amount = self.rounded_total or self.grand_total + if self.get('party_account_currency') == self.company_currency: + amount = self.get('base_rounded_total') or self.base_grand_total + else: + amount = self.get('rounded_total') or self.grand_total + allocated_amount = min(amount - advance_allocated, d.amount) advance_allocated += flt(allocated_amount) @@ -802,10 +806,22 @@ class AccountsController(TransactionBase): self.payment_terms_template = '' return + party_account_currency = self.get('party_account_currency') + if not party_account_currency: + party_type, party = self.get_party() + + if party_type and party: + party_account_currency = get_party_account_currency(party_type, party, self.company) + posting_date = self.get("bill_date") or self.get("posting_date") or self.get("transaction_date") date = self.get("due_date") due_date = date or posting_date - grand_total = self.get("rounded_total") or self.grand_total + + if party_account_currency == self.company_currency: + grand_total = self.get("base_rounded_total") or self.base_grand_total + else: + grand_total = self.get("rounded_total") or self.grand_total + if self.doctype in ("Sales Invoice", "Purchase Invoice"): grand_total = grand_total - flt(self.write_off_amount) @@ -850,13 +866,25 @@ class AccountsController(TransactionBase): def validate_payment_schedule_amount(self): if self.doctype == 'Sales Invoice' and self.is_pos: return + party_account_currency = self.get('party_account_currency') + if not party_account_currency: + party_type, party = self.get_party() + + if party_type and party: + party_account_currency = get_party_account_currency(party_type, party, self.company) + if self.get("payment_schedule"): total = 0 for d in self.get("payment_schedule"): total += flt(d.payment_amount) - total = flt(total, self.precision("grand_total")) - grand_total = flt(self.get("rounded_total") or self.grand_total, self.precision('grand_total')) + if party_account_currency == self.company_currency: + total = flt(total, self.precision("base_grand_total")) + grand_total = flt(self.get("base_rounded_total") or self.base_grand_total, self.precision('base_grand_total')) + else: + total = flt(total, self.precision("grand_total")) + grand_total = flt(self.get("rounded_total") or self.grand_total, self.precision('grand_total')) + if self.get("total_advance"): grand_total -= self.get("total_advance") From 79d731dcd80b73fabeb5f510d4deddf8c5119806 Mon Sep 17 00:00:00 2001 From: Anupam Kumar Date: Tue, 11 Aug 2020 16:11:20 +0530 Subject: [PATCH 26/30] feat: Naming series for Sales/Purchase Return (#22942) * feat: adding return naming series * Update purchase_invoice.json Co-authored-by: Nabin Hait --- .../accounts/doctype/purchase_invoice/purchase_invoice.json | 6 +++--- erpnext/accounts/doctype/sales_invoice/sales_invoice.json | 5 ++--- erpnext/stock/doctype/delivery_note/delivery_note.json | 4 ++-- .../stock/doctype/purchase_receipt/purchase_receipt.json | 5 ++--- 4 files changed, 9 insertions(+), 11 deletions(-) diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json index 2e91c8ef19..d62e73b6ac 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json @@ -180,7 +180,7 @@ "no_copy": 1, "oldfieldname": "naming_series", "oldfieldtype": "Select", - "options": "ACC-PINV-.YYYY.-", + "options": "ACC-PINV-.YYYY.-\nACC-PINV-RET-.YYYY.-", "print_hide": 1, "reqd": 1, "set_only_once": 1 @@ -1334,7 +1334,7 @@ "idx": 204, "is_submittable": 1, "links": [], - "modified": "2020-08-03 12:46:01.411074", + "modified": "2020-08-03 23:20:04.466153", "modified_by": "Administrator", "module": "Accounts", "name": "Purchase Invoice", @@ -1396,4 +1396,4 @@ "timeline_field": "supplier", "title_field": "title", "track_changes": 1 -} \ No newline at end of file +} diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json index 4dc81e9087..31613e50b0 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json @@ -1,7 +1,6 @@ { "actions": [], "allow_import": 1, - "allow_workflow": 1, "autoname": "naming_series:", "creation": "2013-05-24 19:29:05", "doctype": "DocType", @@ -217,7 +216,7 @@ "no_copy": 1, "oldfieldname": "naming_series", "oldfieldtype": "Select", - "options": "ACC-SINV-.YYYY.-", + "options": "ACC-SINV-.YYYY.-\nACC-SINV-RET-.YYYY.-", "print_hide": 1, "reqd": 1, "set_only_once": 1 @@ -1947,7 +1946,7 @@ "idx": 181, "is_submittable": 1, "links": [], - "modified": "2020-07-18 05:07:16.725974", + "modified": "2020-08-03 23:31:12.675040", "modified_by": "Administrator", "module": "Accounts", "name": "Sales Invoice", diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.json b/erpnext/stock/doctype/delivery_note/delivery_note.json index 66efcf8cd8..ea385c8b2a 100644 --- a/erpnext/stock/doctype/delivery_note/delivery_note.json +++ b/erpnext/stock/doctype/delivery_note/delivery_note.json @@ -175,7 +175,7 @@ "no_copy": 1, "oldfieldname": "naming_series", "oldfieldtype": "Select", - "options": "MAT-DN-.YYYY.-", + "options": "MAT-DN-.YYYY.-\nMAT-DN-RET-.YYYY.-", "print_hide": 1, "reqd": 1, "set_only_once": 1 @@ -1255,7 +1255,7 @@ "idx": 146, "is_submittable": 1, "links": [], - "modified": "2020-07-18 05:13:55.580420", + "modified": "2020-08-03 23:18:47.739997", "modified_by": "Administrator", "module": "Stock", "name": "Delivery Note", diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json index 92e33ca64e..ce54fc883f 100755 --- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json +++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json @@ -1,7 +1,6 @@ { "actions": [], "allow_import": 1, - "allow_workflow": 1, "autoname": "naming_series:", "creation": "2013-05-21 16:16:39", "doctype": "DocType", @@ -160,7 +159,7 @@ "no_copy": 1, "oldfieldname": "naming_series", "oldfieldtype": "Select", - "options": "MAT-PRE-.YYYY.-", + "options": "MAT-PRE-.YYYY.-\nMAT-PR-RET-.YYYY.-", "print_hide": 1, "reqd": 1, "set_only_once": 1 @@ -1110,7 +1109,7 @@ "idx": 261, "is_submittable": 1, "links": [], - "modified": "2020-07-18 05:19:12.148115", + "modified": "2020-08-03 23:20:26.381024", "modified_by": "Administrator", "module": "Stock", "name": "Purchase Receipt", From 9f6d114265b2c8b156fb60491f90e2599ef50dee Mon Sep 17 00:00:00 2001 From: Abhishek Balam Date: Tue, 11 Aug 2020 16:16:05 +0530 Subject: [PATCH 27/30] fix: Change Source section name to 'Company Information' --- erpnext/crm/doctype/opportunity/opportunity.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/crm/doctype/opportunity/opportunity.json b/erpnext/crm/doctype/opportunity/opportunity.json index 219ed890f5..80e707cea7 100644 --- a/erpnext/crm/doctype/opportunity/opportunity.json +++ b/erpnext/crm/doctype/opportunity/opportunity.json @@ -344,7 +344,7 @@ "collapsible": 1, "fieldname": "more_info", "fieldtype": "Section Break", - "label": "Source", + "label": "Company Information", "oldfieldtype": "Section Break", "options": "fa fa-file-text" }, @@ -424,7 +424,7 @@ "icon": "fa fa-info-sign", "idx": 195, "links": [], - "modified": "2020-08-11 14:49:13.496297", + "modified": "2020-08-11 16:15:45.052240", "modified_by": "Administrator", "module": "CRM", "name": "Opportunity", From ee5b9c76912d193ae2fe4ea1ae062619fc1c8673 Mon Sep 17 00:00:00 2001 From: Abhishek Balam Date: Tue, 11 Aug 2020 16:23:47 +0530 Subject: [PATCH 28/30] feat(Accounting): Process Statement Of Accounts (#22901) * feat: Process Statement Of Accounts initial commit * fix: add jinja supported inputs for subject and body in email settings * feat: utils support in template, tested autoemail, fixed issues --- .../process_statement_of_accounts/__init__.py | 0 .../process_statement_of_accounts.html | 89 +++++ .../process_statement_of_accounts.js | 132 ++++++++ .../process_statement_of_accounts.json | 310 ++++++++++++++++++ .../process_statement_of_accounts.py | 271 +++++++++++++++ .../test_process_statement_of_accounts.py | 10 + .../__init__.py | 0 ...rocess_statement_of_accounts_customer.json | 47 +++ .../process_statement_of_accounts_customer.py | 10 + .../doctype/psoa_cost_center/__init__.py | 0 .../psoa_cost_center/psoa_cost_center.json | 30 ++ .../psoa_cost_center/psoa_cost_center.py | 10 + .../accounts/doctype/psoa_project/__init__.py | 0 .../doctype/psoa_project/psoa_project.json | 30 ++ .../doctype/psoa_project/psoa_project.py | 10 + erpnext/hooks.py | 3 +- 16 files changed, 951 insertions(+), 1 deletion(-) create mode 100644 erpnext/accounts/doctype/process_statement_of_accounts/__init__.py create mode 100644 erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.html create mode 100644 erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.js create mode 100644 erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.json create mode 100644 erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py create mode 100644 erpnext/accounts/doctype/process_statement_of_accounts/test_process_statement_of_accounts.py create mode 100644 erpnext/accounts/doctype/process_statement_of_accounts_customer/__init__.py create mode 100644 erpnext/accounts/doctype/process_statement_of_accounts_customer/process_statement_of_accounts_customer.json create mode 100644 erpnext/accounts/doctype/process_statement_of_accounts_customer/process_statement_of_accounts_customer.py create mode 100644 erpnext/accounts/doctype/psoa_cost_center/__init__.py create mode 100644 erpnext/accounts/doctype/psoa_cost_center/psoa_cost_center.json create mode 100644 erpnext/accounts/doctype/psoa_cost_center/psoa_cost_center.py create mode 100644 erpnext/accounts/doctype/psoa_project/__init__.py create mode 100644 erpnext/accounts/doctype/psoa_project/psoa_project.json create mode 100644 erpnext/accounts/doctype/psoa_project/psoa_project.py diff --git a/erpnext/accounts/doctype/process_statement_of_accounts/__init__.py b/erpnext/accounts/doctype/process_statement_of_accounts/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.html b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.html new file mode 100644 index 0000000000..e1ddeff61f --- /dev/null +++ b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.html @@ -0,0 +1,89 @@ +

{{ filters.party[0] }}

+

{{ _("Statement of Accounts") }}

+ +
+ {{ frappe.format(filters.from_date, 'Date')}} + {{ _("to") }} + {{ frappe.format(filters.to_date, 'Date')}} +
+ + + + + + + + + + + + + + {% for row in data %} + + {% if(row.posting_date) %} + + + + + + {% else %} + + + + + + {% endif %} + + + {% endfor %} + +
{{ _("Date") }}{{ _("Ref") }}{{ _("Party") }}{{ _("Debit") }}{{ _("Credit") }}{{ _("Balance (Dr - Cr)") }}
{{ frappe.format(row.posting_date, 'Date') }}{{ row.voucher_type }} +
{{ row.voucher_no }}
+ {% if not (filters.party or filters.account) %} + {{ row.party or row.account }} +
+ {% endif %} + + {{ _("Against") }}: {{ row.against }} +
{{ _("Remarks") }}: {{ row.remarks }} + {% if row.bill_no %} +
{{ _("Supplier Invoice No") }}: {{ row.bill_no }} + {% endif %} +
+ {{ frappe.utils.fmt_money(row.debit, filters.presentation_currency) }} + {{ frappe.utils.fmt_money(row.credit, filters.presentation_currency) }}{{ frappe.format(row.account, {fieldtype: "Link"}) or " " }} + {{ row.account and frappe.utils.fmt_money(row.debit, filters.presentation_currency) }} + + {{ row.account and frappe.utils.fmt_money(row.credit, filters.presentation_currency) }} + + {{ frappe.utils.fmt_money(row.balance, filters.presentation_currency) }} +
+

+{% if aging %} +

{{ _("Ageing Report Based On ") }} {{ aging.ageing_based_on }}

+
+ {{ _("Up to " ) }} {{ frappe.format(filters.to_date, 'Date')}} +
+
+ + + + + + + + + + + + + + + + + + +
30 Days60 Days90 Days120 Days
{{ aging.range1 }}{{ aging.range2 }}{{ aging.range3 }}{{ aging.range4 }}
+{% endif %} +

Printed On {{ frappe.format(frappe.utils.get_datetime(), 'Datetime') }}

\ No newline at end of file diff --git a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.js b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.js new file mode 100644 index 0000000000..7425132c46 --- /dev/null +++ b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.js @@ -0,0 +1,132 @@ +// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors +// For license information, please see license.txt + +frappe.ui.form.on('Process Statement Of Accounts', { + view_properties: function(frm) { + frappe.route_options = {doc_type: 'Customer'}; + frappe.set_route("Form", "Customize Form"); + }, + refresh: function(frm){ + if(!frm.doc.__islocal) { + frm.add_custom_button('Send Emails',function(){ + frappe.call({ + method: "erpnext.accounts.doctype.process_statement_of_accounts.process_statement_of_accounts.send_emails", + args: { + "document_name": frm.doc.name, + }, + callback: function(r) { + if(r && r.message) { + frappe.show_alert({message: __('Emails Queued'), indicator: 'blue'}); + } + else{ + frappe.msgprint('No Records for these settings.') + } + } + }); + }); + frm.add_custom_button('Download',function(){ + var url = frappe.urllib.get_full_url( + '/api/method/erpnext.accounts.doctype.process_statement_of_accounts.process_statement_of_accounts.download_statements?' + + 'document_name='+encodeURIComponent(frm.doc.name)) + $.ajax({ + url: url, + type: 'GET', + success: function(result) { + if(jQuery.isEmptyObject(result)){ + frappe.msgprint('No Records for these settings.'); + } + else{ + window.location = url; + } + } + }); + }); + } + }, + onload: function(frm) { + frm.set_query('currency', function(){ + return { + filters: { + 'enabled': 1 + } + } + }); + if(frm.doc.__islocal){ + frm.set_value('from_date', frappe.datetime.add_months(frappe.datetime.get_today(), -1)); + frm.set_value('to_date', frappe.datetime.get_today()); + } + }, + customer_collection: function(frm){ + frm.set_value('collection_name', ''); + if(frm.doc.customer_collection){ + frm.get_field('collection_name').set_label(frm.doc.customer_collection); + } + }, + frequency: function(frm){ + if(frm.doc.frequency != ''){ + frm.set_value('start_date', frappe.datetime.get_today()); + } + else{ + frm.set_value('start_date', ''); + } + }, + fetch_customers: function(frm){ + if(frm.doc.collection_name){ + frappe.call({ + method: "erpnext.accounts.doctype.process_statement_of_accounts.process_statement_of_accounts.fetch_customers", + args: { + 'customer_collection': frm.doc.customer_collection, + 'collection_name': frm.doc.collection_name, + 'primary_mandatory': frm.doc.primary_mandatory + }, + callback: function(r) { + if(!r.exc) { + if(r.message.length){ + frm.clear_table('customers'); + for (const customer of r.message){ + var row = frm.add_child('customers'); + row.customer = customer.name; + row.primary_email = customer.primary_email; + row.billing_email = customer.billing_email; + } + frm.refresh_field('customers'); + } + else{ + frappe.msgprint('No Customers found with selected options.'); + } + } + } + }); + } + else { + frappe.throw('Enter ' + frm.doc.customer_collection + ' name.'); + } + } +}); + +frappe.ui.form.on('Process Statement Of Accounts Customer', { + customer: function(frm, cdt, cdn){ + var row = locals[cdt][cdn]; + if (!row.customer){ + return; + } + frappe.call({ + method: 'erpnext.accounts.doctype.process_statement_of_accounts.process_statement_of_accounts.get_customer_emails', + args: { + 'customer_name': row.customer, + 'primary_mandatory': frm.doc.primary_mandatory + }, + callback: function(r){ + if(!r.exe){ + if(r.message.length){ + frappe.model.set_value(cdt, cdn, "primary_email", r.message[0]) + frappe.model.set_value(cdt, cdn, "billing_email", r.message[1]) + } + else { + return + } + } + } + }) + } +}); \ No newline at end of file diff --git a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.json b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.json new file mode 100644 index 0000000000..4be0e2ec06 --- /dev/null +++ b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.json @@ -0,0 +1,310 @@ +{ + "actions": [], + "allow_workflow": 1, + "autoname": "Prompt", + "creation": "2020-05-22 16:46:18.712954", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "section_break_11", + "from_date", + "company", + "account", + "group_by", + "cost_center", + "column_break_14", + "to_date", + "finance_book", + "currency", + "project", + "section_break_3", + "customer_collection", + "collection_name", + "fetch_customers", + "column_break_6", + "primary_mandatory", + "column_break_17", + "customers", + "preferences", + "orientation", + "section_break_14", + "include_ageing", + "ageing_based_on", + "section_break_1", + "enable_auto_email", + "section_break_18", + "frequency", + "filter_duration", + "column_break_21", + "start_date", + "section_break_33", + "subject", + "column_break_28", + "cc_to", + "section_break_30", + "body", + "help_text" + ], + "fields": [ + { + "fieldname": "frequency", + "fieldtype": "Select", + "label": "Frequency", + "options": "Weekly\nMonthly\nQuarterly" + }, + { + "fieldname": "company", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Company", + "options": "Company", + "reqd": 1 + }, + { + "depends_on": "eval:doc.enable_auto_email == 0;", + "fieldname": "from_date", + "fieldtype": "Date", + "label": "From Date", + "mandatory_depends_on": "eval:doc.frequency == '';" + }, + { + "depends_on": "eval:doc.enable_auto_email == 0;", + "fieldname": "to_date", + "fieldtype": "Date", + "label": "To Date", + "mandatory_depends_on": "eval:doc.frequency == '';" + }, + { + "fieldname": "cost_center", + "fieldtype": "Table MultiSelect", + "label": "Cost Center", + "options": "PSOA Cost Center" + }, + { + "fieldname": "project", + "fieldtype": "Table MultiSelect", + "label": "Project", + "options": "PSOA Project" + }, + { + "fieldname": "section_break_3", + "fieldtype": "Section Break", + "label": "Customers" + }, + { + "fieldname": "column_break_6", + "fieldtype": "Column Break" + }, + { + "fieldname": "section_break_11", + "fieldtype": "Section Break", + "label": "General Ledger Filters" + }, + { + "fieldname": "column_break_14", + "fieldtype": "Column Break" + }, + { + "fieldname": "column_break_17", + "fieldtype": "Section Break", + "hide_border": 1 + }, + { + "fieldname": "customer_collection", + "fieldtype": "Select", + "label": "Select Customers By", + "options": "\nCustomer Group\nTerritory\nSales Partner\nSales Person" + }, + { + "depends_on": "eval: doc.customer_collection !== ''", + "fieldname": "collection_name", + "fieldtype": "Dynamic Link", + "label": "Recipient", + "options": "customer_collection" + }, + { + "fieldname": "section_break_1", + "fieldtype": "Section Break", + "label": "Email Settings" + }, + { + "fieldname": "account", + "fieldtype": "Link", + "label": "Account", + "options": "Account" + }, + { + "fieldname": "finance_book", + "fieldtype": "Link", + "label": "Finance Book", + "options": "Finance Book" + }, + { + "fieldname": "preferences", + "fieldtype": "Section Break", + "label": "Print Preferences" + }, + { + "fieldname": "orientation", + "fieldtype": "Select", + "label": "Orientation", + "options": "Landscape\nPortrait" + }, + { + "default": "Today", + "fieldname": "start_date", + "fieldtype": "Date", + "label": "Start Date" + }, + { + "default": "Group by Voucher (Consolidated)", + "fieldname": "group_by", + "fieldtype": "Select", + "label": "Group By", + "options": "\nGroup by Voucher\nGroup by Voucher (Consolidated)" + }, + { + "fieldname": "currency", + "fieldtype": "Link", + "label": "Currency", + "options": "Currency" + }, + { + "default": "0", + "fieldname": "include_ageing", + "fieldtype": "Check", + "in_list_view": 1, + "label": "Include Ageing Summary" + }, + { + "default": "Due Date", + "depends_on": "eval:doc.include_ageing === 1", + "fieldname": "ageing_based_on", + "fieldtype": "Select", + "label": "Ageing Based On", + "options": "Due Date\nPosting Date" + }, + { + "default": "0", + "fieldname": "enable_auto_email", + "fieldtype": "Check", + "in_list_view": 1, + "label": "Enable Auto Email" + }, + { + "fieldname": "section_break_14", + "fieldtype": "Column Break", + "hide_border": 1 + }, + { + "depends_on": "eval: doc.enable_auto_email ==1", + "fieldname": "section_break_18", + "fieldtype": "Section Break", + "hide_border": 1 + }, + { + "fieldname": "column_break_21", + "fieldtype": "Column Break" + }, + { + "depends_on": "eval: doc.customer_collection !== ''", + "fieldname": "fetch_customers", + "fieldtype": "Button", + "label": "Fetch Customers", + "options": "fetch_customers", + "print_hide": 1, + "report_hide": 1 + }, + { + "default": "1", + "fieldname": "primary_mandatory", + "fieldtype": "Check", + "label": "Send To Primary Contact" + }, + { + "fieldname": "cc_to", + "fieldtype": "Link", + "label": "CC To", + "options": "User" + }, + { + "default": "1", + "fieldname": "filter_duration", + "fieldtype": "Int", + "label": "Filter Duration (Months)" + }, + { + "fieldname": "customers", + "fieldtype": "Table", + "label": "Customers", + "options": "Process Statement Of Accounts Customer", + "reqd": 1 + }, + { + "fieldname": "column_break_28", + "fieldtype": "Column Break" + }, + { + "fieldname": "section_break_30", + "fieldtype": "Section Break", + "hide_border": 1 + }, + { + "fieldname": "section_break_33", + "fieldtype": "Section Break", + "hide_border": 1 + }, + { + "fieldname": "help_text", + "fieldtype": "HTML", + "label": "Help Text", + "options": "
\n

Note

\n
    \n
  • \nYou can use Jinja tags in Subject and Body fields for dynamic values.\n
  • \n All fields in this doctype are available under the doc object and all fields for the customer to whom the mail will go to is available under the customer object.\n
\n

Examples

\n\n
    \n
  • Subject:

    Statement Of Accounts for {{ customer.name }}

  • \n
  • Body:

    \n
    Hello {{ customer.name }},
    PFA your Statement Of Accounts from {{ doc.from_date }} to {{ doc.to_date }}.
  • \n
\n" + }, + { + "fieldname": "subject", + "fieldtype": "Data", + "label": "Subject" + }, + { + "fieldname": "body", + "fieldtype": "Text Editor", + "label": "Body" + } + ], + "links": [], + "modified": "2020-08-08 08:47:09.185728", + "modified_by": "Administrator", + "module": "Accounts", + "name": "Process Statement Of Accounts", + "owner": "Administrator", + "permissions": [ + { + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Accounts User", + "share": 1, + "write": 1 + }, + { + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Accounts Manager", + "share": 1, + "write": 1 + } + ], + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1 +} \ No newline at end of file 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 new file mode 100644 index 0000000000..d50e4a8af9 --- /dev/null +++ b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py @@ -0,0 +1,271 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +from __future__ import unicode_literals +import frappe +from frappe.model.document import Document +from erpnext.accounts.report.general_ledger.general_ledger import execute as get_soa +from erpnext.accounts.report.accounts_receivable_summary.accounts_receivable_summary import execute as get_ageing +from frappe.core.doctype.communication.email import make + +from frappe.utils.print_format import report_to_pdf +from frappe.utils.pdf import get_pdf +from frappe.utils import today, add_days, add_months, getdate, format_date +from frappe.utils.jinja import validate_template + +import copy +from datetime import timedelta +from frappe.www.printview import get_print_style + +class ProcessStatementOfAccounts(Document): + def validate(self): + if not self.subject: + self.subject = 'Statement Of Accounts for {{ customer.name }}' + if not self.body: + self.body = 'Hello {{ customer.name }},
PFA your Statement Of Accounts from {{ doc.from_date }} to {{ doc.to_date }}.' + + validate_template(self.subject) + validate_template(self.body) + + if not self.customers: + frappe.throw(frappe._('Customers not selected.')) + + if self.enable_auto_email: + self.to_date = self.start_date + self.from_date = add_months(self.to_date, -1 * self.filter_duration) + + +def get_report_pdf(doc, consolidated=True): + statement_dict = {} + aging = '' + base_template_path = "frappe/www/printview.html" + template_path = "erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.html" + + for entry in doc.customers: + if doc.include_ageing: + ageing_filters = frappe._dict({ + 'company': doc.company, + 'report_date': doc.to_date, + 'ageing_based_on': doc.ageing_based_on, + 'range1': 30, + 'range2': 60, + 'range3': 90, + 'range4': 120, + 'customer': entry.customer + }) + col1, aging = get_ageing(ageing_filters) + aging[0]['ageing_based_on'] = doc.ageing_based_on + + tax_id = frappe.get_doc('Customer', entry.customer).tax_id + + filters= frappe._dict({ + 'from_date': doc.from_date, + '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, + 'party_type': 'Customer', + 'party': [entry.customer], + 'group_by': doc.group_by, + 'currency': doc.currency, + 'cost_center': [cc.cost_center_name for cc in doc.cost_center], + 'project': [p.project_name for p in doc.project], + 'show_opening_entries': 0, + 'include_default_book_entries': 0, + 'show_cancelled_entries': 1, + 'tax_id': tax_id if tax_id else None + }) + col, res = get_soa(filters) + + for x in [0, -2, -1]: + res[x]['account'] = res[x]['account'].replace("'","") + + if len(res) == 3: + continue + html = frappe.render_template(template_path, \ + {"filters": filters, "data": res, "aging": aging[0] if doc.include_ageing else None}) + html = frappe.render_template(base_template_path, {"body": html, \ + "css": get_print_style(), "title": "Statement For " + entry.customer}) + statement_dict[entry.customer] = html + if not bool(statement_dict): + return False + elif consolidated: + result = ''.join(list(statement_dict.values())) + return get_pdf(result, {'orientation': doc.orientation}) + else: + for customer, statement_html in statement_dict.items(): + statement_dict[customer]=get_pdf(statement_html, {'orientation': doc.orientation}) + return statement_dict + +def get_customers_based_on_territory_or_customer_group(customer_collection, collection_name): + fields_dict = { + 'Customer Group': 'customer_group', + 'Territory': 'territory', + } + collection = frappe.get_doc(customer_collection, collection_name) + selected = [customer.name for customer in frappe.get_list(customer_collection, filters=[ + ['lft', '>=', collection.lft], + ['rgt', '<=', collection.rgt] + ], + fields=['name'], + order_by='lft asc, rgt desc' + )] + return frappe.get_list('Customer', fields=['name', 'email_id'], \ + filters=[[fields_dict[customer_collection], 'IN', selected]]) + +def get_customers_based_on_sales_person(sales_person): + lft, rgt = frappe.db.get_value("Sales Person", + sales_person, ["lft", "rgt"]) + records = frappe.db.sql(""" + select distinct parent, parenttype + from `tabSales Team` steam + where parenttype = 'Customer' + and exists(select name from `tabSales Person` where lft >= %s and rgt <= %s and name = steam.sales_person) + """, (lft, rgt), as_dict=1) + sales_person_records = frappe._dict() + for d in records: + sales_person_records.setdefault(d.parenttype, set()).add(d.parent) + customers = frappe.get_list('Customer', fields=['name', 'email_id'], \ + filters=[['name', 'in', list(sales_person_records['Customer'])]]) + return customers + +def get_recipients_and_cc(customer, doc): + recipients = [] + for clist in doc.customers: + if clist.customer == customer: + recipients.append(clist.billing_email) + if doc.primary_mandatory and clist.primary_email: + recipients.append(clist.primary_email) + cc = [] + if doc.cc_to != '': + try: + cc=[frappe.get_value('User', doc.cc_to, 'email')] + except: + pass + + return recipients, cc + +def get_context(customer, doc): + template_doc = copy.deepcopy(doc) + del template_doc.customers + template_doc.from_date = format_date(template_doc.from_date) + template_doc.to_date = format_date(template_doc.to_date) + return { + 'doc': template_doc, + 'customer': frappe.get_doc('Customer', customer), + 'frappe': frappe.utils + } + +@frappe.whitelist() +def fetch_customers(customer_collection, collection_name, primary_mandatory): + customer_list = [] + customers = [] + + if customer_collection == 'Sales Person': + customers = get_customers_based_on_sales_person(collection_name) + if not bool(customers): + frappe.throw('No Customers found with selected options.') + else: + if customer_collection == 'Sales Partner': + customers = frappe.get_list('Customer', fields=['name', 'email_id'], \ + filters=[['default_sales_partner', '=', collection_name]]) + else: + customers = get_customers_based_on_territory_or_customer_group(customer_collection, collection_name) + + for customer in customers: + primary_email = customer.get('email_id') or '' + billing_email = get_customer_emails(customer.name, 1, billing_and_primary=False) + + if billing_email == '' or (primary_email == '' and int(primary_mandatory)): + continue + + customer_list.append({ + 'name': customer.name, + 'primary_email': primary_email, + 'billing_email': billing_email + }) + return customer_list + +@frappe.whitelist() +def get_customer_emails(customer_name, primary_mandatory, billing_and_primary=True): + billing_email = frappe.db.sql(""" + SELECT c.email_id FROM `tabContact` AS c JOIN `tabDynamic Link` AS l ON c.name=l.parent \ + WHERE l.link_doctype='Customer' and l.link_name='""" + customer_name + """' and \ + c.is_billing_contact=1 \ + order by c.creation desc""") + + if len(billing_email) == 0 or (billing_email[0][0] is None): + if billing_and_primary: + frappe.throw('No billing email found for customer: '+ customer_name) + else: + return '' + + if billing_and_primary: + primary_email = frappe.get_value('Customer', customer_name, 'email_id') + if primary_email is None and int(primary_mandatory): + frappe.throw('No primary email found for customer: '+ customer_name) + return [primary_email or '', billing_email[0][0]] + else: + return billing_email[0][0] or '' + +@frappe.whitelist() +def download_statements(document_name): + doc = frappe.get_doc('Process Statement Of Accounts', document_name) + report = get_report_pdf(doc) + if report: + frappe.local.response.filename = doc.name + '.pdf' + frappe.local.response.filecontent = report + frappe.local.response.type = "download" + +@frappe.whitelist() +def send_emails(document_name, from_scheduler=False): + doc = frappe.get_doc('Process Statement Of Accounts', document_name) + report = get_report_pdf(doc, consolidated=False) + + if report: + for customer, report_pdf in report.items(): + attachments = [{ + 'fname': customer + '.pdf', + 'fcontent': report_pdf + }] + + recipients, cc = get_recipients_and_cc(customer, doc) + context = get_context(customer, doc) + subject = frappe.render_template(doc.subject, context) + message = frappe.render_template(doc.body, context) + + frappe.enqueue( + queue='short', + method=frappe.sendmail, + recipients=recipients, + sender=frappe.session.user, + cc=cc, + subject=subject, + message=message, + now=True, + reference_doctype='Process Statement Of Accounts', + reference_name=document_name, + attachments=attachments + ) + + if doc.enable_auto_email and from_scheduler: + new_to_date = getdate(today()) + if doc.frequency == 'Weekly': + new_to_date = add_days(new_to_date, 7) + else: + new_to_date = add_months(new_to_date, 1 if doc.frequency == 'Monthly' else 3) + new_from_date = add_months(new_to_date, -1 * doc.filter_duration) + doc.add_comment('Comment', 'Emails sent on: ' + frappe.utils.format_datetime(frappe.utils.now())) + doc.db_set('to_date', new_to_date, commit=True) + doc.db_set('from_date', new_from_date, commit=True) + return True + else: + return False + +@frappe.whitelist() +def send_auto_email(): + selected = frappe.get_list('Process Statement Of Accounts', filters={'to_date': format_date(today()), 'enable_auto_email': 1}) + for entry in selected: + send_emails(entry.name, from_scheduler=True) + return True \ No newline at end of file diff --git a/erpnext/accounts/doctype/process_statement_of_accounts/test_process_statement_of_accounts.py b/erpnext/accounts/doctype/process_statement_of_accounts/test_process_statement_of_accounts.py new file mode 100644 index 0000000000..30efbb3683 --- /dev/null +++ b/erpnext/accounts/doctype/process_statement_of_accounts/test_process_statement_of_accounts.py @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors +# See license.txt +from __future__ import unicode_literals + +# import frappe +import unittest + +class TestProcessStatementOfAccounts(unittest.TestCase): + pass diff --git a/erpnext/accounts/doctype/process_statement_of_accounts_customer/__init__.py b/erpnext/accounts/doctype/process_statement_of_accounts_customer/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/erpnext/accounts/doctype/process_statement_of_accounts_customer/process_statement_of_accounts_customer.json b/erpnext/accounts/doctype/process_statement_of_accounts_customer/process_statement_of_accounts_customer.json new file mode 100644 index 0000000000..dd04dc1b3c --- /dev/null +++ b/erpnext/accounts/doctype/process_statement_of_accounts_customer/process_statement_of_accounts_customer.json @@ -0,0 +1,47 @@ +{ + "actions": [], + "allow_workflow": 1, + "creation": "2020-08-03 16:35:21.852178", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "customer", + "billing_email", + "primary_email" + ], + "fields": [ + { + "fieldname": "customer", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Customer", + "options": "Customer", + "reqd": 1 + }, + { + "fieldname": "primary_email", + "fieldtype": "Read Only", + "in_list_view": 1, + "label": "Primary Contact Email" + }, + { + "fieldname": "billing_email", + "fieldtype": "Read Only", + "in_list_view": 1, + "label": "Billing Email" + } + ], + "istable": 1, + "links": [], + "modified": "2020-08-03 22:55:38.875601", + "modified_by": "Administrator", + "module": "Accounts", + "name": "Process Statement Of Accounts Customer", + "owner": "Administrator", + "permissions": [], + "quick_entry": 1, + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1 +} \ No newline at end of file diff --git a/erpnext/accounts/doctype/process_statement_of_accounts_customer/process_statement_of_accounts_customer.py b/erpnext/accounts/doctype/process_statement_of_accounts_customer/process_statement_of_accounts_customer.py new file mode 100644 index 0000000000..1a760101db --- /dev/null +++ b/erpnext/accounts/doctype/process_statement_of_accounts_customer/process_statement_of_accounts_customer.py @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +from __future__ import unicode_literals +# import frappe +from frappe.model.document import Document + +class ProcessStatementOfAccountsCustomer(Document): + pass diff --git a/erpnext/accounts/doctype/psoa_cost_center/__init__.py b/erpnext/accounts/doctype/psoa_cost_center/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/erpnext/accounts/doctype/psoa_cost_center/psoa_cost_center.json b/erpnext/accounts/doctype/psoa_cost_center/psoa_cost_center.json new file mode 100644 index 0000000000..e292b60d68 --- /dev/null +++ b/erpnext/accounts/doctype/psoa_cost_center/psoa_cost_center.json @@ -0,0 +1,30 @@ +{ + "actions": [], + "creation": "2020-08-03 16:56:45.744905", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "cost_center_name" + ], + "fields": [ + { + "fieldname": "cost_center_name", + "fieldtype": "Link", + "label": "Cost Center", + "options": "Cost Center" + } + ], + "istable": 1, + "links": [], + "modified": "2020-08-03 16:56:45.744905", + "modified_by": "Administrator", + "module": "Accounts", + "name": "PSOA Cost Center", + "owner": "Administrator", + "permissions": [], + "quick_entry": 1, + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1 +} \ No newline at end of file diff --git a/erpnext/accounts/doctype/psoa_cost_center/psoa_cost_center.py b/erpnext/accounts/doctype/psoa_cost_center/psoa_cost_center.py new file mode 100644 index 0000000000..0aeef3ed3a --- /dev/null +++ b/erpnext/accounts/doctype/psoa_cost_center/psoa_cost_center.py @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +from __future__ import unicode_literals +# import frappe +from frappe.model.document import Document + +class PSOACostCenter(Document): + pass diff --git a/erpnext/accounts/doctype/psoa_project/__init__.py b/erpnext/accounts/doctype/psoa_project/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/erpnext/accounts/doctype/psoa_project/psoa_project.json b/erpnext/accounts/doctype/psoa_project/psoa_project.json new file mode 100644 index 0000000000..20a03eed96 --- /dev/null +++ b/erpnext/accounts/doctype/psoa_project/psoa_project.json @@ -0,0 +1,30 @@ +{ + "actions": [], + "creation": "2020-08-03 16:52:14.731978", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "project_name" + ], + "fields": [ + { + "fieldname": "project_name", + "fieldtype": "Link", + "label": "Project", + "options": "Project" + } + ], + "istable": 1, + "links": [], + "modified": "2020-08-03 16:53:39.219736", + "modified_by": "Administrator", + "module": "Accounts", + "name": "PSOA Project", + "owner": "Administrator", + "permissions": [], + "quick_entry": 1, + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1 +} \ No newline at end of file diff --git a/erpnext/accounts/doctype/psoa_project/psoa_project.py b/erpnext/accounts/doctype/psoa_project/psoa_project.py new file mode 100644 index 0000000000..f4a5dee975 --- /dev/null +++ b/erpnext/accounts/doctype/psoa_project/psoa_project.py @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +from __future__ import unicode_literals +# import frappe +from frappe.model.document import Document + +class PSOAProject(Document): + pass diff --git a/erpnext/hooks.py b/erpnext/hooks.py index 95a836fe65..463ad6c94b 100644 --- a/erpnext/hooks.py +++ b/erpnext/hooks.py @@ -322,7 +322,8 @@ scheduler_events = { "erpnext.crm.doctype.email_campaign.email_campaign.set_email_campaign_status", "erpnext.selling.doctype.quotation.quotation.set_expired_status", "erpnext.healthcare.doctype.patient_appointment.patient_appointment.update_appointment_status", - "erpnext.buying.doctype.supplier_quotation.supplier_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" ], "daily_long": [ "erpnext.setup.doctype.email_digest.email_digest.send", From d0ae92d4bd11603bbdd8c646b7b17ecd3708b8d3 Mon Sep 17 00:00:00 2001 From: Abhishek Balam Date: Tue, 11 Aug 2020 17:39:17 +0530 Subject: [PATCH 29/30] fix: moved company field, renamed to 'More Information' --- erpnext/crm/doctype/opportunity/opportunity.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/erpnext/crm/doctype/opportunity/opportunity.json b/erpnext/crm/doctype/opportunity/opportunity.json index 80e707cea7..5cd5233b2e 100644 --- a/erpnext/crm/doctype/opportunity/opportunity.json +++ b/erpnext/crm/doctype/opportunity/opportunity.json @@ -50,9 +50,9 @@ "contact_email", "contact_mobile", "more_info", + "company", "campaign", "column_break1", - "company", "transaction_date", "amended_from", "lost_reasons" @@ -344,7 +344,7 @@ "collapsible": 1, "fieldname": "more_info", "fieldtype": "Section Break", - "label": "Company Information", + "label": "More Information", "oldfieldtype": "Section Break", "options": "fa fa-file-text" }, @@ -424,7 +424,7 @@ "icon": "fa fa-info-sign", "idx": 195, "links": [], - "modified": "2020-08-11 16:15:45.052240", + "modified": "2020-08-11 17:34:35.066961", "modified_by": "Administrator", "module": "CRM", "name": "Opportunity", From ed6e9550ca12bce53e581ebee6b8a96f7f8aa79e Mon Sep 17 00:00:00 2001 From: Anurag Mishra <32095923+Anurag810@users.noreply.github.com> Date: Tue, 11 Aug 2020 18:04:42 +0530 Subject: [PATCH 30/30] fix: removed payroll from HR. (#22991) Co-authored-by: Rucha Mahabal --- erpnext/hr/desk_page/hr/hr.json | 17 +++++++++-------- erpnext/payroll/desk_page/payroll/payroll.json | 4 ++-- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/erpnext/hr/desk_page/hr/hr.json b/erpnext/hr/desk_page/hr/hr.json index 0fed8d322f..895cf7290c 100644 --- a/erpnext/hr/desk_page/hr/hr.json +++ b/erpnext/hr/desk_page/hr/hr.json @@ -78,7 +78,7 @@ "idx": 0, "is_standard": 1, "label": "HR", - "modified": "2020-06-16 19:20:50.976045", + "modified": "2020-08-11 17:04:38.655417", "modified_by": "Administrator", "module": "HR", "name": "HR", @@ -88,7 +88,7 @@ "pin_to_top": 0, "shortcuts": [ { - "color": "#9deca2", + "color": "#cef6d1", "format": "{} Active", "label": "Employee", "link_to": "Employee", @@ -96,18 +96,19 @@ "type": "DocType" }, { - "label": "Attendance", - "link_to": "Attendance", - "stats_filter": "", - "type": "DocType" - }, - { + "color": "#ffe8cd", "format": "{} Open", "label": "Leave Application", "link_to": "Leave Application", "stats_filter": "{\"status\":\"Open\"}", "type": "DocType" }, + { + "label": "Attendance", + "link_to": "Attendance", + "stats_filter": "", + "type": "DocType" + }, { "label": "Job Applicant", "link_to": "Job Applicant", diff --git a/erpnext/payroll/desk_page/payroll/payroll.json b/erpnext/payroll/desk_page/payroll/payroll.json index b5eac465c8..285e3b3a13 100644 --- a/erpnext/payroll/desk_page/payroll/payroll.json +++ b/erpnext/payroll/desk_page/payroll/payroll.json @@ -8,7 +8,7 @@ { "hidden": 0, "label": "Taxation", - "links": "[\n {\n \"label\": \"Payroll Period\",\n \"name\": \"Payroll Period\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n \n },\n {\n \"label\": \"Income Tax Slab\",\n \"name\": \"Income Tax Slab\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n \n },\n {\n \"label\": \"Employee Tax Exemption Declaration\",\n \"name\": \"Employee Tax Exemption Declaration\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n \n },\n {\n \"label\": \"Employee Tax Exemption Proof Submission\",\n \"name\": \"Employee Tax Exemption Proof Submission\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n \n },\n {\n \"label\": \"Employee Tax Exemption Category\",\n \"name\": \"Employee Tax Exemption Category\",\n \"type\": \"doctype\"\n \n },\n {\n \"label\": \"Employee Tax Exemption Sub Category\",\n \"name\": \"Employee Tax Exemption Sub Category\",\n \"type\": \"doctype\"\n \n }\n]" + "links": "[\n {\n \"label\": \"Payroll Period\",\n \"name\": \"Payroll Period\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n \n },\n {\n \"label\": \"Income Tax Slab\",\n \"name\": \"Income Tax Slab\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n \n },\n {\n \"label\": \"Employee Other Income\",\n \"name\": \"Employee Other Income\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n \n },\n {\n \"label\": \"Employee Tax Exemption Declaration\",\n \"name\": \"Employee Tax Exemption Declaration\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n \n },\n {\n \"label\": \"Employee Tax Exemption Proof Submission\",\n \"name\": \"Employee Tax Exemption Proof Submission\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n \n },\n {\n \"label\": \"Employee Tax Exemption Category\",\n \"name\": \"Employee Tax Exemption Category\",\n \"type\": \"doctype\"\n \n },\n {\n \"label\": \"Employee Tax Exemption Sub Category\",\n \"name\": \"Employee Tax Exemption Sub Category\",\n \"type\": \"doctype\"\n \n }\n]" }, { "hidden": 0, @@ -38,7 +38,7 @@ "idx": 0, "is_standard": 1, "label": "Payroll", - "modified": "2020-06-19 12:23:06.034046", + "modified": "2020-08-10 19:38:45.976209", "modified_by": "Administrator", "module": "Payroll", "name": "Payroll",