Merge branch 'version-13-hotfix' into version-13-pre-release

This commit is contained in:
Nabin Hait 2021-06-24 20:16:04 +05:30
commit 67768faaef
13 changed files with 75 additions and 39 deletions

View File

@ -19,7 +19,7 @@ class AccountingDimension(Document):
def validate(self): def validate(self):
if self.document_type in core_doctypes_list + ('Accounting Dimension', 'Project', if self.document_type in core_doctypes_list + ('Accounting Dimension', 'Project',
'Cost Center', 'Accounting Dimension Detail', 'Company') : 'Cost Center', 'Accounting Dimension Detail', 'Company', 'Account') :
msg = _("Not allowed to create accounting dimension for {0}").format(self.document_type) msg = _("Not allowed to create accounting dimension for {0}").format(self.document_type)
frappe.throw(msg) frappe.throw(msg)

View File

@ -690,7 +690,7 @@
"options": "Account" "options": "Account"
}, },
{ {
"depends_on": "eval:doc.received_amount", "depends_on": "eval:doc.received_amount && doc.payment_type != 'Internal Transfer'",
"fieldname": "received_amount_after_tax", "fieldname": "received_amount_after_tax",
"fieldtype": "Currency", "fieldtype": "Currency",
"label": "Received Amount After Tax", "label": "Received Amount After Tax",
@ -707,7 +707,7 @@
"index_web_pages_for_search": 1, "index_web_pages_for_search": 1,
"is_submittable": 1, "is_submittable": 1,
"links": [], "links": [],
"modified": "2021-06-09 11:55:04.215050", "modified": "2021-06-22 20:37:06.154206",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Payment Entry", "name": "Payment Entry",

View File

@ -706,7 +706,7 @@ class PaymentEntry(AccountsController):
if account_currency != self.company_currency: if account_currency != self.company_currency:
frappe.throw(_("Currency for {0} must be {1}").format(d.account_head, self.company_currency)) frappe.throw(_("Currency for {0} must be {1}").format(d.account_head, self.company_currency))
if self.payment_type == 'Pay': if self.payment_type in ('Pay', 'Internal Transfer'):
dr_or_cr = "debit" if d.add_deduct_tax == "Add" else "credit" dr_or_cr = "debit" if d.add_deduct_tax == "Add" else "credit"
elif self.payment_type == 'Receive': elif self.payment_type == 'Receive':
dr_or_cr = "credit" if d.add_deduct_tax == "Add" else "debit" dr_or_cr = "credit" if d.add_deduct_tax == "Add" else "debit"
@ -761,7 +761,7 @@ class PaymentEntry(AccountsController):
return self.advance_tax_account return self.advance_tax_account
elif self.payment_type == 'Receive': elif self.payment_type == 'Receive':
return self.paid_from return self.paid_from
elif self.payment_type == 'Pay': elif self.payment_type in ('Pay', 'Internal Transfer'):
return self.paid_to return self.paid_to
def update_advance_paid(self): def update_advance_paid(self):

View File

@ -966,7 +966,7 @@ class TestPurchaseInvoice(unittest.TestCase):
update_tax_witholding_category('_Test Company', 'TDS Payable - _TC', nowdate()) update_tax_witholding_category('_Test Company', 'TDS Payable - _TC', nowdate())
# Create Purchase Order with TDS applied # Create Purchase Order with TDS applied
po = create_purchase_order(do_not_save=1, supplier=supplier.name, rate=3000) po = create_purchase_order(do_not_save=1, supplier=supplier.name, rate=3000, item='_Test Non Stock Item')
po.apply_tds = 1 po.apply_tds = 1
po.tax_withholding_category = 'TDS - 194 - Dividends - Individual' po.tax_withholding_category = 'TDS - 194 - Dividends - Individual'
po.save() po.save()
@ -1002,6 +1002,7 @@ class TestPurchaseInvoice(unittest.TestCase):
# Create Purchase Invoice against Purchase Order # Create Purchase Invoice against Purchase Order
purchase_invoice = get_mapped_purchase_invoice(po.name) purchase_invoice = get_mapped_purchase_invoice(po.name)
purchase_invoice.allocate_advances_automatically = 1 purchase_invoice.allocate_advances_automatically = 1
purchase_invoice.items[0].item_code = '_Test Non Stock Item'
purchase_invoice.items[0].expense_account = '_Test Account Cost for Goods Sold - _TC' purchase_invoice.items[0].expense_account = '_Test Account Cost for Goods Sold - _TC'
purchase_invoice.save() purchase_invoice.save()
purchase_invoice.submit() purchase_invoice.submit()

View File

@ -222,7 +222,7 @@ def get_gl_entries(filters, accounting_dimensions):
def get_conditions(filters): def get_conditions(filters):
conditions = [] conditions = []
if filters.get("account") and not filters.get("include_dimensions"): if filters.get("account"):
filters.account = get_accounts_with_children(filters.account) filters.account = get_accounts_with_children(filters.account)
conditions.append("account in %(account)s") conditions.append("account in %(account)s")

View File

@ -270,11 +270,14 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
let me = this; let me = this;
let item_codes = []; let item_codes = [];
let item_rates = {}; let item_rates = {};
let item_tax_templates = {};
$.each(this.frm.doc.items || [], function(i, item) { $.each(this.frm.doc.items || [], function(i, item) {
if (item.item_code) { if (item.item_code) {
// Use combination of name and item code in case same item is added multiple times // Use combination of name and item code in case same item is added multiple times
item_codes.push([item.item_code, item.name]); item_codes.push([item.item_code, item.name]);
item_rates[item.name] = item.net_rate; item_rates[item.name] = item.net_rate;
item_tax_templates[item.name] = item.item_tax_template;
} }
}); });
@ -285,18 +288,16 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
company: me.frm.doc.company, company: me.frm.doc.company,
tax_category: cstr(me.frm.doc.tax_category), tax_category: cstr(me.frm.doc.tax_category),
item_codes: item_codes, item_codes: item_codes,
item_rates: item_rates item_rates: item_rates,
item_tax_templates: item_tax_templates
}, },
callback: function(r) { callback: function(r) {
if (!r.exc) { if (!r.exc) {
$.each(me.frm.doc.items || [], function(i, item) { $.each(me.frm.doc.items || [], function(i, item) {
if (item.name && r.message.hasOwnProperty(item.name)) { if (item.name && r.message.hasOwnProperty(item.name) && r.message[item.name].item_tax_template) {
item.item_tax_template = r.message[item.name].item_tax_template; item.item_tax_template = r.message[item.name].item_tax_template;
item.item_tax_rate = r.message[item.name].item_tax_rate; item.item_tax_rate = r.message[item.name].item_tax_rate;
me.add_taxes_from_item_tax_template(item.item_tax_rate); me.add_taxes_from_item_tax_template(item.item_tax_rate);
} else {
item.item_tax_template = "";
item.item_tax_rate = "{}";
} }
}); });
} }

View File

@ -407,8 +407,6 @@ def replace_abbr(company, old, new):
frappe.only_for("System Manager") frappe.only_for("System Manager")
frappe.db.set_value("Company", company, "abbr", new)
def _rename_record(doc): def _rename_record(doc):
parts = doc[0].rsplit(" - ", 1) parts = doc[0].rsplit(" - ", 1)
if len(parts) == 1 or parts[1].lower() == old.lower(): if len(parts) == 1 or parts[1].lower() == old.lower():
@ -419,12 +417,19 @@ def replace_abbr(company, old, new):
doc = (d for d in frappe.db.sql("select name from `tab%s` where company=%s" % (dt, '%s'), company)) doc = (d for d in frappe.db.sql("select name from `tab%s` where company=%s" % (dt, '%s'), company))
for d in doc: for d in doc:
_rename_record(d) _rename_record(d)
try:
frappe.db.auto_commit_on_many_writes = 1
frappe.db.set_value("Company", company, "abbr", new)
for dt in ["Warehouse", "Account", "Cost Center", "Department", for dt in ["Warehouse", "Account", "Cost Center", "Department",
"Sales Taxes and Charges Template", "Purchase Taxes and Charges Template"]: "Sales Taxes and Charges Template", "Purchase Taxes and Charges Template"]:
_rename_records(dt) _rename_records(dt)
frappe.db.commit() frappe.db.commit()
except Exception:
frappe.log_error(title=_('Abbreviation Rename Error'))
finally:
frappe.db.auto_commit_on_many_writes = 0
def get_name_with_abbr(name, company): def get_name_with_abbr(name, company):
company_abbr = frappe.get_cached_value('Company', company, "abbr") company_abbr = frappe.get_cached_value('Company', company, "abbr")

View File

@ -226,9 +226,9 @@ def split_batch(batch_no, item_code, warehouse, qty, new_batch_id=None):
return batch.name return batch.name
def set_batch_nos(doc, warehouse_field, throw=False): def set_batch_nos(doc, warehouse_field, throw=False, child_table="items"):
"""Automatically select `batch_no` for outgoing items in item table""" """Automatically select `batch_no` for outgoing items in item table"""
for d in doc.items: for d in doc.get(child_table):
qty = d.get('stock_qty') or d.get('transfer_qty') or d.get('qty') or 0 qty = d.get('stock_qty') or d.get('transfer_qty') or d.get('qty') or 0
has_batch_no = frappe.db.get_value('Item', d.item_code, 'has_batch_no') has_batch_no = frappe.db.get_value('Item', d.item_code, 'has_batch_no')
warehouse = d.get(warehouse_field, None) warehouse = d.get(warehouse_field, None)

View File

@ -78,6 +78,9 @@ frappe.ui.form.on("Delivery Note", {
}); });
erpnext.accounts.dimensions.setup_dimension_filters(frm, frm.doctype); erpnext.accounts.dimensions.setup_dimension_filters(frm, frm.doctype);
frm.set_df_property('packed_items', 'cannot_add_rows', true);
frm.set_df_property('packed_items', 'cannot_delete_rows', true);
}, },
print_without_amount: function(frm) { print_without_amount: function(frm) {

View File

@ -554,8 +554,7 @@
"oldfieldname": "packing_details", "oldfieldname": "packing_details",
"oldfieldtype": "Table", "oldfieldtype": "Table",
"options": "Packed Item", "options": "Packed Item",
"print_hide": 1, "print_hide": 1
"read_only": 1
}, },
{ {
"fieldname": "product_bundle_help", "fieldname": "product_bundle_help",
@ -1289,7 +1288,7 @@
"idx": 146, "idx": 146,
"is_submittable": 1, "is_submittable": 1,
"links": [], "links": [],
"modified": "2021-04-15 23:55:49.620641", "modified": "2021-06-11 19:27:30.901112",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Stock", "module": "Stock",
"name": "Delivery Note", "name": "Delivery Note",

View File

@ -129,12 +129,13 @@ class DeliveryNote(SellingController):
self.validate_uom_is_integer("uom", "qty") self.validate_uom_is_integer("uom", "qty")
self.validate_with_previous_doc() self.validate_with_previous_doc()
if self._action != 'submit' and not self.is_return:
set_batch_nos(self, 'warehouse', True)
from erpnext.stock.doctype.packed_item.packed_item import make_packing_list from erpnext.stock.doctype.packed_item.packed_item import make_packing_list
make_packing_list(self) make_packing_list(self)
if self._action != 'submit' and not self.is_return:
set_batch_nos(self, 'warehouse', throw=True)
set_batch_nos(self, 'warehouse', throw=True, child_table="packed_items")
self.update_current_stock() self.update_current_stock()
if not self.installation_status: self.installation_status = 'Not Installed' if not self.installation_status: self.installation_status = 'Not Installed'

View File

@ -7,7 +7,7 @@ import unittest
import frappe import frappe
import json import json
import frappe.defaults import frappe.defaults
from frappe.utils import cint, nowdate, nowtime, cstr, add_days, flt, today from frappe.utils import nowdate, nowtime, cstr, flt
from erpnext.stock.stock_ledger import get_previous_sle from erpnext.stock.stock_ledger import get_previous_sle
from erpnext.accounts.utils import get_balance_on from erpnext.accounts.utils import get_balance_on
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import get_gl_entries from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import get_gl_entries
@ -18,9 +18,11 @@ from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos, SerialNoWa
from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation \ from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation \
import create_stock_reconciliation, set_valuation_method import create_stock_reconciliation, set_valuation_method
from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order, create_dn_against_so from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order, create_dn_against_so
from erpnext.accounts.doctype.account.test_account import get_inventory_account, create_account from erpnext.accounts.doctype.account.test_account import get_inventory_account
from erpnext.stock.doctype.warehouse.test_warehouse import get_warehouse from erpnext.stock.doctype.warehouse.test_warehouse import get_warehouse
from erpnext.stock.doctype.item.test_item import create_item from erpnext.stock.doctype.item.test_item import make_item
from erpnext.selling.doctype.product_bundle.test_product_bundle import make_product_bundle
class TestDeliveryNote(unittest.TestCase): class TestDeliveryNote(unittest.TestCase):
def test_over_billing_against_dn(self): def test_over_billing_against_dn(self):
@ -277,8 +279,6 @@ class TestDeliveryNote(unittest.TestCase):
dn.cancel() dn.cancel()
def test_sales_return_for_non_bundled_items_full(self): def test_sales_return_for_non_bundled_items_full(self):
from erpnext.stock.doctype.item.test_item import make_item
company = frappe.db.get_value('Warehouse', 'Stores - TCP1', 'company') company = frappe.db.get_value('Warehouse', 'Stores - TCP1', 'company')
make_item("Box", {'is_stock_item': 1}) make_item("Box", {'is_stock_item': 1})
@ -741,6 +741,25 @@ class TestDeliveryNote(unittest.TestCase):
self.assertEqual(si2.items[0].qty, 2) self.assertEqual(si2.items[0].qty, 2)
self.assertEqual(si2.items[1].qty, 1) self.assertEqual(si2.items[1].qty, 1)
def test_delivery_note_bundle_with_batched_item(self):
batched_bundle = make_item("_Test Batched bundle", {"is_stock_item": 0})
batched_item = make_item("_Test Batched Item",
{"is_stock_item": 1, "has_batch_no": 1, "create_new_batch": 1, "batch_number_series": "TESTBATCH.#####"}
)
make_product_bundle(parent=batched_bundle.name, items=[batched_item.name])
make_stock_entry(item_code=batched_item.name, target="_Test Warehouse - _TC", qty=10, basic_rate=42)
try:
dn = create_delivery_note(item_code=batched_bundle.name, qty=1)
except frappe.ValidationError as e:
if "batch" in str(e).lower():
self.fail("Batch numbers not getting added to bundled items in DN.")
raise e
self.assertTrue("TESTBATCH" in dn.packed_items[0].batch_no, "Batch number not added in packed item")
def create_delivery_note(**args): def create_delivery_note(**args):
dn = frappe.new_doc("Delivery Note") dn = frappe.new_doc("Delivery Note")
args = frappe._dict(args) args = frappe._dict(args)

View File

@ -436,20 +436,28 @@ def get_barcode_data(items_list):
return itemwise_barcode return itemwise_barcode
@frappe.whitelist() @frappe.whitelist()
def get_item_tax_info(company, tax_category, item_codes, item_rates=None): def get_item_tax_info(company, tax_category, item_codes, item_rates=None, item_tax_templates=None):
out = {} out = {}
if isinstance(item_codes, string_types): if isinstance(item_codes, (str,)):
item_codes = json.loads(item_codes) item_codes = json.loads(item_codes)
if isinstance(item_rates, string_types): if isinstance(item_rates, (str,)):
item_rates = json.loads(item_rates) item_rates = json.loads(item_rates)
if isinstance(item_tax_templates, (str,)):
item_tax_templates = json.loads(item_tax_templates)
for item_code in item_codes: for item_code in item_codes:
if not item_code or item_code[1] in out: if not item_code or item_code[1] in out or not item_tax_templates.get(item_code[1]):
continue continue
out[item_code[1]] = {} out[item_code[1]] = {}
item = frappe.get_cached_doc("Item", item_code[0]) item = frappe.get_cached_doc("Item", item_code[0])
args = {"company": company, "tax_category": tax_category, "net_rate": item_rates[item_code[1]]} args = {"company": company, "tax_category": tax_category, "net_rate": item_rates[item_code[1]]}
if item_tax_templates:
args.update({"item_tax_template": item_tax_templates.get(item_code[1])})
get_item_tax_template(args, item, out[item_code[1]]) get_item_tax_template(args, item, out[item_code[1]])
out[item_code[1]]["item_tax_rate"] = get_item_tax_map(company, out[item_code[1]].get("item_tax_template"), as_json=True) out[item_code[1]]["item_tax_rate"] = get_item_tax_map(company, out[item_code[1]].get("item_tax_template"), as_json=True)
@ -463,8 +471,6 @@ def get_item_tax_template(args, item, out):
} }
""" """
item_tax_template = args.get("item_tax_template") item_tax_template = args.get("item_tax_template")
if not item_tax_template:
item_tax_template = _get_item_tax_template(args, item.taxes, out) item_tax_template = _get_item_tax_template(args, item.taxes, out)
if not item_tax_template: if not item_tax_template:
@ -508,7 +514,8 @@ def _get_item_tax_template(args, taxes, out=None, for_validate=False):
return None return None
# do not change if already a valid template # do not change if already a valid template
if args.get('item_tax_template') in taxes: if args.get('item_tax_template') in {t.item_tax_template for t in taxes}:
out["item_tax_template"] = args.get('item_tax_template')
return args.get('item_tax_template') return args.get('item_tax_template')
for tax in taxes: for tax in taxes: