Merge branch 'version-13-hotfix' into version-13-pre-release
This commit is contained in:
commit
67768faaef
@ -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)
|
||||||
|
@ -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",
|
||||||
|
@ -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):
|
||||||
|
@ -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()
|
||||||
|
@ -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")
|
||||||
|
|
||||||
|
@ -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 = "{}";
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -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")
|
||||||
|
@ -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)
|
||||||
|
@ -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) {
|
||||||
|
@ -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",
|
||||||
|
@ -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'
|
||||||
|
@ -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)
|
||||||
|
@ -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:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user