Merge branch 'develop' into trim-custom-field-length
diff --git a/erpnext/accounts/doctype/fiscal_year_company/fiscal_year_company.json b/erpnext/accounts/doctype/fiscal_year_company/fiscal_year_company.json
index 3eb0d74..67acb26 100644
--- a/erpnext/accounts/doctype/fiscal_year_company/fiscal_year_company.json
+++ b/erpnext/accounts/doctype/fiscal_year_company/fiscal_year_company.json
@@ -1,63 +1,33 @@
{
- "allow_copy": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "beta": 0,
- "creation": "2014-10-02 13:35:44.155278",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "Setup",
- "editable_grid": 1,
+ "actions": [],
+ "creation": "2014-10-02 13:35:44.155278",
+ "doctype": "DocType",
+ "document_type": "Setup",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "company"
+ ],
"fields": [
{
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "fieldname": "company",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_list_view": 1,
- "label": "Company",
- "length": 0,
- "no_copy": 0,
- "options": "Company",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "ignore_user_permissions": 1,
+ "in_list_view": 1,
+ "label": "Company",
+ "options": "Company"
}
- ],
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
-
- "is_submittable": 0,
- "issingle": 0,
- "istable": 1,
- "max_attachments": 0,
- "modified": "2016-07-11 03:28:00.505946",
- "modified_by": "Administrator",
- "module": "Accounts",
- "name": "Fiscal Year Company",
- "name_case": "",
- "owner": "Administrator",
- "permissions": [],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_seen": 0
+ ],
+ "index_web_pages_for_search": 1,
+ "istable": 1,
+ "links": [],
+ "modified": "2021-09-28 18:01:53.495929",
+ "modified_by": "Administrator",
+ "module": "Accounts",
+ "name": "Fiscal Year Company",
+ "owner": "Administrator",
+ "permissions": [],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.json b/erpnext/accounts/doctype/journal_entry/journal_entry.json
index b7bbb74..20678d7 100644
--- a/erpnext/accounts/doctype/journal_entry/journal_entry.json
+++ b/erpnext/accounts/doctype/journal_entry/journal_entry.json
@@ -13,10 +13,12 @@
"voucher_type",
"naming_series",
"finance_book",
+ "tax_withholding_category",
"column_break1",
"from_template",
"company",
"posting_date",
+ "apply_tds",
"2_add_edit_gl_entries",
"accounts",
"section_break99",
@@ -498,16 +500,32 @@
"options": "Journal Entry Template",
"print_hide": 1,
"report_hide": 1
+ },
+ {
+ "depends_on": "eval:doc.apply_tds",
+ "fieldname": "tax_withholding_category",
+ "fieldtype": "Link",
+ "label": "Tax Withholding Category",
+ "mandatory_depends_on": "eval:doc.apply_tds",
+ "options": "Tax Withholding Category"
+ },
+ {
+ "default": "0",
+ "depends_on": "eval:['Credit Note', 'Debit Note'].includes(doc.voucher_type)",
+ "fieldname": "apply_tds",
+ "fieldtype": "Check",
+ "label": "Apply Tax Withholding Amount "
}
],
"icon": "fa fa-file-text",
"idx": 176,
"is_submittable": 1,
"links": [],
- "modified": "2020-10-30 13:56:01.121995",
+ "modified": "2021-09-09 15:31:14.484029",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Journal Entry",
+ "naming_rule": "By \"Naming Series\" field",
"owner": "Administrator",
"permissions": [
{
diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py
index 24368f0..e568a82 100644
--- a/erpnext/accounts/doctype/journal_entry/journal_entry.py
+++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py
@@ -15,6 +15,9 @@
from erpnext.accounts.doctype.invoice_discounting.invoice_discounting import (
get_party_account_based_on_invoice_discounting,
)
+from erpnext.accounts.doctype.tax_withholding_category.tax_withholding_category import (
+ get_party_tax_withholding_details,
+)
from erpnext.accounts.party import get_party_account
from erpnext.accounts.utils import (
check_if_stock_and_account_balance_synced,
@@ -57,7 +60,8 @@
self.validate_against_jv()
self.validate_reference_doc()
- self.set_against_account()
+ if self.docstatus == 0:
+ self.set_against_account()
self.create_remarks()
self.set_print_format_fields()
self.validate_expense_claim()
@@ -66,6 +70,10 @@
self.set_account_and_party_balance()
self.validate_inter_company_accounts()
self.validate_stock_accounts()
+
+ if self.docstatus == 0:
+ self.apply_tax_withholding()
+
if not self.title:
self.title = self.get_title()
@@ -139,6 +147,72 @@
frappe.throw(_("Account: {0} can only be updated via Stock Transactions")
.format(account), StockAccountInvalidTransaction)
+ def apply_tax_withholding(self):
+ from erpnext.accounts.report.general_ledger.general_ledger import get_account_type_map
+
+ if not self.apply_tds or self.voucher_type not in ('Debit Note', 'Credit Note'):
+ return
+
+ parties = [d.party for d in self.get('accounts') if d.party]
+ parties = list(set(parties))
+
+ if len(parties) > 1:
+ frappe.throw(_("Cannot apply TDS against multiple parties in one entry"))
+
+ account_type_map = get_account_type_map(self.company)
+ party_type = 'supplier' if self.voucher_type == 'Credit Note' else 'customer'
+ doctype = 'Purchase Invoice' if self.voucher_type == 'Credit Note' else 'Sales Invoice'
+ debit_or_credit = 'debit_in_account_currency' if self.voucher_type == 'Credit Note' else 'credit_in_account_currency'
+ rev_debit_or_credit = 'credit_in_account_currency' if debit_or_credit == 'debit_in_account_currency' else 'debit_in_account_currency'
+
+ party_account = get_party_account(party_type.title(), parties[0], self.company)
+
+ net_total = sum(d.get(debit_or_credit) for d in self.get('accounts') if account_type_map.get(d.account)
+ not in ('Tax', 'Chargeable'))
+
+ party_amount = sum(d.get(rev_debit_or_credit) for d in self.get('accounts') if d.account == party_account)
+
+ inv = frappe._dict({
+ party_type: parties[0],
+ 'doctype': doctype,
+ 'company': self.company,
+ 'posting_date': self.posting_date,
+ 'net_total': net_total
+ })
+
+ tax_withholding_details = get_party_tax_withholding_details(inv, self.tax_withholding_category)
+
+ if not tax_withholding_details:
+ return
+
+ accounts = []
+ for d in self.get('accounts'):
+ if d.get('account') == tax_withholding_details.get("account_head"):
+ d.update({
+ 'account': tax_withholding_details.get("account_head"),
+ debit_or_credit: tax_withholding_details.get('tax_amount')
+ })
+
+ accounts.append(d.get('account'))
+
+ if d.get('account') == party_account:
+ d.update({
+ rev_debit_or_credit: party_amount - tax_withholding_details.get('tax_amount')
+ })
+
+ if not accounts or tax_withholding_details.get("account_head") not in accounts:
+ self.append("accounts", {
+ 'account': tax_withholding_details.get("account_head"),
+ rev_debit_or_credit: tax_withholding_details.get('tax_amount'),
+ 'against_account': parties[0]
+ })
+
+ to_remove = [d for d in self.get('accounts')
+ if not d.get(rev_debit_or_credit) and d.account == tax_withholding_details.get("account_head")]
+
+ for d in to_remove:
+ self.remove(d)
+
def update_inter_company_jv(self):
if self.voucher_type == "Inter Company Journal Entry" and self.inter_company_journal_entry_reference:
frappe.db.set_value("Journal Entry", self.inter_company_journal_entry_reference,\
diff --git a/erpnext/accounts/doctype/payment_entry_reference/payment_entry_reference.json b/erpnext/accounts/doctype/payment_entry_reference/payment_entry_reference.json
index 43eb0b6..8961167 100644
--- a/erpnext/accounts/doctype/payment_entry_reference/payment_entry_reference.json
+++ b/erpnext/accounts/doctype/payment_entry_reference/payment_entry_reference.json
@@ -93,6 +93,7 @@
"options": "Payment Term"
},
{
+ "depends_on": "exchange_gain_loss",
"fieldname": "exchange_gain_loss",
"fieldtype": "Currency",
"label": "Exchange Gain/Loss",
@@ -103,7 +104,7 @@
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
- "modified": "2021-04-21 13:30:11.605388",
+ "modified": "2021-09-26 17:06:55.597389",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Entry Reference",
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
index dde0328..55e288e 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
@@ -1303,6 +1303,7 @@
"fetch_from": "supplier.is_internal_supplier",
"fieldname": "is_internal_supplier",
"fieldtype": "Check",
+ "ignore_user_permissions": 1,
"label": "Is Internal Supplier",
"read_only": 1
},
@@ -1400,7 +1401,7 @@
"idx": 204,
"is_submittable": 1,
"links": [],
- "modified": "2021-09-21 09:27:39.967811",
+ "modified": "2021-09-28 13:10:28.351810",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Invoice",
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
index dd4a005..1c9943f 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
@@ -1146,6 +1146,12 @@
if not self.apply_tds:
return
+ if self.apply_tds and not self.get('tax_withholding_category'):
+ self.tax_withholding_category = frappe.db.get_value('Supplier', self.supplier, 'tax_withholding_category')
+
+ if not self.tax_withholding_category:
+ return
+
tax_withholding_details = get_party_tax_withholding_details(self, self.tax_withholding_category)
if not tax_withholding_details:
diff --git a/erpnext/accounts/doctype/purchase_invoice_advance/purchase_invoice_advance.json b/erpnext/accounts/doctype/purchase_invoice_advance/purchase_invoice_advance.json
index 63dfff8..9fcbf5c 100644
--- a/erpnext/accounts/doctype/purchase_invoice_advance/purchase_invoice_advance.json
+++ b/erpnext/accounts/doctype/purchase_invoice_advance/purchase_invoice_advance.json
@@ -97,6 +97,7 @@
"width": "100px"
},
{
+ "depends_on": "exchange_gain_loss",
"fieldname": "exchange_gain_loss",
"fieldtype": "Currency",
"label": "Exchange Gain/Loss",
@@ -104,6 +105,7 @@
"read_only": 1
},
{
+ "depends_on": "exchange_gain_loss",
"fieldname": "ref_exchange_rate",
"fieldtype": "Float",
"label": "Reference Exchange Rate",
@@ -115,7 +117,7 @@
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
- "modified": "2021-04-20 16:26:53.820530",
+ "modified": "2021-09-26 15:47:28.167371",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Invoice Advance",
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
index f383b52..2d6c04e 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
@@ -1953,6 +1953,7 @@
"fetch_from": "customer.represents_company",
"fieldname": "represents_company",
"fieldtype": "Link",
+ "ignore_user_permissions": 1,
"label": "Represents Company",
"options": "Company",
"read_only": 1
@@ -2022,7 +2023,7 @@
"link_fieldname": "consolidated_invoice"
}
],
- "modified": "2021-09-21 09:27:50.191854",
+ "modified": "2021-09-28 13:09:34.391799",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice",
diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
index 619dc7b..bdd30f3 100644
--- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
@@ -2352,6 +2352,7 @@
if not frappe.db.exists('Address', '_Test Address for Eway bill-Billing'):
address = frappe.get_doc({
"address_line1": "_Test Address Line 1",
+ "address_line2": "_Test Address Line 2",
"address_title": "_Test Address for Eway bill",
"address_type": "Billing",
"city": "_Test City",
@@ -2373,11 +2374,12 @@
address.save()
- if not frappe.db.exists('Address', '_Test Customer-Address for Eway bill-Shipping'):
+ if not frappe.db.exists('Address', '_Test Customer-Address for Eway bill-Billing'):
address = frappe.get_doc({
"address_line1": "_Test Address Line 1",
+ "address_line2": "_Test Address Line 2",
"address_title": "_Test Customer-Address for Eway bill",
- "address_type": "Shipping",
+ "address_type": "Billing",
"city": "_Test City",
"state": "Test State",
"country": "India",
@@ -2397,9 +2399,34 @@
address.save()
+ if not frappe.db.exists('Address', '_Test Customer-Address for Eway bill-Shipping'):
+ address = frappe.get_doc({
+ "address_line1": "_Test Address Line 1",
+ "address_line2": "_Test Address Line 2",
+ "address_title": "_Test Customer-Address for Eway bill",
+ "address_type": "Shipping",
+ "city": "_Test City",
+ "state": "Test State",
+ "country": "India",
+ "doctype": "Address",
+ "is_primary_address": 1,
+ "phone": "+910000000000",
+ "gst_state": "Maharashtra",
+ "gst_state_number": "27",
+ "pincode": "410098"
+ }).insert()
+
+ address.append("links", {
+ "link_doctype": "Customer",
+ "link_name": "_Test Customer"
+ })
+
+ address.save()
+
if not frappe.db.exists('Address', '_Test Dispatch-Address for Eway bill-Shipping'):
address = frappe.get_doc({
"address_line1": "_Test Dispatch Address Line 1",
+ "address_line2": "_Test Dispatch Address Line 2",
"address_title": "_Test Dispatch-Address for Eway bill",
"address_type": "Shipping",
"city": "_Test City",
@@ -2414,11 +2441,6 @@
"pincode": "1100101"
}).insert()
- address.append("links", {
- "link_doctype": "Company",
- "link_name": "_Test Company"
- })
-
address.save()
def make_test_transporter_for_ewaybill():
@@ -2458,7 +2480,8 @@
si.distance = 2000
si.company_address = "_Test Address for Eway bill-Billing"
- si.customer_address = "_Test Customer-Address for Eway bill-Shipping"
+ si.customer_address = "_Test Customer-Address for Eway bill-Billing"
+ si.shipping_address_name = "_Test Customer-Address for Eway bill-Shipping"
si.dispatch_address_name = "_Test Dispatch-Address for Eway bill-Shipping"
si.vehicle_no = "KA12KA1234"
si.gst_category = "Registered Regular"
diff --git a/erpnext/accounts/doctype/sales_invoice_advance/sales_invoice_advance.json b/erpnext/accounts/doctype/sales_invoice_advance/sales_invoice_advance.json
index 29422d6..f92b57a 100644
--- a/erpnext/accounts/doctype/sales_invoice_advance/sales_invoice_advance.json
+++ b/erpnext/accounts/doctype/sales_invoice_advance/sales_invoice_advance.json
@@ -98,6 +98,7 @@
"width": "120px"
},
{
+ "depends_on": "exchange_gain_loss",
"fieldname": "exchange_gain_loss",
"fieldtype": "Currency",
"label": "Exchange Gain/Loss",
@@ -105,6 +106,7 @@
"read_only": 1
},
{
+ "depends_on": "exchange_gain_loss",
"fieldname": "ref_exchange_rate",
"fieldtype": "Float",
"label": "Reference Exchange Rate",
@@ -116,7 +118,7 @@
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
- "modified": "2021-06-04 20:25:49.832052",
+ "modified": "2021-09-26 15:47:46.911595",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice Advance",
diff --git a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
index fa4ea21..16ef5fc 100644
--- a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
+++ b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
@@ -100,6 +100,7 @@
for account_detail in tax_withholding.accounts:
if company == account_detail.company:
return frappe._dict({
+ "tax_withholding_category": tax_withholding_category,
"account_head": account_detail.account,
"rate": tax_rate_detail.tax_withholding_rate,
"from_date": tax_rate_detail.from_date,
@@ -206,18 +207,39 @@
def get_invoice_vouchers(parties, tax_details, company, party_type='Supplier'):
dr_or_cr = 'credit' if party_type == 'Supplier' else 'debit'
+ doctype = 'Purchase Invoice' if party_type == 'Supplier' else 'Sales Invoice'
filters = {
- dr_or_cr: ['>', 0],
'company': company,
- 'party_type': party_type,
- 'party': ['in', parties],
+ frappe.scrub(party_type): ['in', parties],
'posting_date': ['between', (tax_details.from_date, tax_details.to_date)],
'is_opening': 'No',
- 'is_cancelled': 0
+ 'docstatus': 1
}
- return frappe.get_all('GL Entry', filters=filters, distinct=1, pluck="voucher_no") or [""]
+ if not tax_details.get('consider_party_ledger_amount') and doctype != "Sales Invoice":
+ filters.update({
+ 'apply_tds': 1,
+ 'tax_withholding_category': tax_details.get('tax_withholding_category')
+ })
+
+ invoices = frappe.get_all(doctype, filters=filters, pluck="name") or [""]
+
+ journal_entries = frappe.db.sql("""
+ SELECT j.name
+ FROM `tabJournal Entry` j, `tabJournal Entry Account` ja
+ WHERE
+ j.docstatus = 1
+ AND j.is_opening = 'No'
+ AND j.posting_date between %s and %s
+ AND ja.{dr_or_cr} > 0
+ AND ja.party in %s
+ """.format(dr_or_cr=dr_or_cr), (tax_details.from_date, tax_details.to_date, tuple(parties)), as_list=1)
+
+ if journal_entries:
+ journal_entries = journal_entries[0]
+
+ return invoices + journal_entries
def get_advance_vouchers(parties, company=None, from_date=None, to_date=None, party_type='Supplier'):
# for advance vouchers, debit and credit is reversed
diff --git a/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py b/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py
index 8a88d79..84b364b 100644
--- a/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py
+++ b/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py
@@ -176,6 +176,29 @@
for d in invoices:
d.cancel()
+ def test_multi_category_single_supplier(self):
+ frappe.db.set_value("Supplier", "Test TDS Supplier5", "tax_withholding_category", "Test Service Category")
+ invoices = []
+
+ pi = create_purchase_invoice(supplier = "Test TDS Supplier5", rate = 500, do_not_save=True)
+ pi.tax_withholding_category = "Test Service Category"
+ pi.save()
+ pi.submit()
+ invoices.append(pi)
+
+ # Second Invoice will apply TDS checked
+ pi1 = create_purchase_invoice(supplier = "Test TDS Supplier5", rate = 2500, do_not_save=True)
+ pi1.tax_withholding_category = "Test Goods Category"
+ pi1.save()
+ pi1.submit()
+ invoices.append(pi1)
+
+ self.assertEqual(pi1.taxes[0].tax_amount, 250)
+
+ #delete invoices to avoid clashing
+ for d in invoices:
+ d.cancel()
+
def cancel_invoices():
purchase_invoices = frappe.get_all("Purchase Invoice", {
'supplier': ['in', ['Test TDS Supplier', 'Test TDS Supplier1', 'Test TDS Supplier2']],
@@ -251,7 +274,8 @@
def create_records():
# create a new suppliers
- for name in ['Test TDS Supplier', 'Test TDS Supplier1', 'Test TDS Supplier2', 'Test TDS Supplier3', 'Test TDS Supplier4']:
+ for name in ['Test TDS Supplier', 'Test TDS Supplier1', 'Test TDS Supplier2', 'Test TDS Supplier3',
+ 'Test TDS Supplier4', 'Test TDS Supplier5']:
if frappe.db.exists('Supplier', name):
continue
@@ -390,3 +414,39 @@
'account': 'TDS - _TC'
}]
}).insert()
+
+ if not frappe.db.exists("Tax Withholding Category", "Test Service Category"):
+ frappe.get_doc({
+ "doctype": "Tax Withholding Category",
+ "name": "Test Service Category",
+ "category_name": "Test Service Category",
+ "rates": [{
+ 'from_date': fiscal_year[1],
+ 'to_date': fiscal_year[2],
+ 'tax_withholding_rate': 10,
+ 'single_threshold': 2000,
+ 'cumulative_threshold': 2000
+ }],
+ "accounts": [{
+ 'company': '_Test Company',
+ 'account': 'TDS - _TC'
+ }]
+ }).insert()
+
+ if not frappe.db.exists("Tax Withholding Category", "Test Goods Category"):
+ frappe.get_doc({
+ "doctype": "Tax Withholding Category",
+ "name": "Test Goods Category",
+ "category_name": "Test Goods Category",
+ "rates": [{
+ 'from_date': fiscal_year[1],
+ 'to_date': fiscal_year[2],
+ 'tax_withholding_rate': 10,
+ 'single_threshold': 2000,
+ 'cumulative_threshold': 2000
+ }],
+ "accounts": [{
+ 'company': '_Test Company',
+ 'account': 'TDS - _TC'
+ }]
+ }).insert()
diff --git a/erpnext/accounts/report/tds_computation_summary/tds_computation_summary.json b/erpnext/accounts/report/tds_computation_summary/tds_computation_summary.json
index dfc4b18..91f0798 100644
--- a/erpnext/accounts/report/tds_computation_summary/tds_computation_summary.json
+++ b/erpnext/accounts/report/tds_computation_summary/tds_computation_summary.json
@@ -1,12 +1,15 @@
{
- "add_total_row": 0,
+ "add_total_row": 1,
+ "columns": [],
"creation": "2018-08-21 11:25:00.551823",
+ "disable_prepared_report": 0,
"disabled": 0,
"docstatus": 0,
"doctype": "Report",
+ "filters": [],
"idx": 0,
"is_standard": "Yes",
- "modified": "2018-09-21 11:25:00.551823",
+ "modified": "2021-09-20 17:43:39.518851",
"modified_by": "Administrator",
"module": "Accounts",
"name": "TDS Computation Summary",
diff --git a/erpnext/accounts/report/tds_computation_summary/tds_computation_summary.py b/erpnext/accounts/report/tds_computation_summary/tds_computation_summary.py
index c4a8c7a..536df1f 100644
--- a/erpnext/accounts/report/tds_computation_summary/tds_computation_summary.py
+++ b/erpnext/accounts/report/tds_computation_summary/tds_computation_summary.py
@@ -2,11 +2,10 @@
import frappe
from frappe import _
-from frappe.utils import flt
-from erpnext.accounts.doctype.tax_withholding_category.tax_withholding_category import (
- get_advance_vouchers,
- get_debit_note_amount,
+from erpnext.accounts.report.tds_payable_monthly.tds_payable_monthly import (
+ get_result,
+ get_tds_docs,
)
from erpnext.accounts.utils import get_fiscal_year
@@ -17,9 +16,12 @@
filters.naming_series = frappe.db.get_single_value('Buying Settings', 'supp_master_name')
columns = get_columns(filters)
- res = get_result(filters)
+ tds_docs, tds_accounts, tax_category_map = get_tds_docs(filters)
- return columns, res
+ res = get_result(filters, tds_docs, tds_accounts, tax_category_map)
+ final_result = group_by_supplier_and_category(res)
+
+ return columns, final_result
def validate_filters(filters):
''' Validate if dates are properly set and lie in the same fiscal year'''
@@ -33,81 +35,39 @@
filters["fiscal_year"] = from_year
-def get_result(filters):
- # if no supplier selected, fetch data for all tds applicable supplier
- # else fetch relevant data for selected supplier
- pan = "pan" if frappe.db.has_column("Supplier", "pan") else "tax_id"
- fields = ["name", pan+" as pan", "tax_withholding_category", "supplier_type", "supplier_name"]
+def group_by_supplier_and_category(data):
+ supplier_category_wise_map = {}
- if filters.supplier:
- filters.supplier = frappe.db.get_list('Supplier',
- {"name": filters.supplier}, fields)
- else:
- filters.supplier = frappe.db.get_list('Supplier',
- {"tax_withholding_category": ["!=", ""]}, fields)
+ for row in data:
+ supplier_category_wise_map.setdefault((row.get('supplier'), row.get('section_code')), {
+ 'pan': row.get('pan'),
+ 'supplier': row.get('supplier'),
+ 'supplier_name': row.get('supplier_name'),
+ 'section_code': row.get('section_code'),
+ 'entity_type': row.get('entity_type'),
+ 'tds_rate': row.get('tds_rate'),
+ 'total_amount_credited': 0.0,
+ 'tds_deducted': 0.0
+ })
+ supplier_category_wise_map.get((row.get('supplier'), row.get('section_code')))['total_amount_credited'] += \
+ row.get('total_amount_credited', 0.0)
+
+ supplier_category_wise_map.get((row.get('supplier'), row.get('section_code')))['tds_deducted'] += \
+ row.get('tds_deducted', 0.0)
+
+ final_result = get_final_result(supplier_category_wise_map)
+
+ return final_result
+
+
+def get_final_result(supplier_category_wise_map):
out = []
- for supplier in filters.supplier:
- tds = frappe.get_doc("Tax Withholding Category", supplier.tax_withholding_category)
- rate = [d.tax_withholding_rate for d in tds.rates if d.fiscal_year == filters.fiscal_year]
-
- if rate:
- rate = rate[0]
-
- try:
- account = [d.account for d in tds.accounts if d.company == filters.company][0]
-
- except IndexError:
- account = []
- total_invoiced_amount, tds_deducted = get_invoice_and_tds_amount(supplier.name, account,
- filters.company, filters.from_date, filters.to_date, filters.fiscal_year)
-
- if total_invoiced_amount or tds_deducted:
- row = [supplier.pan, supplier.name]
-
- if filters.naming_series == 'Naming Series':
- row.append(supplier.supplier_name)
-
- row.extend([tds.name, supplier.supplier_type, rate, total_invoiced_amount, tds_deducted])
- out.append(row)
+ for key, value in supplier_category_wise_map.items():
+ out.append(value)
return out
-def get_invoice_and_tds_amount(supplier, account, company, from_date, to_date, fiscal_year):
- ''' calculate total invoice amount and total tds deducted for given supplier '''
-
- entries = frappe.db.sql("""
- select voucher_no, credit
- from `tabGL Entry`
- where party in (%s) and credit > 0
- and company=%s and is_cancelled = 0
- and posting_date between %s and %s
- """, (supplier, company, from_date, to_date), as_dict=1)
-
- supplier_credit_amount = flt(sum(d.credit for d in entries))
-
- vouchers = [d.voucher_no for d in entries]
- vouchers += get_advance_vouchers([supplier], company=company,
- from_date=from_date, to_date=to_date)
-
- tds_deducted = 0
- if vouchers:
- tds_deducted = flt(frappe.db.sql("""
- select sum(credit)
- from `tabGL Entry`
- where account=%s and posting_date between %s and %s
- and company=%s and credit > 0 and voucher_no in ({0})
- """.format(', '.join("'%s'" % d for d in vouchers)),
- (account, from_date, to_date, company))[0][0])
-
- date_range_filter = [fiscal_year, from_date, to_date]
-
- debit_note_amount = get_debit_note_amount([supplier], date_range_filter, company=company)
-
- total_invoiced_amount = supplier_credit_amount + tds_deducted - debit_note_amount
-
- return total_invoiced_amount, tds_deducted
-
def get_columns(filters):
columns = [
{
@@ -149,7 +109,7 @@
{
"label": _("TDS Rate %"),
"fieldname": "tds_rate",
- "fieldtype": "Float",
+ "fieldtype": "Percent",
"width": 90
},
{
diff --git a/erpnext/accounts/report/tds_payable_monthly/tds_payable_monthly.js b/erpnext/accounts/report/tds_payable_monthly/tds_payable_monthly.js
index 72de318..ff2aa30 100644
--- a/erpnext/accounts/report/tds_payable_monthly/tds_payable_monthly.js
+++ b/erpnext/accounts/report/tds_payable_monthly/tds_payable_monthly.js
@@ -16,69 +16,6 @@
"label": __("Supplier"),
"fieldtype": "Link",
"options": "Supplier",
- "get_query": function() {
- return {
- "filters": {
- "tax_withholding_category": ["!=", ""],
- }
- }
- },
- on_change: function() {
- frappe.query_report.set_filter_value("purchase_invoice", "");
- frappe.query_report.refresh();
- }
- },
- {
- "fieldname":"purchase_invoice",
- "label": __("Purchase Invoice"),
- "fieldtype": "Link",
- "options": "Purchase Invoice",
- "get_query": function() {
- return {
- "filters": {
- "name": ["in", frappe.query_report.invoices]
- }
- }
- },
- on_change: function() {
- let supplier = frappe.query_report.get_filter_value('supplier');
- if(!supplier) return; // return if no supplier selected
-
- // filter invoices based on selected supplier
- let invoices = [];
- frappe.query_report.invoice_data.map(d => {
- if(d.supplier==supplier)
- invoices.push(d.name)
- });
- frappe.query_report.invoices = invoices;
- frappe.query_report.refresh();
- }
- },
- {
- "fieldname":"purchase_order",
- "label": __("Purchase Order"),
- "fieldtype": "Link",
- "options": "Purchase Order",
- "get_query": function() {
- return {
- "filters": {
- "name": ["in", frappe.query_report.invoices]
- }
- }
- },
- on_change: function() {
- let supplier = frappe.query_report.get_filter_value('supplier');
- if(!supplier) return; // return if no supplier selected
-
- // filter invoices based on selected supplier
- let invoices = [];
- frappe.query_report.invoice_data.map(d => {
- if(d.supplier==supplier)
- invoices.push(d.name)
- });
- frappe.query_report.invoices = invoices;
- frappe.query_report.refresh();
- }
},
{
"fieldname":"from_date",
@@ -96,23 +33,5 @@
"reqd": 1,
"width": "60px"
}
- ],
-
- onload: function(report) {
- // fetch all tds applied invoices
- frappe.call({
- "method": "erpnext.accounts.report.tds_payable_monthly.tds_payable_monthly.get_tds_invoices_and_orders",
- callback: function(r) {
- let invoices = [];
-
- r.message.map(d => {
- invoices.push(d.name);
- });
-
- report["invoice_data"] = r.message.invoices;
- report["invoices"] = invoices;
-
- }
- });
- }
+ ]
}
diff --git a/erpnext/accounts/report/tds_payable_monthly/tds_payable_monthly.json b/erpnext/accounts/report/tds_payable_monthly/tds_payable_monthly.json
index 557a62d..4d555bd 100644
--- a/erpnext/accounts/report/tds_payable_monthly/tds_payable_monthly.json
+++ b/erpnext/accounts/report/tds_payable_monthly/tds_payable_monthly.json
@@ -1,13 +1,15 @@
{
"add_total_row": 1,
+ "columns": [],
"creation": "2018-08-21 11:32:30.874923",
"disable_prepared_report": 0,
"disabled": 0,
"docstatus": 0,
"doctype": "Report",
+ "filters": [],
"idx": 0,
"is_standard": "Yes",
- "modified": "2019-09-24 13:46:16.473711",
+ "modified": "2021-09-20 12:05:50.387572",
"modified_by": "Administrator",
"module": "Accounts",
"name": "TDS Payable Monthly",
diff --git a/erpnext/accounts/report/tds_payable_monthly/tds_payable_monthly.py b/erpnext/accounts/report/tds_payable_monthly/tds_payable_monthly.py
index 9e1382b..621b697 100644
--- a/erpnext/accounts/report/tds_payable_monthly/tds_payable_monthly.py
+++ b/erpnext/accounts/report/tds_payable_monthly/tds_payable_monthly.py
@@ -8,19 +8,12 @@
def execute(filters=None):
- filters["invoices"] = frappe.cache().hget("invoices", frappe.session.user)
validate_filters(filters)
- set_filters(filters)
-
- # TDS payment entries
- payment_entries = get_payment_entires(filters)
+ tds_docs, tds_accounts, tax_category_map = get_tds_docs(filters)
columns = get_columns(filters)
- if not filters.get("invoices"):
- return columns, []
- res = get_result(filters, payment_entries)
-
+ res = get_result(filters, tds_docs, tds_accounts, tax_category_map)
return columns, res
def validate_filters(filters):
@@ -28,109 +21,59 @@
if filters.from_date > filters.to_date:
frappe.throw(_("From Date must be before To Date"))
-def set_filters(filters):
- invoices = []
-
- if not filters.get("invoices"):
- filters["invoices"] = get_tds_invoices_and_orders()
-
- if filters.supplier and filters.purchase_invoice:
- for d in filters["invoices"]:
- if d.name == filters.purchase_invoice and d.supplier == filters.supplier:
- invoices.append(d)
- elif filters.supplier and not filters.purchase_invoice:
- for d in filters["invoices"]:
- if d.supplier == filters.supplier:
- invoices.append(d)
- elif filters.purchase_invoice and not filters.supplier:
- for d in filters["invoices"]:
- if d.name == filters.purchase_invoice:
- invoices.append(d)
- elif filters.supplier and filters.purchase_order:
- for d in filters.get("invoices"):
- if d.name == filters.purchase_order and d.supplier == filters.supplier:
- invoices.append(d)
- elif filters.supplier and not filters.purchase_order:
- for d in filters.get("invoices"):
- if d.supplier == filters.supplier:
- invoices.append(d)
- elif filters.purchase_order and not filters.supplier:
- for d in filters.get("invoices"):
- if d.name == filters.purchase_order:
- invoices.append(d)
-
- filters["invoices"] = invoices if invoices else filters["invoices"]
- filters.naming_series = frappe.db.get_single_value('Buying Settings', 'supp_master_name')
-
- #print(filters.get('invoices'))
-
-def get_result(filters, payment_entries):
- supplier_map, tds_docs = get_supplier_map(filters, payment_entries)
- documents = [d.get('name') for d in filters.get('invoices')] + [d.get('name') for d in payment_entries]
-
- gle_map = get_gle_map(filters, documents)
+def get_result(filters, tds_docs, tds_accounts, tax_category_map):
+ supplier_map = get_supplier_pan_map()
+ tax_rate_map = get_tax_rate_map(filters)
+ gle_map = get_gle_map(filters, tds_docs)
out = []
- for d in gle_map:
+ for name, details in gle_map.items():
tds_deducted, total_amount_credited = 0, 0
- supplier = supplier_map[d]
+ tax_withholding_category = tax_category_map.get(name)
+ rate = tax_rate_map.get(tax_withholding_category)
- tds_doc = tds_docs[supplier.tax_withholding_category]
- account_list = [i.account for i in tds_doc.accounts if i.company == filters.company]
+ for entry in details:
+ supplier = entry.party or entry.against
+ posting_date = entry.posting_date
+ voucher_type = entry.voucher_type
- if account_list:
- account = account_list[0]
+ if entry.account in tds_accounts:
+ tds_deducted += (entry.credit - entry.debit)
- for k in gle_map[d]:
- if k.party == supplier_map[d] and k.credit > 0:
- total_amount_credited += (k.credit - k.debit)
- elif account_list and k.account == account and (k.credit - k.debit) > 0:
- tds_deducted = (k.credit - k.debit)
- total_amount_credited += (k.credit - k.debit)
- voucher_type = k.voucher_type
+ total_amount_credited += (entry.credit - entry.debit)
- rate = [i.tax_withholding_rate for i in tds_doc.rates
- if i.fiscal_year == gle_map[d][0].fiscal_year]
-
- if rate and len(rate) > 0 and tds_deducted:
- rate = rate[0]
-
- row = [supplier.pan, supplier.name]
+ if rate and tds_deducted:
+ row = {
+ 'pan' if frappe.db.has_column('Supplier', 'pan') else 'tax_id': supplier_map.get(supplier).pan,
+ 'supplier': supplier_map.get(supplier).name
+ }
if filters.naming_series == 'Naming Series':
- row.append(supplier.supplier_name)
+ row.update({'supplier_name': supplier_map.get(supplier).supplier_name})
- row.extend([tds_doc.name, supplier.supplier_type, rate, total_amount_credited,
- tds_deducted, gle_map[d][0].posting_date, voucher_type, d])
+ row.update({
+ 'section_code': tax_withholding_category,
+ 'entity_type': supplier_map.get(supplier).supplier_type,
+ 'tds_rate': rate,
+ 'total_amount_credited': total_amount_credited,
+ 'tds_deducted': tds_deducted,
+ 'transaction_date': posting_date,
+ 'transaction_type': voucher_type,
+ 'ref_no': name
+ })
+
out.append(row)
return out
-def get_supplier_map(filters, payment_entries):
- # create a supplier_map of the form {"purchase_invoice": {supplier_name, pan, tds_name}}
- # pre-fetch all distinct applicable tds docs
- supplier_map, tds_docs = {}, {}
- pan = "pan" if frappe.db.has_column("Supplier", "pan") else "tax_id"
- supplier_list = [d.supplier for d in filters["invoices"]]
+def get_supplier_pan_map():
+ supplier_map = frappe._dict()
+ suppliers = frappe.db.get_all('Supplier', fields=['name', 'pan', 'supplier_type', 'supplier_name'])
- supplier_detail = frappe.db.get_all('Supplier',
- {"name": ["in", supplier_list]},
- ["tax_withholding_category", "name", pan+" as pan", "supplier_type", "supplier_name"])
+ for d in suppliers:
+ supplier_map[d.name] = d
- for d in filters["invoices"]:
- supplier_map[d.get("name")] = [k for k in supplier_detail
- if k.name == d.get("supplier")][0]
-
- for d in payment_entries:
- supplier_map[d.get("name")] = [k for k in supplier_detail
- if k.name == d.get("supplier")][0]
-
- for d in supplier_detail:
- if d.get("tax_withholding_category") not in tds_docs:
- tds_docs[d.get("tax_withholding_category")] = \
- frappe.get_doc("Tax Withholding Category", d.get("tax_withholding_category"))
-
- return supplier_map, tds_docs
+ return supplier_map
def get_gle_map(filters, documents):
# create gle_map of the form
@@ -140,10 +83,9 @@
gle = frappe.db.get_all('GL Entry',
{
"voucher_no": ["in", documents],
- 'is_cancelled': 0,
- 'posting_date': ("between", [filters.get('from_date'), filters.get('to_date')]),
+ "credit": (">", 0)
},
- ["fiscal_year", "credit", "debit", "account", "voucher_no", "posting_date", "voucher_type"],
+ ["credit", "debit", "account", "voucher_no", "posting_date", "voucher_type", "against", "party"],
)
for d in gle:
@@ -233,39 +175,57 @@
return columns
-def get_payment_entires(filters):
- filter_dict = {
- 'posting_date': ("between", [filters.get('from_date'), filters.get('to_date')]),
- 'party_type': 'Supplier',
- 'apply_tax_withholding_amount': 1
+def get_tds_docs(filters):
+ tds_documents = []
+ purchase_invoices = []
+ payment_entries = []
+ journal_entries = []
+ tax_category_map = {}
+
+ tds_accounts = frappe.get_all("Tax Withholding Account", {'company': filters.get('company')},
+ pluck="account")
+
+ query_filters = {
+ "credit": ('>', 0),
+ "account": ("in", tds_accounts),
+ "posting_date": ("between", [filters.get("from_date"), filters.get("to_date")]),
+ "is_cancelled": 0
}
- if filters.get('purchase_invoice') or filters.get('purchase_order'):
- parent = frappe.db.get_all('Payment Entry Reference',
- {'reference_name': ('in', [d.get('name') for d in filters.get('invoices')])}, ['parent'])
+ if filters.get('supplier'):
+ query_filters.update({'against': filters.get('supplier')})
- filter_dict.update({'name': ('in', [d.get('parent') for d in parent])})
+ tds_docs = frappe.get_all("GL Entry", query_filters, ["voucher_no", "voucher_type", "against", "party"])
- payment_entries = frappe.get_all('Payment Entry', fields=['name', 'party_name as supplier'],
- filters=filter_dict)
+ for d in tds_docs:
+ if d.voucher_type == "Purchase Invoice":
+ purchase_invoices.append(d.voucher_no)
+ elif d.voucher_type == "Payment Entry":
+ payment_entries.append(d.voucher_no)
+ elif d.voucher_type == "Journal Entry":
+ journal_entries.append(d.voucher_no)
- return payment_entries
+ tds_documents.append(d.voucher_no)
-@frappe.whitelist()
-def get_tds_invoices_and_orders():
- # fetch tds applicable supplier and fetch invoices for these suppliers
- suppliers = [d.name for d in frappe.db.get_list("Supplier",
- {"tax_withholding_category": ["!=", ""]}, ["name"])]
+ if purchase_invoices:
+ get_tax_category_map(purchase_invoices, 'Purchase Invoice', tax_category_map)
- invoices = frappe.db.get_list("Purchase Invoice",
- {"supplier": ["in", suppliers]}, ["name", "supplier"])
+ if payment_entries:
+ get_tax_category_map(payment_entries, 'Payment Entry', tax_category_map)
- orders = frappe.db.get_list("Purchase Order",
- {"supplier": ["in", suppliers]}, ["name", "supplier"])
+ if journal_entries:
+ get_tax_category_map(journal_entries, 'Journal Entry', tax_category_map)
- invoices = invoices + orders
- invoices = [d for d in invoices if d.supplier]
+ return tds_documents, tds_accounts, tax_category_map
- frappe.cache().hset("invoices", frappe.session.user, invoices)
+def get_tax_category_map(vouchers, doctype, tax_category_map):
+ tax_category_map.update(frappe._dict(frappe.get_all(doctype,
+ filters = {'name': ('in', vouchers)}, fields=['name', 'tax_withholding_category'], as_list=1)))
- return invoices
+def get_tax_rate_map(filters):
+ rate_map = frappe.get_all('Tax Withholding Rate', filters={
+ 'from_date': ('<=', filters.get('from_date')),
+ 'to_date': ('>=', filters.get('to_date'))
+ }, fields=['parent', 'tax_withholding_rate'], as_list=1)
+
+ return frappe._dict(rate_map)
\ No newline at end of file
diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py
index 8ff4f97..39f102e 100644
--- a/erpnext/assets/doctype/asset/asset.py
+++ b/erpnext/assets/doctype/asset/asset.py
@@ -394,10 +394,6 @@
if cint(self.number_of_depreciations_booked) > cint(row.total_number_of_depreciations):
frappe.throw(_("Number of Depreciations Booked cannot be greater than Total Number of Depreciations"))
- if row.depreciation_start_date and getdate(row.depreciation_start_date) < getdate(nowdate()):
- frappe.msgprint(_("Depreciation Row {0}: Depreciation Start Date is entered as past date")
- .format(row.idx), title=_('Warning'), indicator='red')
-
if row.depreciation_start_date and getdate(row.depreciation_start_date) < getdate(self.purchase_date):
frappe.throw(_("Depreciation Row {0}: Next Depreciation Date cannot be before Purchase Date")
.format(row.idx))
diff --git a/erpnext/assets/doctype/asset/test_asset.py b/erpnext/assets/doctype/asset/test_asset.py
index 4cc9be5..7183ee7 100644
--- a/erpnext/assets/doctype/asset/test_asset.py
+++ b/erpnext/assets/doctype/asset/test_asset.py
@@ -645,12 +645,18 @@
pr = make_purchase_receipt(item_code="Macbook Pro",
qty=1, rate=8000.0, location="Test Location")
+ finance_book = frappe.new_doc('Finance Book')
+ finance_book.finance_book_name = 'Income Tax'
+ finance_book.for_income_tax = 1
+ finance_book.insert(ignore_if_duplicate=1)
+
asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, 'name')
asset = frappe.get_doc('Asset', asset_name)
asset.calculate_depreciation = 1
asset.available_for_use_date = '2030-07-12'
asset.purchase_date = '2030-01-01'
asset.append("finance_books", {
+ "finance_book": finance_book.name,
"expected_value_after_useful_life": 1000,
"depreciation_method": "Written Down Value",
"total_number_of_depreciations": 3,
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.json b/erpnext/buying/doctype/purchase_order/purchase_order.json
index ef54538..896208f 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.json
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.json
@@ -1121,6 +1121,7 @@
"fetch_from": "supplier.represents_company",
"fieldname": "represents_company",
"fieldtype": "Link",
+ "ignore_user_permissions": 1,
"label": "Represents Company",
"options": "Company",
"read_only": 1
@@ -1143,7 +1144,7 @@
"idx": 105,
"is_submittable": 1,
"links": [],
- "modified": "2021-08-30 20:03:14.008804",
+ "modified": "2021-09-28 13:10:47.955401",
"modified_by": "Administrator",
"module": "Buying",
"name": "Purchase Order",
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index 87d5648..e9b531e 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -685,13 +685,17 @@
.format(d.reference_name, d.against_order))
def set_advance_gain_or_loss(self):
- if not self.get("advances"):
+ if self.get('conversion_rate') == 1 or not self.get("advances"):
+ return
+
+ is_purchase_invoice = self.doctype == 'Purchase Invoice'
+ party_account = self.credit_to if is_purchase_invoice else self.debit_to
+ if get_account_currency(party_account) != self.currency:
return
for d in self.get("advances"):
advance_exchange_rate = d.ref_exchange_rate
- if (d.allocated_amount and self.conversion_rate != 1
- and self.conversion_rate != advance_exchange_rate):
+ if (d.allocated_amount and self.conversion_rate != advance_exchange_rate):
base_allocated_amount_in_ref_rate = advance_exchange_rate * d.allocated_amount
base_allocated_amount_in_inv_rate = self.conversion_rate * d.allocated_amount
@@ -710,7 +714,7 @@
gain_loss_account = frappe.db.get_value('Company', self.company, 'exchange_gain_loss_account')
if not gain_loss_account:
- frappe.throw(_("Please set Default Exchange Gain/Loss Account in Company {}")
+ frappe.throw(_("Please set default Exchange Gain/Loss Account in Company {}")
.format(self.get('company')))
account_currency = get_account_currency(gain_loss_account)
if account_currency != self.company_currency:
@@ -729,7 +733,7 @@
"against": party,
dr_or_cr + "_in_account_currency": abs(d.exchange_gain_loss),
dr_or_cr: abs(d.exchange_gain_loss),
- "cost_center": self.cost_center,
+ "cost_center": self.cost_center or erpnext.get_default_cost_center(self.company),
"project": self.project
}, item=d)
)
diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py
index 232e3a0..7cfec97 100644
--- a/erpnext/manufacturing/doctype/bom/bom.py
+++ b/erpnext/manufacturing/doctype/bom/bom.py
@@ -1133,7 +1133,8 @@
query_filters["has_variants"] = 0
if filters and filters.get("is_stock_item"):
- query_filters["is_stock_item"] = 1
+ or_cond_filters["is_stock_item"] = 1
+ or_cond_filters["has_variants"] = 1
return frappe.get_list("Item",
fields = fields, filters=query_filters,
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 0c36c9f..5091808 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -310,3 +310,5 @@
erpnext.patches.v13_0.gst_fields_for_pos_invoice
erpnext.patches.v13_0.create_accounting_dimensions_in_pos_doctypes
erpnext.patches.v13_0.trim_sales_invoice_custom_field_length
+erpnext.patches.v13_0.create_custom_field_for_finance_book
+erpnext.patches.v13_0.modify_invalid_gain_loss_gl_entries
diff --git a/erpnext/patches/v13_0/create_custom_field_for_finance_book.py b/erpnext/patches/v13_0/create_custom_field_for_finance_book.py
new file mode 100644
index 0000000..313b0e9
--- /dev/null
+++ b/erpnext/patches/v13_0/create_custom_field_for_finance_book.py
@@ -0,0 +1,21 @@
+import frappe
+from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
+
+
+def execute():
+ company = frappe.get_all('Company', filters = {'country': 'India'})
+ if not company:
+ return
+
+ custom_field = {
+ 'Finance Book': [
+ {
+ 'fieldname': 'for_income_tax',
+ 'label': 'For Income Tax',
+ 'fieldtype': 'Check',
+ 'insert_after': 'finance_book_name',
+ 'description': 'If the asset is put to use for less than 180 days, the first Depreciation Rate will be reduced by 50%.'
+ }
+ ]
+ }
+ create_custom_fields(custom_field, update=1)
diff --git a/erpnext/patches/v13_0/modify_invalid_gain_loss_gl_entries.py b/erpnext/patches/v13_0/modify_invalid_gain_loss_gl_entries.py
new file mode 100644
index 0000000..fa8a864
--- /dev/null
+++ b/erpnext/patches/v13_0/modify_invalid_gain_loss_gl_entries.py
@@ -0,0 +1,49 @@
+from __future__ import unicode_literals
+
+import json
+
+import frappe
+
+
+def execute():
+ frappe.reload_doc('accounts', 'doctype', 'purchase_invoice_advance')
+ frappe.reload_doc('accounts', 'doctype', 'sales_invoice_advance')
+
+ purchase_invoices = frappe.db.sql("""
+ select
+ parenttype as type, parent as name
+ from
+ `tabPurchase Invoice Advance`
+ where
+ ref_exchange_rate = 1
+ and docstatus = 1
+ and ifnull(exchange_gain_loss, '') != ''
+ group by
+ parent
+ """, as_dict=1)
+
+ sales_invoices = frappe.db.sql("""
+ select
+ parenttype as type, parent as name
+ from
+ `tabSales Invoice Advance`
+ where
+ ref_exchange_rate = 1
+ and docstatus = 1
+ and ifnull(exchange_gain_loss, '') != ''
+ group by
+ parent
+ """, as_dict=1)
+
+ if purchase_invoices + sales_invoices:
+ frappe.log_error(json.dumps(purchase_invoices + sales_invoices, indent=2), title="Patch Log")
+
+ for invoice in purchase_invoices + sales_invoices:
+ doc = frappe.get_doc(invoice.type, invoice.name)
+ doc.docstatus = 2
+ doc.make_gl_entries()
+ for advance in doc.advances:
+ if advance.ref_exchange_rate == 1:
+ advance.db_set('exchange_gain_loss', 0, False)
+ doc.docstatus = 1
+ doc.make_gl_entries()
\ No newline at end of file
diff --git a/erpnext/projects/doctype/project/project.py b/erpnext/projects/doctype/project/project.py
index 2a8870b..df970f3 100644
--- a/erpnext/projects/doctype/project/project.py
+++ b/erpnext/projects/doctype/project/project.py
@@ -144,6 +144,9 @@
if self.sales_order:
frappe.db.set_value("Sales Order", self.sales_order, "project", self.name)
+ def on_trash(self):
+ frappe.db.set_value("Sales Order", {"project": self.name}, "project", "")
+
def update_percent_complete(self):
if self.percent_complete_method == "Manual":
if self.status == "Completed":
diff --git a/erpnext/projects/doctype/project/test_project.py b/erpnext/projects/doctype/project/test_project.py
index ebc1326..c64ac8d 100644
--- a/erpnext/projects/doctype/project/test_project.py
+++ b/erpnext/projects/doctype/project/test_project.py
@@ -9,6 +9,8 @@
from erpnext.projects.doctype.project_template.test_project_template import make_project_template
from erpnext.projects.doctype.task.test_task import create_task
+from erpnext.selling.doctype.sales_order.sales_order import make_project as make_project_from_so
+from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order
test_records = frappe.get_test_records('Project')
test_ignore = ["Sales Order"]
@@ -96,6 +98,21 @@
self.assertEqual(len(tasks), 2)
+ def test_project_linking_with_sales_order(self):
+ so = make_sales_order()
+ project = make_project_from_so(so.name)
+
+ project.save()
+ self.assertEqual(project.sales_order, so.name)
+
+ so.reload()
+ self.assertEqual(so.project, project.name)
+
+ project.delete()
+
+ so.reload()
+ self.assertFalse(so.project)
+
def get_project(name, template):
project = frappe.get_doc(dict(
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index 91b1247..403c498 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -617,6 +617,7 @@
me.frm.script_manager.trigger('qty', item.doctype, item.name);
if (!me.frm.doc.set_warehouse)
me.frm.script_manager.trigger('warehouse', item.doctype, item.name);
+ me.apply_price_list(item, true);
}, undefined, !frappe.flags.hide_serial_batch_dialog);
}
},
diff --git a/erpnext/regional/india/setup.py b/erpnext/regional/india/setup.py
index 93cbcca..b5c609a 100644
--- a/erpnext/regional/india/setup.py
+++ b/erpnext/regional/india/setup.py
@@ -674,6 +674,15 @@
'fieldtype': 'Data',
'insert_after': 'email'
}
+ ],
+ 'Finance Book': [
+ {
+ 'fieldname': 'for_income_tax',
+ 'label': 'For Income Tax',
+ 'fieldtype': 'Check',
+ 'insert_after': 'finance_book_name',
+ 'description': 'If the asset is put to use for less than 180 days, the first Depreciation Rate will be reduced by 50%.'
+ }
]
}
diff --git a/erpnext/regional/india/utils.py b/erpnext/regional/india/utils.py
index 091cc884..0faf80b 100644
--- a/erpnext/regional/india/utils.py
+++ b/erpnext/regional/india/utils.py
@@ -857,12 +857,13 @@
rate_of_depreciation = row.rate_of_depreciation
# if its the first depreciation
if depreciable_value == asset.gross_purchase_amount:
- # as per IT act, if the asset is purchased in the 2nd half of fiscal year, then rate is divided by 2
- diff = date_diff(row.depreciation_start_date, asset.available_for_use_date)
- if diff <= 180:
- rate_of_depreciation = rate_of_depreciation / 2
- frappe.msgprint(
- _('As per IT Act, the rate of depreciation for the first depreciation entry is reduced by 50%.'))
+ if row.finance_book and frappe.db.get_value('Finance Book', row.finance_book, 'for_income_tax'):
+ # as per IT act, if the asset is purchased in the 2nd half of fiscal year, then rate is divided by 2
+ diff = date_diff(row.depreciation_start_date, asset.available_for_use_date)
+ if diff <= 180:
+ rate_of_depreciation = rate_of_depreciation / 2
+ frappe.msgprint(
+ _('As per IT Act, the rate of depreciation for the first depreciation entry is reduced by 50%.'))
depreciation_amount = flt(depreciable_value * (flt(rate_of_depreciation) / 100))
diff --git a/erpnext/selling/doctype/sales_order/sales_order.json b/erpnext/selling/doctype/sales_order/sales_order.json
index 85282ca..7c7ed9a 100644
--- a/erpnext/selling/doctype/sales_order/sales_order.json
+++ b/erpnext/selling/doctype/sales_order/sales_order.json
@@ -1480,6 +1480,7 @@
"fetch_from": "customer.represents_company",
"fieldname": "represents_company",
"fieldtype": "Link",
+ "ignore_user_permissions": 1,
"label": "Represents Company",
"options": "Company",
"read_only": 1
@@ -1512,7 +1513,7 @@
"idx": 105,
"is_submittable": 1,
"links": [],
- "modified": "2021-09-01 15:12:24.115483",
+ "modified": "2021-09-28 13:09:51.515542",
"modified_by": "Administrator",
"module": "Selling",
"name": "Sales Order",
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.json b/erpnext/stock/doctype/delivery_note/delivery_note.json
index fdc8763..9bf142c 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.json
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.json
@@ -1277,6 +1277,7 @@
"fetch_from": "customer.represents_company",
"fieldname": "represents_company",
"fieldtype": "Link",
+ "ignore_user_permissions": 1,
"label": "Represents Company",
"options": "Company",
"read_only": 1
@@ -1308,7 +1309,7 @@
"idx": 146,
"is_submittable": 1,
"links": [],
- "modified": "2021-08-27 20:14:40.215231",
+ "modified": "2021-09-28 13:10:09.761714",
"modified_by": "Administrator",
"module": "Stock",
"name": "Delivery Note",
diff --git a/erpnext/stock/doctype/pick_list_item/pick_list_item.json b/erpnext/stock/doctype/pick_list_item/pick_list_item.json
index 8665986..805286d 100644
--- a/erpnext/stock/doctype/pick_list_item/pick_list_item.json
+++ b/erpnext/stock/doctype/pick_list_item/pick_list_item.json
@@ -36,7 +36,8 @@
"fieldname": "qty",
"fieldtype": "Float",
"in_list_view": 1,
- "label": "Qty"
+ "label": "Qty",
+ "reqd": 1
},
{
"fieldname": "picked_qty",
@@ -180,7 +181,7 @@
],
"istable": 1,
"links": [],
- "modified": "2020-06-24 17:18:57.357120",
+ "modified": "2021-09-28 12:02:16.923056",
"modified_by": "Administrator",
"module": "Stock",
"name": "Pick List Item",
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json
index 1a59734..112dded 100755
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json
@@ -1140,6 +1140,7 @@
"fetch_from": "supplier.represents_company",
"fieldname": "represents_company",
"fieldtype": "Link",
+ "ignore_user_permissions": 1,
"label": "Represents Company",
"options": "Company",
"read_only": 1
@@ -1149,7 +1150,7 @@
"idx": 261,
"is_submittable": 1,
"links": [],
- "modified": "2021-08-17 20:16:40.849885",
+ "modified": "2021-09-28 13:11:10.181328",
"modified_by": "Administrator",
"module": "Stock",
"name": "Purchase Receipt",
diff --git a/erpnext/templates/print_formats/includes/total.html b/erpnext/templates/print_formats/includes/total.html
index 8179980..879203b 100644
--- a/erpnext/templates/print_formats/includes/total.html
+++ b/erpnext/templates/print_formats/includes/total.html
@@ -7,7 +7,7 @@
</div>
{% else %}
<div class="col-xs-5 {%- if doc.align_labels_right %} text-right{%- endif -%}">
- <label>{{ _(doc.meta.get_label('total')) }}</label></div>
+ <label>{{ _(df.label) }}</label></div>
<div class="col-xs-7 text-right">
{{ doc.get_formatted("total", doc) }}
</div>