Merge pull request #9913 from mbauskar/quotation
[minor] fixes for TypeError: get_lead_details() takes at least 1 argument (2 given)
diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.js b/erpnext/accounts/doctype/journal_entry/journal_entry.js
index 4880224..ba4cc83 100644
--- a/erpnext/accounts/doctype/journal_entry/journal_entry.js
+++ b/erpnext/accounts/doctype/journal_entry/journal_entry.js
@@ -96,7 +96,14 @@
// expense claim
if(jvd.reference_type==="Expense Claim") {
- return {};
+ return {
+ filters: {
+ 'approval_status': 'Approved',
+ 'total_sanctioned_amount': ['>', 0],
+ 'status': ['!=', 'Paid'],
+ 'docstatus': 1
+ }
+ };
}
// journal entry
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index ba38b1f..b24e047 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -160,6 +160,7 @@
def set_missing_item_details(self, for_validate=False):
"""set missing item values"""
from erpnext.stock.get_item_details import get_item_details
+ from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
if hasattr(self, "items"):
parent_dict = {}
@@ -196,7 +197,7 @@
elif fieldname == "serial_no":
stock_qty = item.get("stock_qty") * -1 if item.get("stock_qty") < 0 else item.get("stock_qty")
- if stock_qty != len(item.get('serial_no').split('\n')):
+ if stock_qty != len(get_serial_nos(item.get('serial_no'))):
item.set(fieldname, value)
elif fieldname == "conversion_factor" and not item.get("conversion_factor"):
diff --git a/erpnext/hr/doctype/expense_claim/expense_claim.json b/erpnext/hr/doctype/expense_claim/expense_claim.json
index 48dcfbb..5708c04 100644
--- a/erpnext/hr/doctype/expense_claim/expense_claim.json
+++ b/erpnext/hr/doctype/expense_claim/expense_claim.json
@@ -905,7 +905,7 @@
"label": "Status",
"length": 0,
"no_copy": 1,
- "options": "Draft\nPaid\nUnpaid\nSubmitted\nCancelled",
+ "options": "Draft\nPaid\nUnpaid\nRejected\nSubmitted\nCancelled",
"permlevel": 0,
"precision": "",
"print_hide": 1,
@@ -964,7 +964,7 @@
"istable": 0,
"max_attachments": 0,
"menu_index": 0,
- "modified": "2017-06-13 14:29:16.914609",
+ "modified": "2017-07-17 15:47:23.255142",
"modified_by": "Administrator",
"module": "HR",
"name": "Expense Claim",
diff --git a/erpnext/hr/doctype/expense_claim/expense_claim.py b/erpnext/hr/doctype/expense_claim/expense_claim.py
index 1cd7257..2781f28 100644
--- a/erpnext/hr/doctype/expense_claim/expense_claim.py
+++ b/erpnext/hr/doctype/expense_claim/expense_claim.py
@@ -39,10 +39,13 @@
"2": "Cancelled"
}[cstr(self.docstatus or 0)]
- if self.total_sanctioned_amount == self.total_amount_reimbursed and self.docstatus == 1:
+ if self.total_sanctioned_amount > 0 and self.total_sanctioned_amount == self.total_amount_reimbursed \
+ and self.docstatus == 1 and self.approval_status == 'Approved':
self.status = "Paid"
- elif self.docstatus == 1:
+ elif self.total_sanctioned_amount > 0 and self.docstatus == 1 and self.approval_status == 'Approved':
self.status = "Unpaid"
+ elif self.docstatus == 1 and self.approval_status == 'Rejected':
+ self.status = 'Rejected'
def set_payable_account(self):
if not self.payable_account and not self.is_paid:
@@ -157,6 +160,9 @@
self.total_claimed_amount = 0
self.total_sanctioned_amount = 0
for d in self.get('expenses'):
+ if self.approval_status == 'Rejected':
+ d.sanctioned_amount = 0.0
+
self.total_claimed_amount += flt(d.claim_amount)
self.total_sanctioned_amount += flt(d.sanctioned_amount)
diff --git a/erpnext/hr/doctype/expense_claim/expense_claim_list.js b/erpnext/hr/doctype/expense_claim/expense_claim_list.js
index 7cff8e2..f5a6f4c 100644
--- a/erpnext/hr/doctype/expense_claim/expense_claim_list.js
+++ b/erpnext/hr/doctype/expense_claim/expense_claim_list.js
@@ -4,8 +4,10 @@
get_indicator: function(doc) {
if(doc.status == "Paid") {
return [__("Paid"), "green", "status,=,'Paid'"];
- } else {
+ }else if(doc.status == "Unpaid") {
return [__("Unpaid"), "orange"];
+ } else if(doc.status == "Rejected") {
+ return [__("Rejected"), "grey"];
}
}
};
diff --git a/erpnext/hr/doctype/expense_claim/test_expense_claim.py b/erpnext/hr/doctype/expense_claim/test_expense_claim.py
index 20df7be..e8c24bb 100644
--- a/erpnext/hr/doctype/expense_claim/test_expense_claim.py
+++ b/erpnext/hr/doctype/expense_claim/test_expense_claim.py
@@ -113,5 +113,23 @@
self.assertEquals(expected_values[gle.account][1], gle.debit)
self.assertEquals(expected_values[gle.account][2], gle.credit)
+ def test_rejected_expense_claim(self):
+ payable_account = get_payable_account("Wind Power LLC")
+ expense_claim = frappe.get_doc({
+ "doctype": "Expense Claim",
+ "employee": "_T-Employee-0001",
+ "payable_account": payable_account,
+ "approval_status": "Rejected",
+ "expenses":
+ [{ "expense_type": "Travel", "default_account": "Travel Expenses - WP", "claim_amount": 300, "sanctioned_amount": 200 }]
+ })
+ expense_claim.submit()
+
+ self.assertEquals(expense_claim.status, 'Rejected')
+ self.assertEquals(expense_claim.total_sanctioned_amount, 0.0)
+
+ gl_entry = frappe.get_all('GL Entry', {'voucher_type': 'Expense Claim', 'voucher_no': expense_claim.name})
+ self.assertEquals(len(gl_entry), 0)
+
def get_payable_account(company):
return frappe.db.get_value('Company', company, 'default_payable_account')
diff --git a/erpnext/hr/doctype/holiday_list/holiday_list.py b/erpnext/hr/doctype/holiday_list/holiday_list.py
index 8935689..17d0a91 100644
--- a/erpnext/hr/doctype/holiday_list/holiday_list.py
+++ b/erpnext/hr/doctype/holiday_list/holiday_list.py
@@ -69,27 +69,17 @@
:param end: End date-time.
:param filters: Filters (JSON).
"""
- condition = ''
- values = {
- "start_date": getdate(start),
- "end_date": getdate(end)
- }
-
if filters:
- if isinstance(filters, basestring):
- filters = json.loads(filters)
+ filters = json.loads(filters)
+ else:
+ filters = []
- if filters.get('holiday_list'):
- condition = 'and hlist.name=%(holiday_list)s'
- values['holiday_list'] = filters['holiday_list']
+ if start:
+ filters.append(['Holiday', 'holiday_date', '>', getdate(start)])
+ if end:
+ filters.append(['Holiday', 'holiday_date', '<', getdate(end)])
- data = frappe.db.sql("""select hlist.name, h.holiday_date, h.description
- from `tabHoliday List` hlist, tabHoliday h
- where h.parent = hlist.name
- and h.holiday_date is not null
- and h.holiday_date >= %(start_date)s
- and h.holiday_date <= %(end_date)s
- {condition}""".format(condition=condition),
- values, as_dict=True, update={"allDay": 1})
-
- return data
+ return frappe.get_list('Holiday List',
+ fields=['name', '`tabHoliday`.holiday_date', '`tabHoliday`.description'],
+ filters = filters,
+ update={"allDay": 1})
diff --git a/erpnext/hr/doctype/leave_application/leave_application.py b/erpnext/hr/doctype/leave_application/leave_application.py
index 2a282e1..3d2ba87 100755
--- a/erpnext/hr/doctype/leave_application/leave_application.py
+++ b/erpnext/hr/doctype/leave_application/leave_application.py
@@ -63,13 +63,13 @@
def validate_dates(self):
if self.from_date and self.to_date and (getdate(self.to_date) < getdate(self.from_date)):
frappe.throw(_("To date cannot be before from date"))
-
+
if self.half_day and self.half_day_date \
- and (getdate(self.half_day_date) < getdate(self.from_date)
+ and (getdate(self.half_day_date) < getdate(self.from_date)
or getdate(self.half_day_date) > getdate(self.to_date)):
-
+
frappe.throw(_("Half Day Date should be between From Date and To Date"))
-
+
if not is_lwp(self.leave_type):
self.validate_dates_acorss_allocation()
self.validate_back_dated_application()
@@ -158,7 +158,7 @@
self.name = "New Leave Application"
for d in frappe.db.sql("""
- select
+ select
name, leave_type, posting_date, from_date, to_date, total_leave_days, half_day_date
from `tabLeave Application`
where employee = %(employee)s and docstatus < 2 and status in ("Open", "Approved")
@@ -169,12 +169,12 @@
"to_date": self.to_date,
"name": self.name
}, as_dict = 1):
-
+
if cint(self.half_day)==1 and getdate(self.half_day_date) == getdate(d.half_day_date) and (
- flt(self.total_leave_days)==0.5
- or getdate(self.from_date) == getdate(d.to_date)
+ flt(self.total_leave_days)==0.5
+ or getdate(self.from_date) == getdate(d.to_date)
or getdate(self.to_date) == getdate(d.from_date)):
-
+
total_leaves_on_half_day = self.get_total_leaves_on_half_day()
if total_leaves_on_half_day >= 1:
self.throw_overlap_error(d)
@@ -199,7 +199,7 @@
"half_day_date": self.half_day_date,
"name": self.name
})[0][0]
-
+
return leave_count_on_half_day_date * 0.5
def validate_max_days(self):
@@ -400,7 +400,7 @@
return lwp and cint(lwp[0][0]) or 0
@frappe.whitelist()
-def get_events(start, end):
+def get_events(start, end, filters=None):
events = []
employee = frappe.db.get_value("Employee", {"user_id": frappe.session.user}, ["name", "company"],
@@ -411,14 +411,14 @@
employee=''
company=frappe.db.get_value("Global Defaults", None, "default_company")
- from frappe.desk.reportview import build_match_conditions
- match_conditions = build_match_conditions("Leave Application")
+ from frappe.desk.reportview import get_filters_cond
+ conditions = get_filters_cond("Leave Application")
# show department leaves for employee
if "Employee" in frappe.get_roles():
add_department_leaves(events, start, end, employee, company)
- add_leaves(events, start, end, match_conditions)
+ add_leaves(events, start, end, conditions)
add_block_dates(events, start, end, employee, company)
add_holidays(events, start, end, employee, company)
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index d68f9f2..70d6744 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -419,4 +419,5 @@
erpnext.patches.v8_1.update_gst_state #17-07-2017
erpnext.patches.v8_1.removed_report_support_hours
erpnext.patches.v8_1.add_indexes_in_transaction_doctypes
+erpnext.patches.v8_1.update_expense_claim_status
erpnext.patches.v8_3.update_company_total_sales
\ No newline at end of file
diff --git a/erpnext/patches/v8_1/update_expense_claim_status.py b/erpnext/patches/v8_1/update_expense_claim_status.py
new file mode 100644
index 0000000..4c1b85a
--- /dev/null
+++ b/erpnext/patches/v8_1/update_expense_claim_status.py
@@ -0,0 +1,23 @@
+# Copyright (c) 2017, Frappe and Contributors
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+import frappe
+
+def execute():
+ frappe.reload_doctype('Expense Claim')
+
+ for data in frappe.db.sql(""" select name from `tabExpense Claim`
+ where (docstatus=1 and total_sanctioned_amount=0 and status = 'Paid') or
+ (docstatus = 1 and approval_status = 'Rejected' and total_sanctioned_amount > 0)""", as_dict=1):
+ doc = frappe.get_doc('Expense Claim', data.name)
+ if doc.approval_status == 'Rejected':
+ for d in doc.expenses:
+ d.db_set("sanctioned_amount", 0, update_modified = False)
+ doc.db_set("total_sanctioned_amount", 0, update_modified = False)
+
+ frappe.db.sql(""" delete from `tabGL Entry` where voucher_type = 'Expense Claim'
+ and voucher_no = %s""", (doc.name))
+
+ doc.set_status()
+ doc.db_set("status", doc.status, update_modified = False)
\ No newline at end of file
diff --git a/erpnext/projects/doctype/timesheet/timesheet.py b/erpnext/projects/doctype/timesheet/timesheet.py
index 8844a48..6416176 100644
--- a/erpnext/projects/doctype/timesheet/timesheet.py
+++ b/erpnext/projects/doctype/timesheet/timesheet.py
@@ -9,9 +9,8 @@
import json
from datetime import timedelta
from erpnext.controllers.queries import get_match_cond
-from frappe.utils import flt, time_diff_in_hours, get_datetime, getdate, cint, get_datetime_str
+from frappe.utils import flt, time_diff_in_hours, get_datetime, getdate, cint
from frappe.model.document import Document
-from frappe.model.mapper import get_mapped_doc
from erpnext.manufacturing.doctype.workstation.workstation import (check_if_within_operating_hours,
WorkstationHolidayError)
from erpnext.manufacturing.doctype.manufacturing_settings.manufacturing_settings import get_mins_between_operations
@@ -133,7 +132,7 @@
if data.name == timesheet.operation_id:
summary = self.get_actual_timesheet_summary(timesheet.operation_id)
data.time_sheet = time_sheet
- data.completed_qty = summary.completed_qty
+ data.completed_qty = summary.completed_qty
data.actual_operation_time = summary.mins
data.actual_start_time = summary.from_time
data.actual_end_time = summary.to_time
@@ -148,7 +147,7 @@
"""Returns 'Actual Operating Time'. """
return frappe.db.sql("""select
sum(tsd.hours*60) as mins, sum(tsd.completed_qty) as completed_qty, min(tsd.from_time) as from_time,
- max(tsd.to_time) as to_time from `tabTimesheet Detail` as tsd, `tabTimesheet` as ts where
+ max(tsd.to_time) as to_time from `tabTimesheet Detail` as tsd, `tabTimesheet` as ts where
ts.production_order = %s and tsd.operation_id = %s and ts.docstatus=1 and ts.name = tsd.parent""",
(self.production_order, operation_id), as_dict=1)[0]
@@ -192,7 +191,7 @@
if fieldname == 'workstation':
cond = "tsd.`{0}`".format(fieldname)
- existing = frappe.db.sql("""select ts.name as name, tsd.from_time as from_time, tsd.to_time as to_time from
+ existing = frappe.db.sql("""select ts.name as name, tsd.from_time as from_time, tsd.to_time as to_time from
`tabTimesheet Detail` tsd, `tabTimesheet` ts where {0}=%(val)s and tsd.parent = ts.name and
(
(%(from_time)s > tsd.from_time and %(from_time)s < tsd.to_time) or
@@ -211,8 +210,8 @@
# check internal overlap
for time_log in self.time_logs:
if (fieldname != 'workstation' or args.get(fieldname) == time_log.get(fieldname)) and \
- args.idx != time_log.idx and ((args.from_time > time_log.from_time and args.from_time < time_log.to_time) or
- (args.to_time > time_log.from_time and args.to_time < time_log.to_time) or
+ args.idx != time_log.idx and ((args.from_time > time_log.from_time and args.from_time < time_log.to_time) or
+ (args.to_time > time_log.from_time and args.to_time < time_log.to_time) or
(args.from_time <= time_log.from_time and args.to_time >= time_log.to_time)):
return self
@@ -239,7 +238,7 @@
self.check_workstation_working_day(data)
def get_last_working_slot(self, time_sheet, workstation):
- return frappe.db.sql(""" select max(from_time) as from_time, max(to_time) as to_time
+ return frappe.db.sql(""" select max(from_time) as from_time, max(to_time) as to_time
from `tabTimesheet Detail` where workstation = %(workstation)s""",
{'workstation': workstation}, as_dict=True)[0]
@@ -277,7 +276,7 @@
if parent:
cond = "and parent = %(parent)s"
- return frappe.db.sql("""select name, parent, billing_hours, billing_amount as billing_amt
+ return frappe.db.sql("""select name, parent, billing_hours, billing_amount as billing_amt
from `tabTimesheet Detail` where docstatus=1 and project = %(project)s {0} and billable = 1
and sales_invoice is null""".format(cond), {'project': project, 'parent': parent}, as_dict=1)
@@ -290,9 +289,9 @@
condition = "and tsd.project = %(project)s"
return frappe.db.sql("""select distinct tsd.parent from `tabTimesheet Detail` tsd,
- `tabTimesheet` ts where
- ts.status in ('Submitted', 'Payslip') and tsd.parent = ts.name and
- tsd.docstatus = 1 and ts.total_billable_amount > 0
+ `tabTimesheet` ts where
+ ts.status in ('Submitted', 'Payslip') and tsd.parent = ts.name and
+ tsd.docstatus = 1 and ts.total_billable_amount > 0
and tsd.parent LIKE %(txt)s {condition}
order by tsd.parent limit %(start)s, %(page_len)s"""
.format(condition=condition), {
@@ -305,7 +304,7 @@
if project and project!='':
data = get_projectwise_timesheet_data(project, name)
else:
- data = frappe.get_all('Timesheet',
+ data = frappe.get_all('Timesheet',
fields = ["(total_billable_amount - total_billed_amount) as billing_amt", "total_billable_hours as billing_hours"], filters = {'name': name})
return {
@@ -332,7 +331,7 @@
@frappe.whitelist()
def make_salary_slip(source_name, target_doc=None):
target = frappe.new_doc("Salary Slip")
- set_missing_values(source_name, target)
+ set_missing_values(source_name, target)
target.run_method("get_emp_and_leave_details")
return target
@@ -364,32 +363,21 @@
:param filters: Filters (JSON).
"""
filters = json.loads(filters)
+ from frappe.desk.calendar import get_event_conditions
+ conditions = get_event_conditions("Timesheet", filters)
- conditions = get_conditions(filters)
- return frappe.db.sql("""select `tabTimesheet Detail`.name as name,
+ return frappe.db.sql("""select `tabTimesheet Detail`.name as name,
`tabTimesheet Detail`.docstatus as status, `tabTimesheet Detail`.parent as parent,
- from_time as start_date, hours, activity_type,
- `tabTimesheet Detail`.project, to_time as end_date,
- CONCAT(`tabTimesheet Detail`.parent, ' (', ROUND(hours,2),' hrs)') as title
- from `tabTimesheet Detail`, `tabTimesheet`
- where `tabTimesheet Detail`.parent = `tabTimesheet`.name
- and `tabTimesheet`.docstatus < 2
+ from_time as start_date, hours, activity_type,
+ `tabTimesheet Detail`.project, to_time as end_date,
+ CONCAT(`tabTimesheet Detail`.parent, ' (', ROUND(hours,2),' hrs)') as title
+ from `tabTimesheet Detail`, `tabTimesheet`
+ where `tabTimesheet Detail`.parent = `tabTimesheet`.name
+ and `tabTimesheet`.docstatus < 2
and (from_time <= %(end)s and to_time >= %(start)s) {conditions} {match_cond}
- """.format(conditions=conditions, match_cond = get_match_cond('Timesheet')),
+ """.format(conditions=conditions, match_cond = get_match_cond('Timesheet')),
{
"start": start,
"end": end
}, as_dict=True, update={"allDay": 0})
-def get_conditions(filters):
- conditions = []
- for key in filters:
- if filters.get(key):
- if frappe.get_meta("Timesheet").has_field(key):
- dt = 'tabTimesheet'
- elif frappe.get_meta("Timesheet Detail").has_field(key):
- dt = 'tabTimesheet Detail'
-
- conditions.append("`%s`.%s = '%s'"%(dt, key, filters.get(key)))
-
- return " and {}".format(" and ".join(conditions)) if conditions else ""
diff --git a/erpnext/public/js/utils/serial_no_batch_selector.js b/erpnext/public/js/utils/serial_no_batch_selector.js
index c7a2f77..08630e5 100644
--- a/erpnext/public/js/utils/serial_no_batch_selector.js
+++ b/erpnext/public/js/utils/serial_no_batch_selector.js
@@ -66,7 +66,7 @@
fieldtype:'Float',
read_only: 1,
label: __(me.has_batch ? 'Total Qty' : 'Qty'),
- default: me.qty
+ default: 0
},
];
@@ -155,14 +155,10 @@
},
bind_qty: function() {
- let serial_no_link = this.dialog.fields_dict.serial_no_select;
- let serial_no_list_field = this.dialog.fields_dict.serial_no;
let batches_field = this.dialog.fields_dict.batches;
-
let qty_field = this.dialog.fields_dict.qty;
-
- let update_quantity = (batch) => {
- if(batch) {
+ if(batches_field) {
+ batches_field.grid.wrapper.on('change', function() {
let total_qty = 0;
batches_field.grid.wrapper.find(
'input[data-fieldname="selected_qty"]').each(function() {
@@ -170,48 +166,6 @@
total_qty += Number($(this).val());
});
qty_field.set_input(total_qty);
- } else {
- let serial_numbers = serial_no_list_field.get_value()
- .replace(/\n/g, ' ').match(/\S+/g) || [];
- qty_field.set_input(serial_numbers.length);
- }
- };
-
- if(serial_no_link) {
- let serial_list = [];
- serial_no_link.$input.on('awesomplete-selectcomplete', function() {
- if(serial_no_link.get_value().length > 0) {
- let new_no = serial_no_link.get_value();
- let list_value = serial_no_list_field.get_value();
- let new_line = '\n';
- if(!serial_no_list_field.get_value()) {
- new_line = '';
- } else {
- serial_list = list_value.replace(/\s+/g, ' ').split(' ');
- }
- if(!serial_list.includes(new_no)) {
- serial_no_link.set_new_description('');
- serial_no_list_field.set_value(list_value + new_line + new_no);
- update_quantity(0);
- } else {
- serial_no_link.set_new_description(new_no + ' is already selected.');
- }
- }
-
- // Should, but doesn't work
- serial_no_link.set_input('');
- serial_no_link.$input.blur();
- });
-
- serial_no_list_field.$input.on('input', function() {
- serial_list = serial_no_list_field.get_value().replace(/\s+/g, ' ').split(' ');
- update_quantity(0);
- });
- }
-
- if(batches_field) {
- batches_field.grid.wrapper.on('change', function() {
- update_quantity(1);
});
}
},
@@ -319,6 +273,7 @@
get_serial_no_fields: function() {
var me = this;
+ this.serial_list = [];
return [
{fieldtype: 'Section Break', label: __('Serial No')},
{
@@ -326,10 +281,46 @@
label: __('Select'),
get_query: function() {
return { filters: {item_code: me.item_code}};
+ },
+ onchange: function(e) {
+ if(this.in_local_change) return;
+ this.in_local_change = 1;
+
+ let serial_no_list_field = this.layout.fields_dict.serial_no;
+ let qty_field = this.layout.fields_dict.qty;
+
+ let new_number = this.get_value();
+ let list_value = serial_no_list_field.get_value();
+ let new_line = '\n';
+ if(!list_value) {
+ new_line = '';
+ } else {
+ me.serial_list = list_value.replace(/\n/g, ' ').match(/\S+/g) || [];
+ }
+
+ if(!me.serial_list.includes(new_number)) {
+ this.set_new_description('');
+ serial_no_list_field.set_value(me.serial_list.join('\n') + new_line + new_number);
+ me.serial_list = serial_no_list_field.get_value().replace(/\n/g, ' ').match(/\S+/g) || [];
+ } else {
+ this.set_new_description(new_number + ' is already selected.');
+ }
+
+ qty_field.set_input(me.serial_list.length);
+ this.$input.val("");
+ this.in_local_change = 0;
}
},
{fieldtype: 'Column Break'},
- {fieldname: 'serial_no', fieldtype: 'Small Text'}
+ {
+ fieldname: 'serial_no',
+ fieldtype: 'Small Text',
+ onchange: function() {
+ me.serial_list = this.get_value()
+ .replace(/\n/g, ' ').match(/\S+/g) || [];
+ this.layout.fields_dict.qty.set_input(me.serial_list.length);
+ }
+ }
];
}
});
\ No newline at end of file
diff --git a/erpnext/stock/report/stock_balance/stock_balance.py b/erpnext/stock/report/stock_balance/stock_balance.py
index 5e373d6..c3e3cc5 100644
--- a/erpnext/stock/report/stock_balance/stock_balance.py
+++ b/erpnext/stock/report/stock_balance/stock_balance.py
@@ -13,11 +13,18 @@
columns = get_columns()
item_map = get_item_details(filters)
+ item_reorder_detail_map = get_item_reorder_details(filters)
iwb_map = get_item_warehouse_map(filters)
data = []
for (company, item, warehouse) in sorted(iwb_map):
qty_dict = iwb_map[(company, item, warehouse)]
+ item_reorder_level = 0
+ item_reorder_qty = 0
+ if item + warehouse in item_reorder_detail_map:
+ item_reorder_level = item_reorder_detail_map[item + warehouse]["warehouse_reorder_level"]
+ item_reorder_qty = item_reorder_detail_map[item + warehouse]["warehouse_reorder_qty"]
+
data.append([item, item_map[item]["item_name"],
item_map[item]["item_group"],
item_map[item]["brand"],
@@ -27,6 +34,8 @@
qty_dict.in_val, qty_dict.out_qty,
qty_dict.out_val, qty_dict.bal_qty,
qty_dict.bal_val, qty_dict.val_rate,
+ item_reorder_level,
+ item_reorder_qty,
company
])
@@ -52,6 +61,8 @@
_("Balance Qty")+":Float:100",
_("Balance Value")+":Float:100",
_("Valuation Rate")+":Float:90",
+ _("Reorder Level")+":Float:80",
+ _("Reorder Qty")+":Float:80",
_("Company")+":Link/Company:100"
]
@@ -180,7 +191,19 @@
items = frappe.db.sql("""select name, item_name, stock_uom, item_group, brand, description
from tabItem {condition}""".format(condition=condition), value, as_dict=1)
- return dict((d.name, d) for d in items)
+ return dict((d.name , d) for d in items)
+
+def get_item_reorder_details(filters):
+ condition = ''
+ value = ()
+ if filters.get("item_code"):
+ condition = "where parent=%s"
+ value = (filters.get("item_code"),)
+
+ item_reorder_details = frappe.db.sql("""select parent,warehouse,warehouse_reorder_qty,warehouse_reorder_level
+ from `tabItem Reorder` {condition}""".format(condition=condition), value, as_dict=1)
+
+ return dict((d.parent + d.warehouse, d) for d in item_reorder_details)
def validate_filters(filters):
if not (filters.get("item_code") or filters.get("warehouse")):