Merge branch 'staging-fixes' into gbm001-item-barcodes-pull
diff --git a/erpnext/accounts/party.py b/erpnext/accounts/party.py
index f19aaf8..8c7f3d8 100644
--- a/erpnext/accounts/party.py
+++ b/erpnext/accounts/party.py
@@ -335,7 +335,7 @@
def validate_due_date(posting_date, due_date, party_type, party, company=None, bill_date=None, template_name=None):
if getdate(due_date) < getdate(posting_date):
- frappe.throw(_("Due Date cannot be before Posting Date"))
+ frappe.throw(_("Due Date cannot be before Posting / Supplier Invoice Date"))
else:
if not template_name: return
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index 51747f6..86ceb2e 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -57,6 +57,8 @@
_('{0} is blocked so this transaction cannot proceed'.format(supplier_name)), raise_exception=1)
def validate(self):
+
+ self.validate_qty_is_not_zero()
if self.get("_action") and self._action != "update_after_submit":
self.set_missing_values(for_validate=True)
@@ -179,7 +181,7 @@
validate_due_date(self.posting_date, self.due_date,
"Customer", self.customer, self.company, self.payment_terms_template)
elif self.doctype == "Purchase Invoice":
- validate_due_date(self.posting_date, self.due_date,
+ validate_due_date(self.bill_date or self.posting_date, self.due_date,
"Supplier", self.supplier, self.company, self.bill_date, self.payment_terms_template)
def set_price_list_currency(self, buying_or_selling):
@@ -359,6 +361,11 @@
return gl_dict
+ def validate_qty_is_not_zero(self):
+ for item in self.items:
+ if not item.qty:
+ frappe.throw("Item quantity can not be zero")
+
def validate_account_currency(self, account, account_currency=None):
valid_currency = [self.company_currency]
if self.get("currency") and self.currency != self.company_currency:
@@ -405,7 +412,8 @@
if d.against_order:
allocated_amount = flt(d.amount)
else:
- allocated_amount = min(self.grand_total - advance_allocated, d.amount)
+ amount = self.rounded_total or self.grand_total
+ allocated_amount = min(amount - advance_allocated, d.amount)
advance_allocated += flt(allocated_amount)
self.append("advances", {
diff --git a/erpnext/controllers/selling_controller.py b/erpnext/controllers/selling_controller.py
index 719f4c7..7739592 100644
--- a/erpnext/controllers/selling_controller.py
+++ b/erpnext/controllers/selling_controller.py
@@ -41,6 +41,7 @@
self.validate_selling_price()
self.set_qty_as_per_stock_uom()
self.set_po_nos()
+ self.set_gross_profit()
set_default_income_account_for_item(self)
def set_missing_values(self, for_validate=False):
@@ -348,6 +349,12 @@
if po_nos and po_nos[0].get('po_no'):
self.po_no = ', '.join(list(set([d.po_no for d in po_nos if d.po_no])))
+ def set_gross_profit(self):
+ if self.doctype == "Sales Order":
+ for item in self.items:
+ item.gross_profit = flt(((item.base_rate - item.valuation_rate) * item.stock_qty), self.precision("amount", item))
+
+
def validate_items(self):
# validate items to see if they have is_sales_item enabled
from erpnext.controllers.buying_controller import validate_item_type
diff --git a/erpnext/education/doctype/fees/fees.json b/erpnext/education/doctype/fees/fees.json
index ac32717..2413967 100644
--- a/erpnext/education/doctype/fees/fees.json
+++ b/erpnext/education/doctype/fees/fees.json
@@ -1,5 +1,6 @@
{
"allow_copy": 0,
+ "allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 1,
"allow_rename": 0,
@@ -999,39 +1000,6 @@
"collapsible": 0,
"columns": 0,
"default": "0",
- "fieldname": "paid_amount",
- "fieldtype": "Currency",
- "hidden": 1,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Paid Amount",
- "length": 0,
- "no_copy": 1,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "0",
"fieldname": "outstanding_amount",
"fieldtype": "Currency",
"hidden": 0,
@@ -1360,7 +1328,7 @@
"istable": 0,
"max_attachments": 0,
"menu_index": 0,
- "modified": "2018-08-21 14:44:48.968839",
+ "modified": "2018-11-26 20:42:14.467284",
"modified_by": "Administrator",
"module": "Education",
"name": "Fees",
diff --git a/erpnext/education/doctype/fees/fees.py b/erpnext/education/doctype/fees/fees.py
index bfe6af4..aa616e6 100644
--- a/erpnext/education/doctype/fees/fees.py
+++ b/erpnext/education/doctype/fees/fees.py
@@ -112,7 +112,10 @@
user = frappe.session.user
student = frappe.db.sql("select name from `tabStudent` where student_email_id= %s", user)
if student:
- return frappe. db.sql('''select name, program, due_date, paid_amount, outstanding_amount, grand_total from `tabFees`
+ return frappe. db.sql('''
+ select name, program, due_date, grand_total - outstanding_amount as paid_amount,
+ outstanding_amount, grand_total, currency
+ from `tabFees`
where student= %s and docstatus=1
order by due_date asc limit {0} , {1}'''
.format(limit_start, limit_page_length), student, as_dict = True)
diff --git a/erpnext/hr/doctype/leave_application/leave_application_list.js b/erpnext/hr/doctype/leave_application/leave_application_list.js
index d7588da..f69b182 100644
--- a/erpnext/hr/doctype/leave_application/leave_application_list.js
+++ b/erpnext/hr/doctype/leave_application/leave_application_list.js
@@ -1,3 +1,10 @@
frappe.listview_settings['Leave Application'] = {
- add_fields: ["leave_type", "employee", "employee_name", "total_leave_days", "from_date", "to_date"]
+ add_fields: ["leave_type", "employee", "employee_name", "total_leave_days", "from_date", "to_date"],
+ get_indicator: function (doc) {
+ if (doc.status === "Approved") {
+ return [__("Approved"), "green", "status,=,Approved"];
+ } else if (doc.status === "Rejected") {
+ return [__("Rejected"), "red", "status,=,Rejected"];
+ }
+ }
};
diff --git a/erpnext/hr/doctype/salary_slip/salary_slip.js b/erpnext/hr/doctype/salary_slip/salary_slip.js
index affbb55..86c50d0 100644
--- a/erpnext/hr/doctype/salary_slip/salary_slip.js
+++ b/erpnext/hr/doctype/salary_slip/salary_slip.js
@@ -177,7 +177,7 @@
if(cint(tbl[i].depends_on_lwp) == 1) {
tbl[i].amount = Math.round(tbl[i].default_amount)*(flt(doc.payment_days) /
cint(doc.total_working_days)*100)/100;
- } else if(reset_amount) {
+ } else if(reset_amount && tbl[i].default_amount) {
tbl[i].amount = tbl[i].default_amount;
}
if(!tbl[i].do_not_include_in_total) {
@@ -198,7 +198,7 @@
for(var i = 0; i < tbl.length; i++){
if(cint(tbl[i].depends_on_lwp) == 1) {
tbl[i].amount = Math.round(tbl[i].default_amount)*(flt(doc.payment_days)/cint(doc.total_working_days)*100)/100;
- } else if(reset_amount) {
+ } else if(reset_amount && tbl[i].default_amount) {
tbl[i].amount = tbl[i].default_amount;
}
if(!tbl[i].do_not_include_in_total) {
diff --git a/erpnext/manufacturing/doctype/manufacturing_settings/manufacturing_settings.py b/erpnext/manufacturing/doctype/manufacturing_settings/manufacturing_settings.py
index b80b0be..e88164f 100644
--- a/erpnext/manufacturing/doctype/manufacturing_settings/manufacturing_settings.py
+++ b/erpnext/manufacturing/doctype/manufacturing_settings/manufacturing_settings.py
@@ -13,3 +13,11 @@
def get_mins_between_operations():
return relativedelta(minutes=cint(frappe.db.get_single_value("Manufacturing Settings",
"mins_between_operations")) or 10)
+
+@frappe.whitelist()
+def is_material_consumption_enabled():
+ if not hasattr(frappe.local, 'material_consumption'):
+ frappe.local.material_consumption = cint(frappe.db.get_single_value('Manufacturing Settings',
+ 'material_consumption'))
+
+ return frappe.local.material_consumption
\ No newline at end of file
diff --git a/erpnext/projects/doctype/task/task.js b/erpnext/projects/doctype/task/task.js
index b8f324a..c1a9c44 100644
--- a/erpnext/projects/doctype/task/task.js
+++ b/erpnext/projects/doctype/task/task.js
@@ -80,15 +80,15 @@
}
},
- is_group: function(frm) {
+ is_group: function (frm) {
frappe.call({
- method:"erpnext.projects.doctype.task.task.check_if_child_exists",
+ method: "erpnext.projects.doctype.task.task.check_if_child_exists",
args: {
name: frm.doc.name
},
- callback: function(r){
- if(r.message){
- frappe.msgprint(__('Cannot convert it to non-group. Child Tasks exist.'));
+ callback: function (r) {
+ if (r.message.length > 0) {
+ frappe.msgprint(__(`Cannot convert it to non-group. The following child Tasks exist: ${r.message.join(", ")}.`));
frm.reload_doc();
}
}
diff --git a/erpnext/projects/doctype/task/task.py b/erpnext/projects/doctype/task/task.py
index 3dc52d4..649d73a 100755
--- a/erpnext/projects/doctype/task/task.py
+++ b/erpnext/projects/doctype/task/task.py
@@ -2,12 +2,15 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe, json
-from frappe.utils import getdate, date_diff, add_days, cstr
+import json
+
+import frappe
from frappe import _, throw
+from frappe.utils import add_days, cstr, date_diff, get_link_to_form, getdate
from frappe.utils.nestedset import NestedSet
+
class CircularReferenceError(frappe.ValidationError): pass
class Task(NestedSet):
@@ -157,8 +160,10 @@
@frappe.whitelist()
def check_if_child_exists(name):
- return frappe.db.sql("""select name from `tabTask`
- where parent_task = %s""", name)
+ child_tasks = frappe.get_all("Task", filters={"parent_task": name})
+ child_tasks = [get_link_to_form("Task", task.name) for task in child_tasks]
+ return child_tasks
+
def get_project(doctype, txt, searchfield, start, page_len, filters):
from erpnext.controllers.queries import get_match_cond
@@ -237,4 +242,4 @@
new_task.insert()
def on_doctype_update():
- frappe.db.add_index("Task", ["lft", "rgt"])
\ No newline at end of file
+ frappe.db.add_index("Task", ["lft", "rgt"])
diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py
index 5f435ce..9a35aed 100755
--- a/erpnext/selling/doctype/sales_order/sales_order.py
+++ b/erpnext/selling/doctype/sales_order/sales_order.py
@@ -32,7 +32,6 @@
def validate(self):
super(SalesOrder, self).validate()
-
self.validate_order_type()
self.validate_delivery_date()
self.validate_proj_cust()
@@ -342,9 +341,11 @@
delivered_qty += item.delivered_qty
tot_qty += item.qty
-
- self.db_set("per_delivered", flt(delivered_qty/tot_qty) * 100,
- update_modified=False)
+
+ if tot_qty != 0:
+ self.db_set("per_delivered", flt(delivered_qty/tot_qty) * 100,
+ update_modified=False)
+
def set_indicator(self):
"""Set indicator for portal"""
diff --git a/erpnext/selling/report/sales_analytics/sales_analytics.js b/erpnext/selling/report/sales_analytics/sales_analytics.js
index 718f29c..7dc7c75 100644
--- a/erpnext/selling/report/sales_analytics/sales_analytics.js
+++ b/erpnext/selling/report/sales_analytics/sales_analytics.js
@@ -73,7 +73,8 @@
events: {
onCheckRow: function(data) {
row_name = data[2].content;
- row_values = data.slice(4).map(function (column) {
+ length = data.length
+ row_values = data.slice(4,length-1).map(function (column) {
return column.content;
})
entry = {
@@ -102,12 +103,12 @@
labels: raw_data.labels,
datasets: new_datasets
}
-
+
setTimeout(() => {
frappe.query_report.chart.update(new_data)
},200)
-
-
+
+
setTimeout(() => {
frappe.query_report.chart.draw(true);
}, 800)
diff --git a/erpnext/selling/report/sales_analytics/sales_analytics.py b/erpnext/selling/report/sales_analytics/sales_analytics.py
index 2cc2f70..8d99a9b 100644
--- a/erpnext/selling/report/sales_analytics/sales_analytics.py
+++ b/erpnext/selling/report/sales_analytics/sales_analytics.py
@@ -166,7 +166,7 @@
for entity, period_data in iteritems(self.entity_periodic_data):
row = {
"entity": entity,
- "entity_name": self.entity_names.get(entity)
+ "entity_name": self.entity_names.get(entity)
}
total = 0
for dummy, end_date in self.periodic_daterange:
@@ -177,7 +177,7 @@
row["total"] = total
self.data.append(row)
-
+
def get_rows_by_group(self):
self.get_periodic_data()
out = []
@@ -185,7 +185,7 @@
for d in reversed(self.group_entries):
row = {
"entity": d.name,
- "indent": self.depth_map.get(d.name)
+ "indent": self.depth_map.get(d.name)
}
total = 0
for dummy, end_date in self.periodic_daterange:
@@ -275,7 +275,8 @@
self.parent_child_map = frappe._dict(frappe.db.sql(""" select name, supplier_group from `tabSupplier`"""))
def get_chart_data(self):
- labels = [d.get("label") for d in self.columns[2:]]
+ length = len(self.columns)
+ labels = [d.get("label") for d in self.columns[2:length-1]]
self.chart = {
"data": {
'labels': labels,
diff --git a/erpnext/setup/doctype/company/company.py b/erpnext/setup/doctype/company/company.py
index 0c58fb2..40bbc2c 100644
--- a/erpnext/setup/doctype/company/company.py
+++ b/erpnext/setup/doctype/company/company.py
@@ -363,7 +363,8 @@
for d in doc:
_rename_record(d)
- for dt in ["Warehouse", "Account", "Cost Center"]:
+ for dt in ["Warehouse", "Account", "Cost Center", "Department", "Location",
+ "Sales Taxes and Charges Template", "Purchase Taxes and Charges Template"]:
_rename_records(dt)
frappe.db.commit()
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.js b/erpnext/stock/doctype/stock_entry/stock_entry.js
index a26992a..ccd5f36 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.js
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.js
@@ -199,12 +199,15 @@
},
validate_purpose_consumption: function(frm) {
- frappe.model.get_value('Manufacturing Settings', {'name': 'Manufacturing Settings'}, 'material_consumption', function(d) {
- if (d.material_consumption==0 && frm.doc.purpose=="Material Consumption for Manufacture") {
+ frappe.call({
+ method: "erpnext.manufacturing.doctype.manufacturing_settings.manufacturing_settings.is_material_consumption_enabled",
+ }).then(r => {
+ if (cint(r.message) == 0
+ && frm.doc.purpose=="Material Consumption for Manufacture") {
frm.set_value("purpose", 'Manufacture');
frappe.throw(__('Material Consumption is not set in Manufacturing Settings.'));
}
- })
+ });
},
company: function(frm) {
diff --git a/erpnext/stock/report/stock_analytics/stock_analytics.js b/erpnext/stock/report/stock_analytics/stock_analytics.js
index 6010ea9..bebc84e 100644
--- a/erpnext/stock/report/stock_analytics/stock_analytics.js
+++ b/erpnext/stock/report/stock_analytics/stock_analytics.js
@@ -88,10 +88,9 @@
events: {
onCheckRow: function(data) {
row_name = data[2].content;
- row_values = data.slice(6).map(function (column) {
+ row_values = data.slice(7).map(function (column) {
return column.content;
})
-
entry = {
'name':row_name,
'values':row_values
@@ -118,12 +117,12 @@
labels: raw_data.labels,
datasets: new_datasets
}
-
+
setTimeout(() => {
frappe.query_report.chart.update(new_data)
},200)
-
-
+
+
setTimeout(() => {
frappe.query_report.chart.draw(true);
}, 800)
diff --git a/erpnext/stock/report/stock_analytics/stock_analytics.py b/erpnext/stock/report/stock_analytics/stock_analytics.py
index 5a8a672..dad8be1 100644
--- a/erpnext/stock/report/stock_analytics/stock_analytics.py
+++ b/erpnext/stock/report/stock_analytics/stock_analytics.py
@@ -167,13 +167,11 @@
return data
def get_chart_data(columns):
- labels = [d.get("label") for d in columns[4:]]
+ labels = [d.get("label") for d in columns[5:]]
chart = {
"data": {
'labels': labels,
- 'datasets':[
- { "values": ['0' for d in columns[4:]] }
- ]
+ 'datasets':[]
}
}
chart["type"] = "line"
diff --git a/erpnext/templates/includes/fee/fee_row.html b/erpnext/templates/includes/fee/fee_row.html
index ac2b100..d5fd682 100644
--- a/erpnext/templates/includes/fee/fee_row.html
+++ b/erpnext/templates/includes/fee/fee_row.html
@@ -5,13 +5,13 @@
{{ doc.program }}
</div>
<div class="col-xs-2">
- {{ doc.get_formatted("total_amount") }}
+ {{ frappe.utils.fmt_money(doc.grand_total, currency=doc.currency) }}
</div>
<div class="col-xs-2">
- {{ doc.get_formatted("paid_amount") }}
+ {{ frappe.utils.fmt_money(doc.paid_amount, currency=doc.currency) }}
</div>
<div class="col-xs-2">
- {{ doc.get_formatted("outstanding_amount") }}
+ {{ frappe.utils.fmt_money(doc.outstanding_amount, currency=doc.currency) }}
</div>
</div>
</a>