Merge branch 'hotfix'
diff --git a/erpnext/__init__.py b/erpnext/__init__.py
index ccb7e8f..7f8dde3 100644
--- a/erpnext/__init__.py
+++ b/erpnext/__init__.py
@@ -5,7 +5,7 @@
from erpnext.hooks import regional_overrides
from frappe.utils import getdate
-__version__ = '10.1.18'
+__version__ = '10.1.19'
def get_default_company(user=None):
'''Get default company for user'''
diff --git a/erpnext/accounts/doctype/cost_center/cost_center_tree.js b/erpnext/accounts/doctype/cost_center/cost_center_tree.js
index f409d64..5043669 100644
--- a/erpnext/accounts/doctype/cost_center/cost_center_tree.js
+++ b/erpnext/accounts/doctype/cost_center/cost_center_tree.js
@@ -48,5 +48,10 @@
}, __('Budget'));
},
+ onrender: function(node) {
+ if(node.is_root){
+ node.hide_add = true;
+ }
+ }
}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py
index eafdac3..2f8e6b8 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.py
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py
@@ -768,6 +768,8 @@
party_account = doc.receivable_account
elif dt == "Employee Advance":
party_account = doc.advance_account
+ elif dt == "Expense Claim":
+ party_account = doc.payable_account
else:
party_account = get_party_account(party_type, doc.get(party_type.lower()), doc.company)
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index 1af2fdd..d690241 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -666,7 +666,9 @@
self.remove(item)
def set_payment_schedule(self):
- if self.doctype == 'Sales Invoice' and self.is_pos: return
+ if self.doctype == 'Sales Invoice' and self.is_pos:
+ self.payment_terms_template = ''
+ return
posting_date = self.get("bill_date") or self.get("posting_date") or self.get("transaction_date")
date = self.get("due_date")
diff --git a/erpnext/controllers/queries.py b/erpnext/controllers/queries.py
index 139586f..15a93bd 100644
--- a/erpnext/controllers/queries.py
+++ b/erpnext/controllers/queries.py
@@ -152,6 +152,11 @@
def item_query(doctype, txt, searchfield, start, page_len, filters, as_dict=False):
conditions = []
+ description_cond = ''
+ if frappe.db.count('Item', cache=True) < 50000:
+ # scan description only if items are less than 50000
+ description_cond = 'or tabItem.description LIKE %(txt)s'
+
return frappe.db.sql("""select tabItem.name, tabItem.item_group,
if(length(tabItem.item_name) > 40,
concat(substr(tabItem.item_name, 1, 40), "..."), item_name) as item_name,
@@ -166,7 +171,7 @@
or tabItem.item_group LIKE %(txt)s
or tabItem.item_name LIKE %(txt)s
or tabItem.barcode LIKE %(txt)s
- or tabItem.description LIKE %(txt)s)
+ {description_cond})
{fcond} {mcond}
order by
if(locate(%(_txt)s, name), locate(%(_txt)s, name), 99999),
@@ -176,7 +181,8 @@
limit %(start)s, %(page_len)s """.format(
key=searchfield,
fcond=get_filters_cond(doctype, filters, conditions).replace('%', '%%'),
- mcond=get_match_cond(doctype).replace('%', '%%')),
+ mcond=get_match_cond(doctype).replace('%', '%%'),
+ description_cond = description_cond),
{
"today": nowdate(),
"txt": "%%%s%%" % txt,
diff --git a/erpnext/demo/user/hr.py b/erpnext/demo/user/hr.py
index 504478a..f5dcecf 100644
--- a/erpnext/demo/user/hr.py
+++ b/erpnext/demo/user/hr.py
@@ -34,14 +34,14 @@
payroll_entry.salary_slip_based_on_timesheet = 0
payroll_entry.create_salary_slips()
payroll_entry.submit_salary_slips()
- payroll_entry.make_accural_jv_entry()
+ payroll_entry.make_accrual_jv_entry()
# payroll_entry.make_journal_entry(reference_date=frappe.flags.current_date,
# reference_number=random_string(10))
payroll_entry.salary_slip_based_on_timesheet = 1
payroll_entry.create_salary_slips()
payroll_entry.submit_salary_slips()
- payroll_entry.make_accural_jv_entry()
+ payroll_entry.make_accrual_jv_entry()
# payroll_entry.make_journal_entry(reference_date=frappe.flags.current_date,
# reference_number=random_string(10))
diff --git a/erpnext/docs/user/manual/en/stock/tools/landed-cost-voucher.md b/erpnext/docs/user/manual/en/stock/tools/landed-cost-voucher.md
index a11759d..259d60e 100644
--- a/erpnext/docs/user/manual/en/stock/tools/landed-cost-voucher.md
+++ b/erpnext/docs/user/manual/en/stock/tools/landed-cost-voucher.md
@@ -24,7 +24,7 @@
<img class="screenshot" alt="Landed Cost Vouher" src="/docs/assets/img/stock/landed-cost.png">
-### What happend on submission?
+### What happens on submission?
1. On submission of Landed Cost Voucher, the applicable landed cost charges are updated in Purchase Receipt Item table.
diff --git a/erpnext/education/doctype/program_enrollment_tool/program_enrollment_tool.py b/erpnext/education/doctype/program_enrollment_tool/program_enrollment_tool.py
index bc60218..ca5b49c 100644
--- a/erpnext/education/doctype/program_enrollment_tool/program_enrollment_tool.py
+++ b/erpnext/education/doctype/program_enrollment_tool/program_enrollment_tool.py
@@ -26,7 +26,7 @@
elif self.get_students_from == "Program Enrollment":
condition2 = 'and student_batch_name=%(student_batch)s' if self.student_batch else " "
students = frappe.db.sql('''select student, student_name, student_batch_name from `tabProgram Enrollment`
- where program=%(program)s and academic_year=%(academic_year)s {0} {1}'''
+ where program=%(program)s and academic_year=%(academic_year)s {0} {1} and docstatus != 2'''
.format(condition, condition2), self.as_dict(), as_dict=1)
student_list = [d.student for d in students]
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index 698c373..5f1e7d4 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -204,7 +204,7 @@
'Address': {
'validate': 'erpnext.regional.india.utils.validate_gstin_for_india'
},
- ('Sales Invoice', 'Purchase Invoice'): {
+ ('Sales Invoice', 'Purchase Invoice', 'Delivery Note'): {
'validate': 'erpnext.regional.india.utils.set_place_of_supply'
}
}
diff --git a/erpnext/hr/doctype/expense_claim/expense_claim.js b/erpnext/hr/doctype/expense_claim/expense_claim.js
index f40e77c..7cce7d3 100644
--- a/erpnext/hr/doctype/expense_claim/expense_claim.js
+++ b/erpnext/hr/doctype/expense_claim/expense_claim.js
@@ -98,9 +98,9 @@
if (cint(doc.total_amount_reimbursed) > 0 && frappe.model.can_read(entry_doctype)) {
cur_frm.add_custom_button(__('Bank Entries'), function() {
frappe.route_options = {
- entry_route_doctype: me.frm.doc.doctype,
- entry_route_name: me.frm.doc.name,
- company: me.frm.doc.company
+ party_type: "Employee",
+ party: doc.employee,
+ company: doc.company
};
frappe.set_route("List", entry_doctype);
}, __("View"));
@@ -205,7 +205,7 @@
make_payment_entry: function(frm) {
var method = "erpnext.accounts.doctype.payment_entry.payment_entry.get_payment_entry";
if(frm.doc.__onload && frm.doc.__onload.make_payment_via_journal_entry) {
- method = "erpnext.hr.doctype.expense_claim.expense_claim.make_bank_entry"
+ method = "erpnext.hr.doctype.expense_claim.expense_claim.make_bank_entry";
}
return frappe.call({
method: method,
diff --git a/erpnext/hr/doctype/payroll_entry/payroll_entry.py b/erpnext/hr/doctype/payroll_entry/payroll_entry.py
index e53a2a6..111df4c 100644
--- a/erpnext/hr/doctype/payroll_entry/payroll_entry.py
+++ b/erpnext/hr/doctype/payroll_entry/payroll_entry.py
@@ -164,7 +164,7 @@
except frappe.ValidationError:
not_submitted_ss.append(ss_dict)
if submitted_ss:
- jv_name = self.make_accural_jv_entry()
+ jv_name = self.make_accrual_jv_entry()
frappe.msgprint(_("Salary Slip submitted for period from {0} to {1}")
.format(ss_obj.start_date, ss_obj.end_date))
@@ -237,7 +237,7 @@
return payroll_payable_account
- def make_accural_jv_entry(self):
+ def make_accrual_jv_entry(self):
self.check_permission('write')
earnings = self.get_salary_component_total(component_type = "earnings") or {}
deductions = self.get_salary_component_total(component_type = "deductions") or {}
@@ -249,7 +249,7 @@
if earnings or deductions:
journal_entry = frappe.new_doc('Journal Entry')
journal_entry.voucher_type = 'Journal Entry'
- journal_entry.user_remark = _('Accural Journal Entry for salaries from {0} to {1}')\
+ journal_entry.user_remark = _('Accrual Journal Entry for salaries from {0} to {1}')\
.format(self.start_date, self.end_date)
journal_entry.company = self.company
journal_entry.posting_date = self.posting_date
diff --git a/erpnext/hr/doctype/salary_component/salary_component.py b/erpnext/hr/doctype/salary_component/salary_component.py
index 35d274c..9108f31 100644
--- a/erpnext/hr/doctype/salary_component/salary_component.py
+++ b/erpnext/hr/doctype/salary_component/salary_component.py
@@ -17,6 +17,5 @@
self.salary_component.split()]).upper()
self.salary_component_abbr = self.salary_component_abbr.strip()
-
- self.salary_component_abbr = append_number_if_name_exists('Salary Component',
- self.salary_component_abbr, 'salary_component_abbr', separator='_')
\ No newline at end of file
+ self.salary_component_abbr = append_number_if_name_exists('Salary Component', self.salary_component_abbr,
+ 'salary_component_abbr', separator='_', filters={"name": ["!=", self.name]})
\ No newline at end of file
diff --git a/erpnext/hr/doctype/salary_structure/salary_structure.js b/erpnext/hr/doctype/salary_structure/salary_structure.js
index 68c5f25..8e6b69b 100755
--- a/erpnext/hr/doctype/salary_structure/salary_structure.js
+++ b/erpnext/hr/doctype/salary_structure/salary_structure.js
@@ -39,6 +39,16 @@
}
}
});
+ frm.set_query("payment_account", function () {
+ var account_types = ["Bank", "Cash"];
+ return {
+ filters: {
+ "account_type": ["in", account_types],
+ "is_group": 0,
+ "company": frm.doc.company
+ }
+ };
+ });
},
refresh: function(frm) {
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 95c78e6..049a822 100644
--- a/erpnext/manufacturing/report/bom_stock_report/bom_stock_report.js
+++ b/erpnext/manufacturing/report/bom_stock_report/bom_stock_report.js
@@ -12,6 +12,10 @@
"fieldtype": "Link",
"options": "Warehouse",
"reqd": 1
+ }, {
+ "fieldname": "show_exploded_view",
+ "label": __("Show exploded view"),
+ "fieldtype": "Check"
}
]
}
diff --git a/erpnext/manufacturing/report/bom_stock_report/bom_stock_report.py b/erpnext/manufacturing/report/bom_stock_report/bom_stock_report.py
index ab9f83d..3236839 100644
--- a/erpnext/manufacturing/report/bom_stock_report/bom_stock_report.py
+++ b/erpnext/manufacturing/report/bom_stock_report/bom_stock_report.py
@@ -6,52 +6,61 @@
from frappe import _
def execute(filters=None):
- if not filters: filters = {}
- columns = get_columns()
- data = get_bom_stock(filters)
- return columns, data
+ if not filters: filters = {}
+ columns = get_columns()
+
+ data = get_bom_stock(filters)
+
+ return columns, data
def get_columns():
- """return columns"""
- columns = [
- _("Item") + ":Link/Item:150",
- _("Description") + "::500",
- _("Required Qty") + ":Float:100",
- _("In Stock Qty") + ":Float:100",
- _("Enough Parts to Build") + ":Float:200",
- ]
+ """return columns"""
+ columns = [
+ _("Item") + ":Link/Item:150",
+ _("Description") + "::500",
+ _("Required Qty") + ":Float:100",
+ _("In Stock Qty") + ":Float:100",
+ _("Enough Parts to Build") + ":Float:200",
+ ]
- return columns
+ return columns
def get_bom_stock(filters):
- conditions = ""
- bom = filters.get("bom")
+ conditions = ""
+ bom = filters.get("bom")
- if filters.get("warehouse"):
- warehouse_details = frappe.db.get_value("Warehouse", filters.get("warehouse"), ["lft", "rgt"], as_dict=1)
- if warehouse_details:
- conditions += " and exists (select name from `tabWarehouse` wh \
- where wh.lft >= %s and wh.rgt <= %s and ledger.warehouse = wh.name)" % (warehouse_details.lft,
- warehouse_details.rgt)
- else:
- conditions += " and ledger.warehouse = '%s'" % frappe.db.escape(filters.get("warehouse"))
+ table = "`tabBOM Item`"
+ qty_field = "qty"
- else:
- conditions += ""
+ if filters.get("show_exploded_view"):
+ table = "`tabBOM Explosion Item`"
+ qty_field = "stock_qty"
- return frappe.db.sql("""
- SELECT
- bom_item.item_code ,
- bom_item.description ,
- bom_item.qty,
- sum(ledger.actual_qty) as actual_qty,
- sum(FLOOR(ledger.actual_qty /bom_item.qty))as to_build
- FROM
- `tabBOM Item` AS bom_item
- LEFT JOIN `tabBin` AS ledger
- ON bom_item.item_code = ledger.item_code
- %s
- WHERE
- bom_item.parent = '%s' and bom_item.parenttype='BOM'
+ if filters.get("warehouse"):
+ warehouse_details = frappe.db.get_value("Warehouse", filters.get("warehouse"), ["lft", "rgt"], as_dict=1)
+ if warehouse_details:
+ conditions += " and exists (select name from `tabWarehouse` wh \
+ where wh.lft >= %s and wh.rgt <= %s and ledger.warehouse = wh.name)" % (warehouse_details.lft,
+ warehouse_details.rgt)
+ else:
+ conditions += " and ledger.warehouse = '%s'" % frappe.db.escape(filters.get("warehouse"))
- GROUP BY bom_item.item_code""" % (conditions, bom))
+ else:
+ conditions += ""
+
+ return frappe.db.sql("""
+ SELECT
+ bom_item.item_code ,
+ bom_item.description ,
+ bom_item.{qty_field},
+ sum(ledger.actual_qty) as actual_qty,
+ sum(FLOOR(ledger.actual_qty / bom_item.{qty_field}))as to_build
+ FROM
+ {table} AS bom_item
+ LEFT JOIN `tabBin` AS ledger
+ ON bom_item.item_code = ledger.item_code
+ {conditions}
+ WHERE
+ bom_item.parent = '{bom}' and bom_item.parenttype='BOM'
+
+ GROUP BY bom_item.item_code""".format(qty_field=qty_field, table=table, conditions=conditions, bom=bom))
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index eae5283..9ed20c9 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -106,7 +106,8 @@
}
if(
- this.frm.fields_dict["payment_terms_template"]
+ this.frm.docstatus < 2
+ && this.frm.fields_dict["payment_terms_template"]
&& this.frm.fields_dict["payment_schedule"]
&& this.frm.doc.payment_terms_template
&& !this.frm.doc.payment_schedule.length
diff --git a/erpnext/regional/india/utils.py b/erpnext/regional/india/utils.py
index 1b91218..fb2faba 100644
--- a/erpnext/regional/india/utils.py
+++ b/erpnext/regional/india/utils.py
@@ -64,7 +64,7 @@
def set_place_of_supply(doc, method):
if not frappe.get_meta('Address').has_field('gst_state'): return
- if doc.doctype == "Sales Invoice":
+ if doc.doctype in ("Sales Invoice", "Delivery Note"):
address_name = doc.shipping_address_name or doc.customer_address
elif doc.doctype == "Purchase Invoice":
address_name = doc.shipping_address or doc.supplier_address
diff --git a/erpnext/setup/doctype/company/delete_company_transactions.py b/erpnext/setup/doctype/company/delete_company_transactions.py
index d975a9e..247445d 100644
--- a/erpnext/setup/doctype/company/delete_company_transactions.py
+++ b/erpnext/setup/doctype/company/delete_company_transactions.py
@@ -85,7 +85,7 @@
in ({leads})""".format(leads=",".join(leads)))
if addresses:
- addresses = ["'%s'"%addr for addr in addresses]
+ addresses = ["'%s'"%frappe.db.escape(addr) for addr in addresses]
frappe.db.sql("""delete from tabAddress where name in ({addresses}) and
name not in (select distinct dl1.parent from `tabDynamic Link` dl1
diff --git a/erpnext/stock/report/stock_ledger/stock_ledger.py b/erpnext/stock/report/stock_ledger/stock_ledger.py
index 305702e..ef198f0 100644
--- a/erpnext/stock/report/stock_ledger/stock_ledger.py
+++ b/erpnext/stock/report/stock_ledger/stock_ledger.py
@@ -7,8 +7,9 @@
def execute(filters=None):
columns = get_columns()
- sl_entries = get_stock_ledger_entries(filters)
- item_details = get_item_details(filters)
+ item_conditions = get_item_conditions(filters)
+ item_details = get_item_details(filters, item_conditions)
+ sl_entries = get_stock_ledger_entries(filters, item_conditions, item_details)
opening_row = get_opening_balance(filters, columns)
data = []
@@ -52,7 +53,12 @@
return columns
-def get_stock_ledger_entries(filters):
+def get_stock_ledger_entries(filters, item_conditions, item_details):
+ item_conditions_sql = ''
+ if item_conditions:
+ items = ['"' + frappe.db.escape(i) + '"' for i in item_details.keys()]
+ if items:
+ item_conditions_sql = 'and sle.item_code in ({})'.format(', '.join(items))
return frappe.db.sql("""select concat_ws(" ", posting_date, posting_time) as date,
item_code, warehouse, actual_qty, qty_after_transaction, incoming_rate, valuation_rate,
stock_value, voucher_type, voucher_no, batch_no, serial_no, company, project
@@ -60,14 +66,18 @@
where company = %(company)s and
posting_date between %(from_date)s and %(to_date)s
{sle_conditions}
+ {item_conditions_sql}
order by posting_date asc, posting_time asc, name asc"""\
- .format(sle_conditions=get_sle_conditions(filters)), filters, as_dict=1)
+ .format(
+ sle_conditions=get_sle_conditions(filters),
+ item_conditions_sql = item_conditions_sql
+ ), filters, as_dict=1)
-def get_item_details(filters):
+def get_item_details(filters, item_conditions):
item_details = {}
for item in frappe.db.sql("""select name, item_name, description, item_group,
brand, stock_uom from `tabItem` item {item_conditions}"""\
- .format(item_conditions=get_item_conditions(filters)), filters, as_dict=1):
+ .format(item_conditions=item_conditions), filters, as_dict=1):
item_details.setdefault(item.name, item)
return item_details
@@ -85,10 +95,6 @@
def get_sle_conditions(filters):
conditions = []
- item_conditions=get_item_conditions(filters)
- if item_conditions:
- conditions.append("""sle.item_code in (select item.name from tabItem item
- {item_conditions})""".format(item_conditions=item_conditions))
if filters.get("warehouse"):
warehouse_condition = get_warehouse_condition(filters.get("warehouse"))
if warehouse_condition:
diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py
index db9c2a6..22db7f1 100644
--- a/erpnext/stock/stock_ledger.py
+++ b/erpnext/stock/stock_ledger.py
@@ -442,7 +442,7 @@
last_valuation_rate = frappe.db.sql("""select valuation_rate
from `tabStock Ledger Entry`
where item_code = %s and warehouse = %s
- and valuation_rate > 0
+ and valuation_rate >= 0
order by posting_date desc, posting_time desc, name desc limit 1""", (item_code, warehouse))
if not last_valuation_rate: