From 642819b955205e9faa64ae1e72c697c2a7950305 Mon Sep 17 00:00:00 2001
From: pateljannat
Date: Tue, 17 Nov 2020 09:47:10 +0530
Subject: [PATCH 01/18] fix: place of supply change when address changes
---
erpnext/public/js/utils.js | 15 +++++++++++++++
erpnext/regional/india/utils.py | 1 +
erpnext/selling/sales_common.js | 1 +
3 files changed, 17 insertions(+)
diff --git a/erpnext/public/js/utils.js b/erpnext/public/js/utils.js
index ea2093eee1..b4fe412fe9 100755
--- a/erpnext/public/js/utils.js
+++ b/erpnext/public/js/utils.js
@@ -304,6 +304,21 @@ $.extend(erpnext.utils, {
}
frappe.ui.form.make_quick_entry(doctype, null, null, new_doc);
});
+ },
+
+ set_place_of_supply: function(frm){
+ frappe.call({
+ method: "erpnext.regional.india.utils.get_place_of_supply",
+ args: {
+ "party_details": frm.doc,
+ "doctype": frm.doc.doctype
+ },
+ callback: function(r){
+ if(r.message){
+ frm.set_value("place_of_supply", r.message)
+ }
+ }
+ })
}
});
diff --git a/erpnext/regional/india/utils.py b/erpnext/regional/india/utils.py
index dd87f0f660..c774cb03be 100644
--- a/erpnext/regional/india/utils.py
+++ b/erpnext/regional/india/utils.py
@@ -135,6 +135,7 @@ def test_method():
'''test function'''
return 'overridden'
+@frappe.whitelist()
def get_place_of_supply(party_details, doctype):
if not frappe.get_meta('Address').has_field('gst_state'): return
diff --git a/erpnext/selling/sales_common.js b/erpnext/selling/sales_common.js
index 002cfe41e1..77bdf2912f 100644
--- a/erpnext/selling/sales_common.js
+++ b/erpnext/selling/sales_common.js
@@ -117,6 +117,7 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({
customer_address: function() {
erpnext.utils.get_address_display(this.frm, "customer_address");
erpnext.utils.set_taxes_from_address(this.frm, "customer_address", "customer_address", "shipping_address_name");
+ erpnext.utils.set_place_of_supply(this.frm)
},
shipping_address_name: function() {
From 6b10d87d468acdf4e810d5a4b4da4b389def6a06 Mon Sep 17 00:00:00 2001
From: pateljannat
Date: Tue, 17 Nov 2020 20:34:51 +0530
Subject: [PATCH 02/18] fix: place of supply change on address change
---
erpnext/public/js/controllers/buying.js | 1 +
erpnext/public/js/utils.js | 28 ++++++++++++-------------
erpnext/regional/india/utils.py | 3 +++
3 files changed, 17 insertions(+), 15 deletions(-)
diff --git a/erpnext/public/js/controllers/buying.js b/erpnext/public/js/controllers/buying.js
index cb76c87b62..cd5cc9282b 100644
--- a/erpnext/public/js/controllers/buying.js
+++ b/erpnext/public/js/controllers/buying.js
@@ -135,6 +135,7 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({
supplier_address: function() {
erpnext.utils.get_address_display(this.frm);
erpnext.utils.set_taxes_from_address(this.frm, "supplier_address", "supplier_address", "supplier_address");
+ erpnext.utils.set_place_of_supply(this.frm)
},
buying_price_list: function() {
diff --git a/erpnext/public/js/utils.js b/erpnext/public/js/utils.js
index b4fe412fe9..1555896eac 100755
--- a/erpnext/public/js/utils.js
+++ b/erpnext/public/js/utils.js
@@ -116,6 +116,19 @@ $.extend(erpnext.utils, {
}
},
+ set_place_of_supply: function(frm){
+ frappe.call({
+ method: "erpnext.regional.india.utils.get_place_of_supply",
+ args: {
+ "party_details": frm.doc,
+ "doctype": frm.doc.doctype
+ },
+ callback: function(r){
+ frm.set_value("place_of_supply", r.message)
+ }
+ })
+ },
+
add_indicator_for_multicompany: function(frm, info) {
frm.dashboard.stats_area.removeClass('hidden');
frm.dashboard.stats_area_row.addClass('flex');
@@ -304,21 +317,6 @@ $.extend(erpnext.utils, {
}
frappe.ui.form.make_quick_entry(doctype, null, null, new_doc);
});
- },
-
- set_place_of_supply: function(frm){
- frappe.call({
- method: "erpnext.regional.india.utils.get_place_of_supply",
- args: {
- "party_details": frm.doc,
- "doctype": frm.doc.doctype
- },
- callback: function(r){
- if(r.message){
- frm.set_value("place_of_supply", r.message)
- }
- }
- })
}
});
diff --git a/erpnext/regional/india/utils.py b/erpnext/regional/india/utils.py
index c774cb03be..7ad1c07f93 100644
--- a/erpnext/regional/india/utils.py
+++ b/erpnext/regional/india/utils.py
@@ -138,6 +138,9 @@ def test_method():
@frappe.whitelist()
def get_place_of_supply(party_details, doctype):
if not frappe.get_meta('Address').has_field('gst_state'): return
+ if isinstance(party_details, string_types):
+ party_details = json.loads(party_details)
+ party_details = frappe._dict(party_details)
if doctype in ("Sales Invoice", "Delivery Note", "Sales Order"):
address_name = party_details.customer_address or party_details.shipping_address_name
From 8c9b60edfec53a8a58ace5e5a3284efbdae7b724 Mon Sep 17 00:00:00 2001
From: pateljannat
Date: Wed, 18 Nov 2020 12:51:13 +0530
Subject: [PATCH 03/18] fix: reversing previous commits and adding condition in
regional controller
---
erpnext/public/js/controllers/buying.js | 1 -
erpnext/public/js/utils.js | 13 -------------
erpnext/regional/india/taxes.js | 1 +
erpnext/regional/india/utils.py | 23 +++++++++--------------
erpnext/selling/sales_common.js | 1 -
5 files changed, 10 insertions(+), 29 deletions(-)
diff --git a/erpnext/public/js/controllers/buying.js b/erpnext/public/js/controllers/buying.js
index cd5cc9282b..cb76c87b62 100644
--- a/erpnext/public/js/controllers/buying.js
+++ b/erpnext/public/js/controllers/buying.js
@@ -135,7 +135,6 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({
supplier_address: function() {
erpnext.utils.get_address_display(this.frm);
erpnext.utils.set_taxes_from_address(this.frm, "supplier_address", "supplier_address", "supplier_address");
- erpnext.utils.set_place_of_supply(this.frm)
},
buying_price_list: function() {
diff --git a/erpnext/public/js/utils.js b/erpnext/public/js/utils.js
index 1555896eac..ea2093eee1 100755
--- a/erpnext/public/js/utils.js
+++ b/erpnext/public/js/utils.js
@@ -116,19 +116,6 @@ $.extend(erpnext.utils, {
}
},
- set_place_of_supply: function(frm){
- frappe.call({
- method: "erpnext.regional.india.utils.get_place_of_supply",
- args: {
- "party_details": frm.doc,
- "doctype": frm.doc.doctype
- },
- callback: function(r){
- frm.set_value("place_of_supply", r.message)
- }
- })
- },
-
add_indicator_for_multicompany: function(frm, info) {
frm.dashboard.stats_area.removeClass('hidden');
frm.dashboard.stats_area_row.addClass('flex');
diff --git a/erpnext/regional/india/taxes.js b/erpnext/regional/india/taxes.js
index 3b6a28f52c..ecfa9b7cdf 100644
--- a/erpnext/regional/india/taxes.js
+++ b/erpnext/regional/india/taxes.js
@@ -37,6 +37,7 @@ erpnext.setup_auto_gst_taxation = (doctype) => {
callback: function(r) {
if(r.message) {
frm.set_value('taxes_and_charges', r.message.taxes_and_charges);
+ frm.set_value('place_of_supply', r.message.place_of_supply);
} else if (frm.doc.is_internal_supplier || frm.doc.is_internal_customer) {
frm.set_value('taxes_and_charges', '');
frm.set_value('taxes', []);
diff --git a/erpnext/regional/india/utils.py b/erpnext/regional/india/utils.py
index 7ad1c07f93..54083dea84 100644
--- a/erpnext/regional/india/utils.py
+++ b/erpnext/regional/india/utils.py
@@ -135,12 +135,8 @@ def test_method():
'''test function'''
return 'overridden'
-@frappe.whitelist()
def get_place_of_supply(party_details, doctype):
if not frappe.get_meta('Address').has_field('gst_state'): return
- if isinstance(party_details, string_types):
- party_details = json.loads(party_details)
- party_details = frappe._dict(party_details)
if doctype in ("Sales Invoice", "Delivery Note", "Sales Order"):
address_name = party_details.customer_address or party_details.shipping_address_name
@@ -164,7 +160,7 @@ def get_regional_address_details(party_details, doctype, company, return_taxes=N
if is_internal_transfer(party_details, doctype):
party_details.taxes_and_charges = ''
party_details.taxes = ''
- return
+ return party_details
if doctype in ("Sales Invoice", "Delivery Note", "Sales Order"):
master_doctype = "Sales Taxes and Charges Template"
@@ -172,26 +168,26 @@ def get_regional_address_details(party_details, doctype, company, return_taxes=N
get_tax_template_for_sez(party_details, master_doctype, company, 'Customer')
get_tax_template_based_on_category(master_doctype, company, party_details)
- if party_details.get('taxes_and_charges') and return_taxes:
+ if party_details.get('taxes_and_charges'):
return party_details
if not party_details.company_gstin:
- return
+ return party_details
elif doctype in ("Purchase Invoice", "Purchase Order", "Purchase Receipt"):
master_doctype = "Purchase Taxes and Charges Template"
get_tax_template_for_sez(party_details, master_doctype, company, 'Supplier')
get_tax_template_based_on_category(master_doctype, company, party_details)
- if party_details.get('taxes_and_charges') and return_taxes:
+ if party_details.get('taxes_and_charges'):
return party_details
if not party_details.supplier_gstin:
- return
+ return party_details
- if not party_details.place_of_supply: return
+ if not party_details.place_of_supply: return party_details
- if not party_details.company_gstin: return
+ if not party_details.company_gstin: return party_details
if ((doctype in ("Sales Invoice", "Delivery Note", "Sales Order") and party_details.company_gstin
and party_details.company_gstin[:2] != party_details.place_of_supply[:2]) or (doctype in ("Purchase Invoice",
@@ -201,12 +197,11 @@ def get_regional_address_details(party_details, doctype, company, return_taxes=N
default_tax = get_tax_template(master_doctype, company, 0, party_details.company_gstin[:2])
if not default_tax:
- return
+ return party_details
party_details["taxes_and_charges"] = default_tax
party_details.taxes = get_taxes_and_charges(master_doctype, default_tax)
- if return_taxes:
- return party_details
+ return party_details
def is_internal_transfer(party_details, doctype):
if doctype in ("Sales Invoice", "Delivery Note", "Sales Order"):
diff --git a/erpnext/selling/sales_common.js b/erpnext/selling/sales_common.js
index 77bdf2912f..002cfe41e1 100644
--- a/erpnext/selling/sales_common.js
+++ b/erpnext/selling/sales_common.js
@@ -117,7 +117,6 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({
customer_address: function() {
erpnext.utils.get_address_display(this.frm, "customer_address");
erpnext.utils.set_taxes_from_address(this.frm, "customer_address", "customer_address", "shipping_address_name");
- erpnext.utils.set_place_of_supply(this.frm)
},
shipping_address_name: function() {
From 410db04b48291e310b981b541279d0930dcf4eed Mon Sep 17 00:00:00 2001
From: pateljannat
Date: Wed, 18 Nov 2020 15:57:16 +0530
Subject: [PATCH 04/18] fix: linter issue for translation syntax
---
erpnext/regional/india/utils.py | 23 ++++++++++++-----------
1 file changed, 12 insertions(+), 11 deletions(-)
diff --git a/erpnext/regional/india/utils.py b/erpnext/regional/india/utils.py
index 227af9cdeb..e189da7b11 100644
--- a/erpnext/regional/india/utils.py
+++ b/erpnext/regional/india/utils.py
@@ -86,7 +86,7 @@ def validate_gstin_check_digit(gstin, label='GSTIN'):
factor = 2 if factor == 1 else 1
if gstin[-1] != code_point_chars[((mod - (total % mod)) % mod)]:
frappe.throw(_("""Invalid {0}! The check digit validation has failed.
- Please ensure you've typed the {0} correctly.""".format(label)))
+ Please ensure you've typed the {0} correctly.""").format(label))
def get_itemised_tax_breakup_header(item_doctype, tax_accounts):
if frappe.get_meta(item_doctype).has_field('gst_hsn_code'):
@@ -160,7 +160,7 @@ def get_regional_address_details(party_details, doctype, company, return_taxes=N
if is_internal_transfer(party_details, doctype):
party_details.taxes_and_charges = ''
party_details.taxes = ''
- return party_details
+ return
if doctype in ("Sales Invoice", "Delivery Note", "Sales Order"):
master_doctype = "Sales Taxes and Charges Template"
@@ -168,26 +168,26 @@ def get_regional_address_details(party_details, doctype, company, return_taxes=N
get_tax_template_for_sez(party_details, master_doctype, company, 'Customer')
get_tax_template_based_on_category(master_doctype, company, party_details)
- if party_details.get('taxes_and_charges'):
+ if party_details.get('taxes_and_charges') and return_taxes:
return party_details
if not party_details.company_gstin:
- return party_details
+ return
elif doctype in ("Purchase Invoice", "Purchase Order", "Purchase Receipt"):
master_doctype = "Purchase Taxes and Charges Template"
get_tax_template_for_sez(party_details, master_doctype, company, 'Supplier')
get_tax_template_based_on_category(master_doctype, company, party_details)
- if party_details.get('taxes_and_charges'):
+ if party_details.get('taxes_and_charges') and return_taxes:
return party_details
if not party_details.supplier_gstin:
- return party_details
+ return
- if not party_details.place_of_supply: return party_details
+ if not party_details.place_of_supply: return
- if not party_details.company_gstin: return party_details
+ if not party_details.company_gstin: return
if ((doctype in ("Sales Invoice", "Delivery Note", "Sales Order") and party_details.company_gstin
and party_details.company_gstin[:2] != party_details.place_of_supply[:2]) or (doctype in ("Purchase Invoice",
@@ -197,11 +197,12 @@ def get_regional_address_details(party_details, doctype, company, return_taxes=N
default_tax = get_tax_template(master_doctype, company, 0, party_details.company_gstin[:2])
if not default_tax:
- return party_details
+ return
party_details["taxes_and_charges"] = default_tax
party_details.taxes = get_taxes_and_charges(master_doctype, default_tax)
- return party_details
+ if return_taxes:
+ return party_details
def is_internal_transfer(party_details, doctype):
if doctype in ("Sales Invoice", "Delivery Note", "Sales Order"):
@@ -235,7 +236,7 @@ def get_tax_template(master_doctype, company, is_inter_state, state_code):
if tax_category.gst_state == number_state_mapping[state_code] or \
(not default_tax and not tax_category.gst_state):
default_tax = frappe.db.get_value(master_doctype,
- {'company': company, 'disabled': 0, 'tax_category': tax_category.name}, 'name')
+ {'disabled': 0, 'tax_category': tax_category.name}, 'name')
return default_tax
def get_tax_template_for_sez(party_details, master_doctype, company, party_type):
From cd05b34691d7ef50d06791820afddb184259e1b3 Mon Sep 17 00:00:00 2001
From: pateljannat
Date: Thu, 19 Nov 2020 11:37:08 +0530
Subject: [PATCH 05/18] fix: company filter added again
---
erpnext/regional/india/utils.py | 21 ++++++++++-----------
1 file changed, 10 insertions(+), 11 deletions(-)
diff --git a/erpnext/regional/india/utils.py b/erpnext/regional/india/utils.py
index e189da7b11..c6620aa92b 100644
--- a/erpnext/regional/india/utils.py
+++ b/erpnext/regional/india/utils.py
@@ -160,7 +160,7 @@ def get_regional_address_details(party_details, doctype, company, return_taxes=N
if is_internal_transfer(party_details, doctype):
party_details.taxes_and_charges = ''
party_details.taxes = ''
- return
+ return party_details
if doctype in ("Sales Invoice", "Delivery Note", "Sales Order"):
master_doctype = "Sales Taxes and Charges Template"
@@ -168,26 +168,26 @@ def get_regional_address_details(party_details, doctype, company, return_taxes=N
get_tax_template_for_sez(party_details, master_doctype, company, 'Customer')
get_tax_template_based_on_category(master_doctype, company, party_details)
- if party_details.get('taxes_and_charges') and return_taxes:
+ if party_details.get('taxes_and_charges'):
return party_details
if not party_details.company_gstin:
- return
+ return party_details
elif doctype in ("Purchase Invoice", "Purchase Order", "Purchase Receipt"):
master_doctype = "Purchase Taxes and Charges Template"
get_tax_template_for_sez(party_details, master_doctype, company, 'Supplier')
get_tax_template_based_on_category(master_doctype, company, party_details)
- if party_details.get('taxes_and_charges') and return_taxes:
+ if party_details.get('taxes_and_charges'):
return party_details
if not party_details.supplier_gstin:
- return
+ return party_details
- if not party_details.place_of_supply: return
+ if not party_details.place_of_supply: return party_details
- if not party_details.company_gstin: return
+ if not party_details.company_gstin: return party_details
if ((doctype in ("Sales Invoice", "Delivery Note", "Sales Order") and party_details.company_gstin
and party_details.company_gstin[:2] != party_details.place_of_supply[:2]) or (doctype in ("Purchase Invoice",
@@ -197,12 +197,11 @@ def get_regional_address_details(party_details, doctype, company, return_taxes=N
default_tax = get_tax_template(master_doctype, company, 0, party_details.company_gstin[:2])
if not default_tax:
- return
+ return party_details
party_details["taxes_and_charges"] = default_tax
party_details.taxes = get_taxes_and_charges(master_doctype, default_tax)
- if return_taxes:
- return party_details
+ return party_details
def is_internal_transfer(party_details, doctype):
if doctype in ("Sales Invoice", "Delivery Note", "Sales Order"):
@@ -236,7 +235,7 @@ def get_tax_template(master_doctype, company, is_inter_state, state_code):
if tax_category.gst_state == number_state_mapping[state_code] or \
(not default_tax and not tax_category.gst_state):
default_tax = frappe.db.get_value(master_doctype,
- {'disabled': 0, 'tax_category': tax_category.name}, 'name')
+ {'company': company, 'disabled': 0, 'tax_category': tax_category.name}, 'name')
return default_tax
def get_tax_template_for_sez(party_details, master_doctype, company, party_type):
From f0b1670abc331bf7aad8eb7d746482648b710e65 Mon Sep 17 00:00:00 2001
From: Rohit Waghchaure
Date: Thu, 19 Nov 2020 18:40:13 +0530
Subject: [PATCH 06/18] fix: tds test case
---
.../test_tax_withholding_category.py | 12 ++++++++----
.../buying/doctype/supplier/test_supplier.py | 17 +++++++++++++++++
2 files changed, 25 insertions(+), 4 deletions(-)
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 a0b0cbb995..ef77674372 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
@@ -7,6 +7,7 @@ import frappe
import unittest
from frappe.utils import today
from erpnext.accounts.utils import get_fiscal_year
+from erpnext.buying.doctype.supplier.test_supplier import create_supplier
test_dependencies = ["Supplier Group"]
@@ -103,17 +104,20 @@ class TestTaxWithholdingCategory(unittest.TestCase):
def test_single_threshold_tds_with_previous_vouchers_and_no_tds(self):
invoices = []
- frappe.db.set_value("Supplier", "Test TDS Supplier2", "tax_withholding_category", "Single Threshold TDS")
- pi = create_purchase_invoice(supplier="Test TDS Supplier2")
+ doc = create_supplier(supplier_name = "Test TDS Supplier ABC",
+ tax_withholding_category="Single Threshold TDS")
+ supplier = doc.name
+
+ pi = create_purchase_invoice(supplier=supplier)
pi.submit()
invoices.append(pi)
# TDS not applied
- pi = create_purchase_invoice(supplier="Test TDS Supplier2", do_not_apply_tds=True)
+ pi = create_purchase_invoice(supplier=supplier, do_not_apply_tds=True)
pi.submit()
invoices.append(pi)
- pi = create_purchase_invoice(supplier="Test TDS Supplier2")
+ pi = create_purchase_invoice(supplier=supplier)
pi.submit()
invoices.append(pi)
diff --git a/erpnext/buying/doctype/supplier/test_supplier.py b/erpnext/buying/doctype/supplier/test_supplier.py
index a377ec90f8..f9c8d35518 100644
--- a/erpnext/buying/doctype/supplier/test_supplier.py
+++ b/erpnext/buying/doctype/supplier/test_supplier.py
@@ -120,3 +120,20 @@ class TestSupplier(unittest.TestCase):
# Rollback
address.delete()
+
+def create_supplier(**args):
+ args = frappe._dict(args)
+
+ try:
+ doc = frappe.get_doc({
+ "doctype": "Supplier",
+ "supplier_name": args.supplier_name,
+ "supplier_group": args.supplier_group or "Services",
+ "supplier_type": args.supplier_type or "Company",
+ "tax_withholding_category": args.tax_withholding_category
+ }).insert()
+
+ return doc
+
+ except frappe.DuplicateEntryError:
+ return frappe.get_doc("Supplier", args.supplier_name)
\ No newline at end of file
From 1d5d863e9a7e71c540e9ba032ef042e218667a56 Mon Sep 17 00:00:00 2001
From: pateljannat
Date: Thu, 19 Nov 2020 20:11:45 +0530
Subject: [PATCH 07/18] fix: removing return_taxes condition
---
erpnext/regional/india/taxes.js | 3 +--
erpnext/regional/india/utils.py | 2 +-
2 files changed, 2 insertions(+), 3 deletions(-)
diff --git a/erpnext/regional/india/taxes.js b/erpnext/regional/india/taxes.js
index ecfa9b7cdf..3c156479c5 100644
--- a/erpnext/regional/india/taxes.js
+++ b/erpnext/regional/india/taxes.js
@@ -31,8 +31,7 @@ erpnext.setup_auto_gst_taxation = (doctype) => {
args: {
party_details: JSON.stringify(party_details),
doctype: frm.doc.doctype,
- company: frm.doc.company,
- return_taxes: 1
+ company: frm.doc.company
},
callback: function(r) {
if(r.message) {
diff --git a/erpnext/regional/india/utils.py b/erpnext/regional/india/utils.py
index c6620aa92b..8d89335717 100644
--- a/erpnext/regional/india/utils.py
+++ b/erpnext/regional/india/utils.py
@@ -150,7 +150,7 @@ def get_place_of_supply(party_details, doctype):
return cstr(address.gst_state_number) + "-" + cstr(address.gst_state)
@frappe.whitelist()
-def get_regional_address_details(party_details, doctype, company, return_taxes=None):
+def get_regional_address_details(party_details, doctype, company):
if isinstance(party_details, string_types):
party_details = json.loads(party_details)
party_details = frappe._dict(party_details)
From ceab692f7313acfb11704dd50a72738a9c3be9c0 Mon Sep 17 00:00:00 2001
From: Rohit Waghchaure
Date: Wed, 18 Nov 2020 17:57:35 +0530
Subject: [PATCH 08/18] fix: incorrect delink serial no and batch
---
erpnext/controllers/stock_controller.py | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py
index f743d707f7..2d2fff8fd5 100644
--- a/erpnext/controllers/stock_controller.py
+++ b/erpnext/controllers/stock_controller.py
@@ -229,9 +229,9 @@ class StockController(AccountsController):
def check_expense_account(self, item):
if not item.get("expense_account"):
- frappe.throw(_("Row #{0}: Expense Account not set for Item {1}. Please set an Expense \
- Account in the Items table").format(item.idx, frappe.bold(item.item_code)),
- title=_("Expense Account Missing"))
+ msg = _("Please set an Expense Account in the Items table")
+ frappe.throw(_("Row #{0}: Expense Account not set for the Item {1}. {2}")
+ .format(item.idx, frappe.bold(item.item_code), msg), title=_("Expense Account Missing"))
else:
is_expense_account = frappe.db.get_value("Account",
@@ -247,7 +247,9 @@ class StockController(AccountsController):
for d in self.items:
if not d.batch_no: continue
- serial_nos = [sr.name for sr in frappe.get_all("Serial No", {'batch_no': d.batch_no})]
+ serial_nos = [sr.name for sr in frappe.get_all("Serial No",
+ {'batch_no': d.batch_no, 'status': 'Inactive'})]
+
if serial_nos:
frappe.db.set_value("Serial No", { 'name': ['in', serial_nos] }, "batch_no", None)
From 34d07b630669a6d18e3289df9561a50dcc3371fa Mon Sep 17 00:00:00 2001
From: Jannat Patel <31363128+pateljannat@users.noreply.github.com>
Date: Fri, 20 Nov 2020 19:22:35 +0530
Subject: [PATCH 09/18] fix: purchase receipt to purchase invoice bill date
mapping (#23967)
Co-authored-by: pateljannat
---
erpnext/stock/doctype/purchase_receipt/purchase_receipt.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
index d964669830..2cc4679c8c 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
@@ -572,7 +572,8 @@ def make_purchase_invoice(source_name, target_doc=None):
"doctype": "Purchase Invoice",
"field_map": {
"supplier_warehouse":"supplier_warehouse",
- "is_return": "is_return"
+ "is_return": "is_return",
+ "bill_date": "bill_date"
},
"validation": {
"docstatus": ["=", 1],
From 610d9ca64937366da56ad2ef7610def4c5d36b57 Mon Sep 17 00:00:00 2001
From: Rohit Waghchaure
Date: Mon, 23 Nov 2020 13:47:49 +0530
Subject: [PATCH 10/18] fix: bom stock report color issue
---
.../report/bom_stock_report/bom_stock_report.js | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/erpnext/manufacturing/report/bom_stock_report/bom_stock_report.js b/erpnext/manufacturing/report/bom_stock_report/bom_stock_report.js
index 2ac6fa073b..45331c6af8 100644
--- a/erpnext/manufacturing/report/bom_stock_report/bom_stock_report.js
+++ b/erpnext/manufacturing/report/bom_stock_report/bom_stock_report.js
@@ -25,11 +25,11 @@ frappe.query_reports["BOM Stock Report"] = {
],
"formatter": function(value, row, column, data, default_formatter) {
value = default_formatter(value, row, column, data);
- if (column.id == "Item"){
+ if (column.id == "item"){
if (data["Enough Parts to Build"] > 0){
- value = `${data['Item']}`
+ value = `${data['item']}`;
} else {
- value = `${data['Item']}`
+ value = `${data['item']}`;
}
}
return value
From 34f381df172f7c40db4f51317a22d8f29868b0d3 Mon Sep 17 00:00:00 2001
From: pateljannat
Date: Mon, 23 Nov 2020 15:31:08 +0530
Subject: [PATCH 11/18] fix: enabling track changes for stock settings
---
erpnext/stock/doctype/stock_settings/stock_settings.json | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/erpnext/stock/doctype/stock_settings/stock_settings.json b/erpnext/stock/doctype/stock_settings/stock_settings.json
index 067659f64a..a1666579d1 100644
--- a/erpnext/stock/doctype/stock_settings/stock_settings.json
+++ b/erpnext/stock/doctype/stock_settings/stock_settings.json
@@ -217,7 +217,7 @@
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
- "modified": "2020-10-13 10:33:29.147682",
+ "modified": "2020-11-23 15:26:54.225608",
"modified_by": "Administrator",
"module": "Stock",
"name": "Stock Settings",
@@ -235,5 +235,6 @@
],
"quick_entry": 1,
"sort_field": "modified",
- "sort_order": "ASC"
+ "sort_order": "ASC",
+ "track_changes": 1
}
\ No newline at end of file
From f9a44000d9b06517dc2fd10916eac3f8d0c02b8e Mon Sep 17 00:00:00 2001
From: rohitwaghchaure
Date: Mon, 23 Nov 2020 15:40:06 +0530
Subject: [PATCH 12/18] Update bom_stock_report.js
---
.../manufacturing/report/bom_stock_report/bom_stock_report.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/erpnext/manufacturing/report/bom_stock_report/bom_stock_report.js b/erpnext/manufacturing/report/bom_stock_report/bom_stock_report.js
index 45331c6af8..84f5c346ca 100644
--- a/erpnext/manufacturing/report/bom_stock_report/bom_stock_report.js
+++ b/erpnext/manufacturing/report/bom_stock_report/bom_stock_report.js
@@ -25,8 +25,8 @@ frappe.query_reports["BOM Stock Report"] = {
],
"formatter": function(value, row, column, data, default_formatter) {
value = default_formatter(value, row, column, data);
- if (column.id == "item"){
- if (data["Enough Parts to Build"] > 0){
+ if (column.id == "item") {
+ if (data["Enough Parts to Build"] > 0) {
value = `${data['item']}`;
} else {
value = `${data['item']}`;
From 6aa6ec1832d9c4caf00e4f113845b47f80dd92bb Mon Sep 17 00:00:00 2001
From: Afshan <33727827+AfshanKhan@users.noreply.github.com>
Date: Tue, 24 Nov 2020 08:01:19 +0530
Subject: [PATCH 13/18] fix: clear error message when approval not available
(#23971)
---
.../department_approver/department_approver.py | 12 +++++-------
1 file changed, 5 insertions(+), 7 deletions(-)
diff --git a/erpnext/hr/doctype/department_approver/department_approver.py b/erpnext/hr/doctype/department_approver/department_approver.py
index 9b2de0e1cb..d337959d53 100644
--- a/erpnext/hr/doctype/department_approver/department_approver.py
+++ b/erpnext/hr/doctype/department_approver/department_approver.py
@@ -20,7 +20,7 @@ def get_approvers(doctype, txt, searchfield, start, page_len, filters):
approvers = []
department_details = {}
department_list = []
- employee = frappe.get_value("Employee", filters.get("employee"), ["department", "leave_approver", "expense_approver", "shift_request_approver"], as_dict=True)
+ employee = frappe.get_value("Employee", filters.get("employee"), ["employee_name","department", "leave_approver", "expense_approver", "shift_request_approver"], as_dict=True)
employee_department = filters.get("department") or employee.department
if employee_department:
@@ -59,11 +59,9 @@ def get_approvers(doctype, txt, searchfield, start, page_len, filters):
and approver.approver=user.name""",(d, "%" + txt + "%", parentfield), as_list=True)
if len(approvers) == 0:
- frappe.throw(_("Please set {0} for the Employee or for Department: {1}").
- format(
- field_name, frappe.bold(employee_department),
- frappe.bold(employee.name)
- ),
- title=_(field_name + " Missing"))
+ error_msg = _("Please set {0} for the Employee: {1}").format(field_name, frappe.bold(employee.employee_name))
+ if department_list:
+ error_msg += _(" or for Department: {0}").format(frappe.bold(employee_department))
+ frappe.throw(error_msg, title=_(field_name + " Missing"))
return set(tuple(approver) for approver in approvers)
From d07447aa5fbeed93e72e882230e6b571a47b6611 Mon Sep 17 00:00:00 2001
From: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com>
Date: Tue, 24 Nov 2020 08:09:17 +0530
Subject: [PATCH 14/18] fix: Validation for duplicate Tax Category (#23978)
* fix: Validation for duplicate Tax Category
* Update utils.py
Co-authored-by: Nabin Hait
---
erpnext/hooks.py | 3 +++
erpnext/regional/india/utils.py | 14 ++++++++++----
2 files changed, 13 insertions(+), 4 deletions(-)
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index b4c57d7c91..741176f33f 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -237,6 +237,9 @@ doc_events = {
"Website Settings": {
"validate": "erpnext.portal.doctype.products_settings.products_settings.home_page_is_products"
},
+ "Tax Category": {
+ "validate": "erpnext.regional.india.utils.validate_tax_category"
+ },
"Sales Invoice": {
"on_submit": [
"erpnext.regional.create_transaction_log",
diff --git a/erpnext/regional/india/utils.py b/erpnext/regional/india/utils.py
index fc38ed0972..62487ba2aa 100644
--- a/erpnext/regional/india/utils.py
+++ b/erpnext/regional/india/utils.py
@@ -51,6 +51,13 @@ def validate_gstin_for_india(doc, method):
frappe.throw(_("Invalid GSTIN! First 2 digits of GSTIN should match with State number {0}.")
.format(doc.gst_state_number))
+def validate_tax_category(doc, method):
+ if doc.get('gst_state') and frappe.db.get_value('Tax category', {'gst_state': doc.gst_state, 'is_inter_state': doc.is_inter_state}):
+ if doc.is_inter_state:
+ frappe.throw(_("Inter State tax category for GST State {0} already exists").format(doc.gst_state))
+ else:
+ frappe.throw(_("Intra State tax category for GST State {0} already exists").format(doc.gst_state))
+
def update_gst_category(doc, method):
for link in doc.links:
if link.link_doctype in ['Customer', 'Supplier']:
@@ -85,8 +92,7 @@ def validate_gstin_check_digit(gstin, label='GSTIN'):
total += digit
factor = 2 if factor == 1 else 1
if gstin[-1] != code_point_chars[((mod - (total % mod)) % mod)]:
- frappe.throw(_("""Invalid {0}! The check digit validation has failed.
- Please ensure you've typed the {0} correctly.""").format(label))
+ frappe.throw(_("""Invalid {0}! The check digit validation has failed. Please ensure you've typed the {0} correctly.""").format(label))
def get_itemised_tax_breakup_header(item_doctype, tax_accounts):
if frappe.get_meta(item_doctype).has_field('gst_hsn_code'):
@@ -515,7 +521,7 @@ def get_address_details(data, doc, company_address, billing_address):
data.transType = 1
data.actualToStateCode = data.toStateCode
shipping_address = billing_address
-
+
if doc.gst_category == 'SEZ':
data.toStateCode = 99
@@ -754,4 +760,4 @@ def make_regional_gl_entries(gl_entries, doc):
}, account_currency, item=tax)
)
- return gl_entries
\ No newline at end of file
+ return gl_entries
From e09037ed2c1e5cf634fbd993e1d135cae84b0673 Mon Sep 17 00:00:00 2001
From: Krushnal Patel
Date: Tue, 24 Nov 2020 12:53:30 +0530
Subject: [PATCH 15/18] docs: README build status badge (#23933)
* fixed build status badge
* changed build branch from `master` to `develop`
* updated build status badge url
* Update README.md
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 0f6a52142b..15782a2e0c 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,7 @@
ERP made simple
-[](https://travis-ci.com/frappe/erpnext)
+[](https://travis-ci.com/frappe/erpnext)
[](https://www.codetriage.com/frappe/erpnext)
[](https://coveralls.io/github/frappe/erpnext?branch=develop)
From 927106f5528bfebe8d43ae24ac627ae9965720d5 Mon Sep 17 00:00:00 2001
From: Anurag Mishra
Date: Tue, 24 Nov 2020 15:02:52 +0530
Subject: [PATCH 16/18] fix: maintain stock can't be changed it there is
product bundle
---
erpnext/stock/doctype/item/item.py | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py
index 3b62c38b86..be845d9d9d 100644
--- a/erpnext/stock/doctype/item/item.py
+++ b/erpnext/stock/doctype/item/item.py
@@ -977,15 +977,20 @@ class Item(WebsiteGenerator):
# For "Is Stock Item", following doctypes is important
# because reserved_qty, ordered_qty and requested_qty updated from these doctypes
if field == "is_stock_item":
- linked_doctypes += ["Sales Order Item", "Purchase Order Item", "Material Request Item"]
+ linked_doctypes += ["Sales Order Item", "Purchase Order Item", "Material Request Item", "Product Bundle"]
for doctype in linked_doctypes:
+ filters={"item_code": self.name, "docstatus": 1}
+
+ if doctype == "Product Bundle":
+ filters={"new_item_code": self.name}
+
if doctype in ("Purchase Invoice Item", "Sales Invoice Item",):
# If Invoice has Stock impact, only then consider it.
if self.stock_ledger_created():
return True
- elif frappe.db.get_value(doctype, filters={"item_code": self.name, "docstatus": 1}):
+ elif frappe.db.get_value(doctype, filters):
return True
def validate_auto_reorder_enabled_in_stock_settings(self):
From 43a830f3f593f463f695c7419e1b7961ff96d79d Mon Sep 17 00:00:00 2001
From: Deepesh Garg
Date: Tue, 24 Nov 2020 15:10:36 +0530
Subject: [PATCH 17/18] fix: Old shopify order syncing date
---
.../connectors/shopify_connection.py | 18 ++++++++++--------
1 file changed, 10 insertions(+), 8 deletions(-)
diff --git a/erpnext/erpnext_integrations/connectors/shopify_connection.py b/erpnext/erpnext_integrations/connectors/shopify_connection.py
index 8aa7453bd6..efbaa71924 100644
--- a/erpnext/erpnext_integrations/connectors/shopify_connection.py
+++ b/erpnext/erpnext_integrations/connectors/shopify_connection.py
@@ -149,26 +149,28 @@ def create_sales_invoice(shopify_order, shopify_settings, so, old_order_sync=Fal
si.shopify_order_number = shopify_order.get("name")
si.set_posting_time = 1
si.posting_date = posting_date
+ si.due_date = posting_date
si.naming_series = shopify_settings.sales_invoice_series or "SI-Shopify-"
si.flags.ignore_mandatory = True
set_cost_center(si.items, shopify_settings.cost_center)
si.insert(ignore_mandatory=True)
si.submit()
- make_payament_entry_against_sales_invoice(si, shopify_settings)
+ make_payament_entry_against_sales_invoice(si, shopify_settings, posting_date)
frappe.db.commit()
def set_cost_center(items, cost_center):
for item in items:
item.cost_center = cost_center
-def make_payament_entry_against_sales_invoice(doc, shopify_settings):
+def make_payament_entry_against_sales_invoice(doc, shopify_settings, posting_date=None):
from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry
- payemnt_entry = get_payment_entry(doc.doctype, doc.name, bank_account=shopify_settings.cash_bank_account)
- payemnt_entry.flags.ignore_mandatory = True
- payemnt_entry.reference_no = doc.name
- payemnt_entry.reference_date = nowdate()
- payemnt_entry.insert(ignore_permissions=True)
- payemnt_entry.submit()
+ payment_entry = get_payment_entry(doc.doctype, doc.name, bank_account=shopify_settings.cash_bank_account)
+ payment_entry.flags.ignore_mandatory = True
+ payment_entry.reference_no = doc.name
+ payment_entry.posting_date = posting_date or nowdate()
+ payment_entry.reference_date = posting_date or nowdate()
+ payment_entry.insert(ignore_permissions=True)
+ payment_entry.submit()
def create_delivery_note(shopify_order, shopify_settings, so):
if not cint(shopify_settings.sync_delivery_note):
From b67ebc7636187f1e4ee508579a77cbb6a7e223d1 Mon Sep 17 00:00:00 2001
From: pateljannat
Date: Tue, 24 Nov 2020 15:37:30 +0530
Subject: [PATCH 18/18] fix: job card error handling for operations field
---
.../doctype/job_card/job_card.py | 22 ++++++++++---------
1 file changed, 12 insertions(+), 10 deletions(-)
diff --git a/erpnext/manufacturing/doctype/job_card/job_card.py b/erpnext/manufacturing/doctype/job_card/job_card.py
index 4dfa78bf21..d15d81ed93 100644
--- a/erpnext/manufacturing/doctype/job_card/job_card.py
+++ b/erpnext/manufacturing/doctype/job_card/job_card.py
@@ -353,17 +353,19 @@ def get_operation_details(work_order, operation):
@frappe.whitelist()
def get_operations(doctype, txt, searchfield, start, page_len, filters):
- if filters.get("work_order"):
- args = {"parent": filters.get("work_order")}
- if txt:
- args["operation"] = ("like", "%{0}%".format(txt))
+ if not filters.get("work_order"):
+ frappe.msgprint(_("Please select a Work Order first."))
+ return []
+ args = {"parent": filters.get("work_order")}
+ if txt:
+ args["operation"] = ("like", "%{0}%".format(txt))
- return frappe.get_all("Work Order Operation",
- filters = args,
- fields = ["distinct operation as operation"],
- limit_start = start,
- limit_page_length = page_len,
- order_by="idx asc", as_list=1)
+ return frappe.get_all("Work Order Operation",
+ filters = args,
+ fields = ["distinct operation as operation"],
+ limit_start = start,
+ limit_page_length = page_len,
+ order_by="idx asc", as_list=1)
@frappe.whitelist()
def make_material_request(source_name, target_doc=None):