diff --git a/erpnext/accounts/doctype/accounts_settings/accounts_settings.json b/erpnext/accounts/doctype/accounts_settings/accounts_settings.json
index d2f7de3be52..70e6e44d719 100644
--- a/erpnext/accounts/doctype/accounts_settings/accounts_settings.json
+++ b/erpnext/accounts/doctype/accounts_settings/accounts_settings.json
@@ -97,7 +97,7 @@
"default": "1",
"fieldname": "unlink_advance_payment_on_cancelation_of_order",
"fieldtype": "Check",
- "label": "Unlink Advance Payment on Cancelation of Order"
+ "label": "Unlink Advance Payment on Cancellation of Order"
},
{
"default": "1",
@@ -179,7 +179,7 @@
"icon": "icon-cog",
"idx": 1,
"issingle": 1,
- "modified": "2020-03-11 13:09:26.235848",
+ "modified": "2020-10-08 09:40:12.121145",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Accounts Settings",
diff --git a/erpnext/accounts/doctype/gl_entry/gl_entry.py b/erpnext/accounts/doctype/gl_entry/gl_entry.py
index cf1ad6eab6f..077a11a9be6 100644
--- a/erpnext/accounts/doctype/gl_entry/gl_entry.py
+++ b/erpnext/accounts/doctype/gl_entry/gl_entry.py
@@ -138,7 +138,7 @@ class GLEntry(Document):
frappe.throw(_("{0} {1}: Cost Center {2} does not belong to Company {3}")
.format(self.voucher_type, self.voucher_no, self.cost_center, self.company))
- if self.cost_center and _check_is_group():
+ if not self.flags.from_repost and self.cost_center and _check_is_group():
frappe.throw(_("""{0} {1}: Cost Center {2} is a group cost center and group cost centers cannot
be used in transactions""").format(self.voucher_type, self.voucher_no, frappe.bold(self.cost_center)))
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice_dashboard.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice_dashboard.py
index b35e32c5ca5..4be4c269f17 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice_dashboard.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice_dashboard.py
@@ -13,8 +13,7 @@ def get_data():
'Auto Repeat': 'reference_document',
},
'internal_links': {
- 'Sales Order': ['items', 'sales_order'],
- 'Delivery Note': ['items', 'delivery_note']
+ 'Sales Order': ['items', 'sales_order']
},
'transactions': [
{
diff --git a/erpnext/accounts/doctype/tax_rule/test_tax_rule.py b/erpnext/accounts/doctype/tax_rule/test_tax_rule.py
index bbbcc7f3a69..632e30db45d 100644
--- a/erpnext/accounts/doctype/tax_rule/test_tax_rule.py
+++ b/erpnext/accounts/doctype/tax_rule/test_tax_rule.py
@@ -6,6 +6,8 @@ from __future__ import unicode_literals
import frappe
import unittest
from erpnext.accounts.doctype.tax_rule.tax_rule import IncorrectCustomerGroup, IncorrectSupplierType, ConflictingTaxRule, get_tax_template
+from erpnext.crm.doctype.opportunity.test_opportunity import make_opportunity
+from erpnext.crm.doctype.opportunity.opportunity import make_quotation
test_records = frappe.get_test_records('Tax Rule')
@@ -144,6 +146,23 @@ class TestTaxRule(unittest.TestCase):
self.assertEqual(get_tax_template("2015-01-01", {"customer":"_Test Customer", "billing_city": "Test City 1"}),
"_Test Sales Taxes and Charges Template 1 - _TC")
+ def test_taxes_fetch_via_tax_rule(self):
+ make_tax_rule(customer= "_Test Customer", billing_city = "_Test City",
+ sales_tax_template = "_Test Sales Taxes and Charges Template - _TC", save=1)
+
+ # create opportunity for customer
+ opportunity = make_opportunity(with_items=1)
+
+ # make quotation from opportunity
+ quotation = make_quotation(opportunity.name)
+ quotation.save()
+
+ self.assertEqual(quotation.taxes_and_charges, "_Test Sales Taxes and Charges Template - _TC")
+
+ # Check if accounts heads and rate fetched are also fetched from tax template or not
+ self.assertTrue(len(quotation.taxes) > 0)
+
+
def make_tax_rule(**args):
args = frappe._dict(args)
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 b539fff74e9..f6a7218d601 100644
--- a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
+++ b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
@@ -106,6 +106,7 @@ def get_tds_amount(suppliers, net_total, company, tax_details, fiscal_year_detai
from `tabGL Entry`
where company = %s and
party in %s and fiscal_year=%s and credit > 0
+ and is_opening = 'No'
""", (company, tuple(suppliers), fiscal_year), as_dict=1)
vouchers = [d.voucher_no for d in entries]
@@ -139,9 +140,9 @@ def get_tds_amount(suppliers, net_total, company, tax_details, fiscal_year_detai
else:
tds_amount = _get_tds(net_total, tax_details.rate)
else:
- supplier_credit_amount = frappe.get_all('Purchase Invoice Item',
- fields = ['sum(net_amount)'],
- filters = {'parent': ('in', vouchers), 'docstatus': 1}, as_list=1)
+ supplier_credit_amount = frappe.get_all('Purchase Invoice',
+ fields = ['sum(net_total)'],
+ filters = {'name': ('in', vouchers), 'docstatus': 1, "apply_tds": 1}, as_list=1)
supplier_credit_amount = (supplier_credit_amount[0][0]
if supplier_credit_amount and supplier_credit_amount[0][0] else 0)
@@ -192,6 +193,7 @@ def get_advance_vouchers(suppliers, fiscal_year=None, company=None, from_date=No
select distinct voucher_no
from `tabGL Entry`
where party in %s and %s and debit > 0
+ and is_opening = 'No'
""", (tuple(suppliers), condition)) or []
def get_debit_note_amount(suppliers, year_start_date, year_end_date, company=None):
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 b1468999fc1..a0b0cbb9956 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
@@ -101,6 +101,29 @@ class TestTaxWithholdingCategory(unittest.TestCase):
for d in invoices:
d.cancel()
+ 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")
+ pi.submit()
+ invoices.append(pi)
+
+ # TDS not applied
+ pi = create_purchase_invoice(supplier="Test TDS Supplier2", do_not_apply_tds=True)
+ pi.submit()
+ invoices.append(pi)
+
+ pi = create_purchase_invoice(supplier="Test TDS Supplier2")
+ pi.submit()
+ invoices.append(pi)
+
+ self.assertEqual(pi.taxes_and_charges_deducted, 2000)
+ self.assertEqual(pi.grand_total, 8000)
+
+ # delete invoices to avoid clashing
+ for d in invoices:
+ d.cancel()
+
def create_purchase_invoice(**args):
# return sales invoice doc object
item = frappe.get_doc('Item', {'item_name': 'TDS Item'})
@@ -109,7 +132,7 @@ def create_purchase_invoice(**args):
pi = frappe.get_doc({
"doctype": "Purchase Invoice",
"posting_date": today(),
- "apply_tds": 1,
+ "apply_tds": 0 if args.do_not_apply_tds else 1,
"supplier": args.supplier,
"company": '_Test Company',
"taxes_and_charges": "",
diff --git a/erpnext/accounts/page/pos/pos.js b/erpnext/accounts/page/pos/pos.js
index cecf7f5e6fc..1e82e54cdf8 100755
--- a/erpnext/accounts/page/pos/pos.js
+++ b/erpnext/accounts/page/pos/pos.js
@@ -1064,7 +1064,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
$(frappe.render_template("pos_item", {
item_code: escape(obj.name),
item_price: item_price,
- title: obj.name || obj.item_name,
+ title: obj.name === obj.item_name ? obj.name : obj.item_name,
item_name: obj.name === obj.item_name ? "" : obj.item_name,
item_image: obj.image,
item_stock: __('Stock Qty') + ": " + me.get_actual_qty(obj),
@@ -1546,7 +1546,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
$.each(this.frm.doc.items || [], function (i, d) {
$(frappe.render_template("pos_bill_item_new", {
item_code: escape(d.item_code),
- title: d.item_code || d.item_name,
+ title: d.item_code === d.item_name ? d.item_code : d.item_name,
item_name: (d.item_name === d.item_code || !d.item_name) ? "" : ("
" + d.item_name),
qty: d.qty,
discount_percentage: d.discount_percentage || 0.0,
diff --git a/erpnext/accounts/report/financial_statements.html b/erpnext/accounts/report/financial_statements.html
index 50947ecf5ef..2bb09cf0dc5 100644
--- a/erpnext/accounts/report/financial_statements.html
+++ b/erpnext/accounts/report/financial_statements.html
@@ -44,7 +44,7 @@
- {% for(let j=0, k=data.length-1; j flt(flt(d.get("rate")) * flt(d.get("qty")), precision):
+ if flt(child_item.billed_amt, rate_precision) > flt(flt(d.get("rate"), rate_precision) * flt(d.get("qty"), qty_precision), rate_precision):
frappe.throw(_("Row #{0}: Cannot set Rate if amount is greater than billed amount for Item {1}.")
.format(child_item.idx, child_item.item_code))
else:
- child_item.rate = flt(d.get("rate"))
+ child_item.rate = flt(d.get("rate"), rate_precision)
if d.get("conversion_factor"):
if child_item.stock_uom == child_item.uom:
child_item.conversion_factor = 1
else:
- child_item.conversion_factor = flt(d.get('conversion_factor'))
+ child_item.conversion_factor = flt(d.get('conversion_factor'), conv_fac_precision)
if d.get("delivery_date") and parent_doctype == 'Sales Order':
child_item.delivery_date = d.get('delivery_date')
diff --git a/erpnext/controllers/selling_controller.py b/erpnext/controllers/selling_controller.py
index 1399654ffd2..3ebb12541ab 100644
--- a/erpnext/controllers/selling_controller.py
+++ b/erpnext/controllers/selling_controller.py
@@ -10,6 +10,7 @@ from erpnext.stock.utils import get_incoming_rate
from erpnext.stock.get_item_details import get_conversion_factor
from erpnext.stock.doctype.item.item import set_item_default
from frappe.contacts.doctype.address.address import get_address_display
+from erpnext.controllers.accounts_controller import get_taxes_and_charges
from erpnext.controllers.stock_controller import StockController
@@ -53,10 +54,10 @@ class SellingController(StockController):
super(SellingController, self).set_missing_values(for_validate)
# set contact and address details for customer, if they are not mentioned
- self.set_missing_lead_customer_details()
+ self.set_missing_lead_customer_details(for_validate=for_validate)
self.set_price_list_and_item_details(for_validate=for_validate)
- def set_missing_lead_customer_details(self):
+ def set_missing_lead_customer_details(self, for_validate=False):
customer, lead = None, None
if getattr(self, "customer", None):
customer = self.customer
@@ -93,6 +94,11 @@ class SellingController(StockController):
posting_date=self.get('transaction_date') or self.get('posting_date'),
company=self.company))
+ if self.get('taxes_and_charges') and not self.get('taxes') and not for_validate:
+ taxes = get_taxes_and_charges('Sales Taxes and Charges Template', self.taxes_and_charges)
+ for tax in taxes:
+ self.append('taxes', tax)
+
def set_price_list_and_item_details(self, for_validate=False):
self.set_price_list_currency("Selling")
self.set_missing_item_details(for_validate=for_validate)
diff --git a/erpnext/public/js/utils.js b/erpnext/public/js/utils.js
index 9b1c94e5ba0..264344ca94c 100755
--- a/erpnext/public/js/utils.js
+++ b/erpnext/public/js/utils.js
@@ -452,6 +452,9 @@ erpnext.utils.update_child_items = function(opts) {
const frm = opts.frm;
const cannot_add_row = (typeof opts.cannot_add_row === 'undefined') ? true : opts.cannot_add_row;
const child_docname = (typeof opts.cannot_add_row === 'undefined') ? "items" : opts.child_docname;
+ const child_meta = frappe.get_meta(`${frm.doc.doctype} Item`);
+ const get_precision = (fieldname) => child_meta.fields.find(f => f.fieldname == fieldname).precision;
+
this.data = [];
const fields = [{
fieldtype:'Data',
@@ -472,14 +475,16 @@ erpnext.utils.update_child_items = function(opts) {
default: 0,
read_only: 0,
in_list_view: 1,
- label: __('Qty')
+ label: __('Qty'),
+ precision: get_precision("qty")
}, {
fieldtype:'Currency',
fieldname:"rate",
default: 0,
read_only: 0,
in_list_view: 1,
- label: __('Rate')
+ label: __('Rate'),
+ precision: get_precision("rate")
}];
if (frm.doc.doctype == 'Sales Order' || frm.doc.doctype == 'Purchase Order' ) {
@@ -494,7 +499,8 @@ erpnext.utils.update_child_items = function(opts) {
fieldtype: 'Float',
fieldname: "conversion_factor",
in_list_view: 1,
- label: __("Conversion Factor")
+ label: __("Conversion Factor"),
+ precision: get_precision('conversion_factor')
})
}
diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py
index 1484f6b2290..a4a63d2aef2 100644
--- a/erpnext/selling/doctype/customer/customer.py
+++ b/erpnext/selling/doctype/customer/customer.py
@@ -129,7 +129,7 @@ class Customer(TransactionBase):
address = frappe.get_doc('Address', address_name.get('name'))
if not address.has_link('Customer', self.name):
address.append('links', dict(link_doctype='Customer', link_name=self.name))
- address.save()
+ address.save(ignore_permissions=self.flags.ignore_permissions)
lead = frappe.db.get_value("Lead", self.lead_name, ["organization_lead", "lead_name", "email_id", "phone", "mobile_no", "gender", "salutation"], as_dict=True)
@@ -147,7 +147,7 @@ class Customer(TransactionBase):
contact = frappe.get_doc('Contact', contact_name.get('name'))
if not contact.has_link('Customer', self.name):
contact.append('links', dict(link_doctype='Customer', link_name=self.name))
- contact.save()
+ contact.save(ignore_permissions=self.flags.ignore_permissions)
else:
lead.lead_name = lead.lead_name.lstrip().split(" ")
diff --git a/erpnext/selling/doctype/quotation/test_quotation.py b/erpnext/selling/doctype/quotation/test_quotation.py
index ee6b429ccae..dfb284b7682 100644
--- a/erpnext/selling/doctype/quotation/test_quotation.py
+++ b/erpnext/selling/doctype/quotation/test_quotation.py
@@ -108,6 +108,10 @@ class TestQuotation(unittest.TestCase):
sales_order.transaction_date = nowdate()
sales_order.insert()
+ # Remove any unknown taxes if applied
+ sales_order.set('taxes', [])
+ sales_order.save()
+
self.assertEqual(sales_order.payment_schedule[0].payment_amount, 8906.00)
self.assertEqual(sales_order.payment_schedule[0].due_date, getdate(quotation.transaction_date))
self.assertEqual(sales_order.payment_schedule[1].payment_amount, 8906.00)
diff --git a/erpnext/selling/doctype/sales_order/sales_order.js b/erpnext/selling/doctype/sales_order/sales_order.js
index b4e151b2e30..423922e4865 100644
--- a/erpnext/selling/doctype/sales_order/sales_order.js
+++ b/erpnext/selling/doctype/sales_order/sales_order.js
@@ -169,7 +169,7 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
}
// project
- if(flt(doc.per_delivered, 2) < 100 && ["Sales", "Shopping Cart"].indexOf(doc.order_type)!==-1 && allow_delivery) {
+ if(flt(doc.per_delivered, 2) < 100) {
this.frm.add_custom_button(__('Project'), () => this.make_project(), __('Create'));
}
diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py
index 31c328fdf3e..55458a51e98 100644
--- a/erpnext/selling/doctype/sales_order/test_sales_order.py
+++ b/erpnext/selling/doctype/sales_order/test_sales_order.py
@@ -88,6 +88,8 @@ class TestSalesOrder(unittest.TestCase):
self.assertEqual(len(si.get("items")), 1)
si.insert()
+ si.set('taxes', [])
+ si.save()
self.assertEqual(si.payment_schedule[0].payment_amount, 500.0)
self.assertEqual(si.payment_schedule[0].due_date, so.transaction_date)
@@ -400,6 +402,22 @@ class TestSalesOrder(unittest.TestCase):
trans_item = json.dumps([{'item_code' : '_Test Item', 'rate' : 200, 'qty' : 2, 'docname': so.items[0].name}])
self.assertRaises(frappe.ValidationError, update_child_qty_rate,'Sales Order', trans_item, so.name)
+
+ def test_update_child_with_precision(self):
+ from frappe.model.meta import get_field_precision
+ from frappe.custom.doctype.property_setter.property_setter import make_property_setter
+
+ precision = get_field_precision(frappe.get_meta("Sales Order Item").get_field("rate"))
+
+ make_property_setter("Sales Order Item", "rate", "precision", 7, "Currency")
+ so = make_sales_order(item_code= "_Test Item", qty=4, rate=200.34664)
+
+ trans_item = json.dumps([{'item_code' : '_Test Item', 'rate' : 200.34669, 'qty' : 4, 'docname': so.items[0].name}])
+ update_child_qty_rate('Sales Order', trans_item, so.name)
+
+ so.reload()
+ self.assertEqual(so.items[0].rate, 200.34669)
+ make_property_setter("Sales Order Item", "rate", "precision", precision, "Currency")
def test_update_child_qty_rate_perm(self):
so = make_sales_order(item_code= "_Test Item", qty=4)
diff --git a/erpnext/setup/doctype/company/company.py b/erpnext/setup/doctype/company/company.py
index 335cad3598b..60dacb54d1a 100644
--- a/erpnext/setup/doctype/company/company.py
+++ b/erpnext/setup/doctype/company/company.py
@@ -372,7 +372,7 @@ class Company(NestedSet):
@frappe.whitelist()
def enqueue_replace_abbr(company, old, new):
- kwargs = dict(company=company, old=old, new=new)
+ kwargs = dict(queue='long', company=company, old=old, new=new)
frappe.enqueue('erpnext.setup.doctype.company.company.replace_abbr', **kwargs)
diff --git a/erpnext/setup/doctype/naming_series/naming_series.py b/erpnext/setup/doctype/naming_series/naming_series.py
index b2cffbbf0d8..abff97364c0 100644
--- a/erpnext/setup/doctype/naming_series/naming_series.py
+++ b/erpnext/setup/doctype/naming_series/naming_series.py
@@ -4,7 +4,7 @@
from __future__ import unicode_literals
import frappe
-from frappe.utils import cstr
+from frappe.utils import cstr, cint
from frappe import msgprint, throw, _
from frappe.model.document import Document
@@ -159,7 +159,7 @@ class NamingSeries(Document):
prefix = self.parse_naming_series()
self.insert_series(prefix)
frappe.db.sql("update `tabSeries` set current = %s where name = %s",
- (self.current_value, prefix))
+ (cint(self.current_value), prefix))
msgprint(_("Series Updated Successfully"))
else:
msgprint(_("Please select prefix first"))
diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py
index 4d5fabb9702..e6634d29fe1 100644
--- a/erpnext/stock/doctype/item/item.py
+++ b/erpnext/stock/doctype/item/item.py
@@ -1072,8 +1072,8 @@ def get_last_purchase_details(item_code, doc_name=None, conversion_rate=1.0):
order by pr.posting_date desc, pr.posting_time desc, pr.name desc
limit 1""", (item_code, cstr(doc_name)), as_dict=1)
-
-
+
+
purchase_order_date = getdate(last_purchase_order and last_purchase_order[0].transaction_date
or "1900-01-01")
purchase_receipt_date = getdate(last_purchase_receipt and
@@ -1081,7 +1081,7 @@ def get_last_purchase_details(item_code, doc_name=None, conversion_rate=1.0):
if last_purchase_order and (purchase_order_date >= purchase_receipt_date or not last_purchase_receipt):
# use purchase order
-
+
last_purchase = last_purchase_order[0]
purchase_date = purchase_order_date
@@ -1101,7 +1101,7 @@ def get_last_purchase_details(item_code, doc_name=None, conversion_rate=1.0):
"discount_percentage": flt(last_purchase.discount_percentage),
"purchase_date": purchase_date
})
-
+
conversion_rate = flt(conversion_rate) or 1.0
out.update({
@@ -1140,8 +1140,7 @@ def invalidate_item_variants_cache_for_website(doc):
if item_code:
item_cache = ItemVariantsCacheManager(item_code)
- item_cache.clear_cache()
-
+ item_cache.rebuild_cache()
def check_stock_uom_with_bin(item, stock_uom):
if stock_uom == frappe.db.get_value("Item", item, "stock_uom"):
diff --git a/erpnext/stock/doctype/item_attribute/item_attribute.json b/erpnext/stock/doctype/item_attribute/item_attribute.json
index 2fbff4e614e..5c4678916f3 100644
--- a/erpnext/stock/doctype/item_attribute/item_attribute.json
+++ b/erpnext/stock/doctype/item_attribute/item_attribute.json
@@ -1,357 +1,97 @@
{
- "allow_copy": 0,
- "allow_events_in_timeline": 0,
- "allow_guest_to_view": 0,
- "allow_import": 1,
- "allow_rename": 1,
- "autoname": "field:attribute_name",
- "beta": 0,
- "creation": "2014-09-26 03:49:54.899170",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "Setup",
- "editable_grid": 0,
+ "actions": [],
+ "allow_import": 1,
+ "allow_rename": 1,
+ "autoname": "field:attribute_name",
+ "creation": "2014-09-26 03:49:54.899170",
+ "doctype": "DocType",
+ "document_type": "Setup",
+ "engine": "InnoDB",
+ "field_order": [
+ "attribute_name",
+ "numeric_values",
+ "section_break_4",
+ "from_range",
+ "increment",
+ "column_break_8",
+ "to_range",
+ "section_break_5",
+ "item_attribute_values"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "attribute_name",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Attribute Name",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
+ "fieldname": "attribute_name",
+ "fieldtype": "Data",
+ "in_list_view": 1,
+ "label": "Attribute Name",
+ "reqd": 1,
"unique": 1
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "0",
- "fieldname": "numeric_values",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Numeric Values",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "default": "0",
+ "fieldname": "numeric_values",
+ "fieldtype": "Check",
+ "label": "Numeric Values"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "numeric_values",
- "fieldname": "section_break_4",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "depends_on": "numeric_values",
+ "fieldname": "section_break_4",
+ "fieldtype": "Section Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
- "fieldname": "from_range",
- "fieldtype": "Float",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "From Range",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "default": "0",
+ "fieldname": "from_range",
+ "fieldtype": "Float",
+ "label": "From Range"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
- "fieldname": "increment",
- "fieldtype": "Float",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Increment",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "default": "0",
+ "fieldname": "increment",
+ "fieldtype": "Float",
+ "label": "Increment"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_8",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "column_break_8",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
- "fieldname": "to_range",
- "fieldtype": "Float",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "To Range",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "default": "0",
+ "fieldname": "to_range",
+ "fieldtype": "Float",
+ "label": "To Range"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval: !doc.numeric_values",
- "fieldname": "section_break_5",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "depends_on": "eval: !doc.numeric_values",
+ "fieldname": "section_break_5",
+ "fieldtype": "Section Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
- "fieldname": "item_attribute_values",
- "fieldtype": "Table",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Item Attribute Values",
- "length": 0,
- "no_copy": 0,
- "options": "Item Attribute Value",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "fieldname": "item_attribute_values",
+ "fieldtype": "Table",
+ "label": "Item Attribute Values",
+ "options": "Item Attribute Value"
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "icon": "fa fa-edit",
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2019-01-01 13:17:46.524806",
- "modified_by": "Administrator",
- "module": "Stock",
- "name": "Item Attribute",
- "name_case": "",
- "owner": "Administrator",
+ ],
+ "icon": "fa fa-edit",
+ "index_web_pages_for_search": 1,
+ "links": [],
+ "modified": "2020-10-02 12:03:02.359202",
+ "modified_by": "Administrator",
+ "module": "Stock",
+ "name": "Item Attribute",
+ "owner": "Administrator",
"permissions": [
{
- "amend": 0,
- "cancel": 0,
- "create": 1,
- "delete": 1,
- "email": 0,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 0,
- "read": 1,
- "report": 1,
- "role": "Item Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
+ "create": 1,
+ "delete": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Item Manager",
+ "share": 1,
"write": 1
}
- ],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1,
- "track_seen": 0,
- "track_views": 0
+ ],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
}
\ No newline at end of file
diff --git a/erpnext/stock/doctype/item_attribute/item_attribute.py b/erpnext/stock/doctype/item_attribute/item_attribute.py
index 2f75bbd97c0..7f00201587a 100644
--- a/erpnext/stock/doctype/item_attribute/item_attribute.py
+++ b/erpnext/stock/doctype/item_attribute/item_attribute.py
@@ -5,6 +5,7 @@ from __future__ import unicode_literals
import frappe
from frappe.model.document import Document
from frappe import _
+from frappe.utils import flt
from erpnext.controllers.item_variant import (validate_is_incremental,
validate_item_attribute_value, InvalidItemAttributeValueError)
@@ -42,7 +43,7 @@ class ItemAttribute(Document):
if self.from_range is None or self.to_range is None:
frappe.throw(_("Please specify from/to range"))
- elif self.from_range >= self.to_range:
+ elif flt(self.from_range) >= flt(self.to_range):
frappe.throw(_("From Range has to be less than To Range"))
if not self.increment:
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
index 42cc473b18d..08553675f4c 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
@@ -207,6 +207,7 @@ class PurchaseReceipt(BuyingController):
from erpnext.accounts.general_ledger import process_gl_map
stock_rbnb = self.get_company_default("stock_received_but_not_billed")
+ stock_rbnb_currency = get_account_currency(stock_rbnb)
cogs_account = self.get_company_default("default_expense_account")
landed_cost_entries = get_item_account_wise_additional_cost(self.name)
expenses_included_in_valuation = self.get_company_default("expenses_included_in_valuation")
@@ -243,7 +244,6 @@ class PurchaseReceipt(BuyingController):
# stock received but not billed
if d.base_net_amount:
- stock_rbnb_currency = get_account_currency(stock_rbnb)
gl_entries.append(self.get_gl_dict({
"account": stock_rbnb,
"against": warehouse_account[d.warehouse]["account"],
@@ -289,6 +289,7 @@ class PurchaseReceipt(BuyingController):
if self.is_return or flt(d.item_tax_amount):
loss_account = expenses_included_in_valuation
else:
+ cogs_account = self.get_company_default("default_expense_account")
loss_account = cogs_account
gl_entries.append(self.get_gl_dict({
diff --git a/erpnext/stock/report/stock_ageing/stock_ageing.py b/erpnext/stock/report/stock_ageing/stock_ageing.py
index 99d816c4a24..953939bccb8 100644
--- a/erpnext/stock/report/stock_ageing/stock_ageing.py
+++ b/erpnext/stock/report/stock_ageing/stock_ageing.py
@@ -17,14 +17,17 @@ def execute(filters=None):
data = []
for item, item_dict in iteritems(item_details):
+ earliest_age, latest_age = 0, 0
fifo_queue = sorted(filter(_func, item_dict["fifo_queue"]), key=_func)
details = item_dict["details"]
- if not fifo_queue or (not item_dict.get("total_qty")): continue
+ if not fifo_queue and (not item_dict.get("total_qty")): continue
average_age = get_average_age(fifo_queue, to_date)
- earliest_age = date_diff(to_date, fifo_queue[0][1])
- latest_age = date_diff(to_date, fifo_queue[-1][1])
+
+ if fifo_queue:
+ earliest_age = date_diff(to_date, fifo_queue[0][1])
+ latest_age = date_diff(to_date, fifo_queue[-1][1])
row = [details.name, details.item_name,
details.description, details.item_group, details.brand]
@@ -147,7 +150,8 @@ def get_fifo_queue(filters, sle=None):
item_details.setdefault(key, {"details": d, "fifo_queue": []})
fifo_queue = item_details[key]["fifo_queue"]
- transferred_item_details.setdefault((d.voucher_no, d.name), [])
+ transferred_item_key = (d.voucher_no, d.name, d.warehouse)
+ transferred_item_details.setdefault(transferred_item_key, [])
if d.voucher_type == "Stock Reconciliation":
d.actual_qty = flt(d.qty_after_transaction) - flt(item_details[key].get("qty_after_transaction", 0))
@@ -155,10 +159,10 @@ def get_fifo_queue(filters, sle=None):
serial_no_list = get_serial_nos(d.serial_no) if d.serial_no else []
if d.actual_qty > 0:
- if transferred_item_details.get((d.voucher_no, d.name)):
- batch = transferred_item_details[(d.voucher_no, d.name)][0]
+ if transferred_item_details.get(transferred_item_key):
+ batch = transferred_item_details[transferred_item_key][0]
fifo_queue.append(batch)
- transferred_item_details[((d.voucher_no, d.name))].pop(0)
+ transferred_item_details[transferred_item_key].pop(0)
else:
if serial_no_list:
for serial_no in serial_no_list:
@@ -182,11 +186,11 @@ def get_fifo_queue(filters, sle=None):
# if batch qty > 0
# not enough or exactly same qty in current batch, clear batch
qty_to_pop -= flt(batch[0])
- transferred_item_details[(d.voucher_no, d.name)].append(fifo_queue.pop(0))
+ transferred_item_details[transferred_item_key].append(fifo_queue.pop(0))
else:
# all from current batch
batch[0] = flt(batch[0]) - qty_to_pop
- transferred_item_details[(d.voucher_no, d.name)].append([qty_to_pop, batch[1]])
+ transferred_item_details[transferred_item_key].append([qty_to_pop, batch[1]])
qty_to_pop = 0
item_details[key]["qty_after_transaction"] = d.qty_after_transaction