Merge branch 'master' into develop
diff --git a/erpnext/__init__.py b/erpnext/__init__.py
index 83c6069..16629d9 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.37'
+__version__ = '10.1.38'
def get_default_company(user=None):
'''Get default company for user'''
diff --git a/erpnext/accounts/party.py b/erpnext/accounts/party.py
index 909856c..bb7d55b 100644
--- a/erpnext/accounts/party.py
+++ b/erpnext/accounts/party.py
@@ -422,10 +422,10 @@
# fetch and append data from Activity Log
data += frappe.db.sql("""select {fields}
from `tabActivity Log`
- where reference_doctype='{doctype}' and reference_name='{name}'
+ where reference_doctype="{doctype}" and reference_name="{name}"
and status!='Success' and creation > {after}
{group_by} order by creation desc
- """.format(doctype=doctype, name=name, fields=fields,
+ """.format(doctype=frappe.db.escape(doctype), name=frappe.db.escape(name), fields=fields,
group_by=group_by, after=after), as_dict=False)
timeline_items = dict(data)
diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
index bf906ce..16768b9 100644
--- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
+++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
@@ -297,7 +297,10 @@
if party_type == "Supplier":
for pi in frappe.db.sql("""select name, due_date, bill_no, bill_date
- from `tabPurchase Invoice` where docstatus=1""", as_dict=1):
+ from `tabPurchase Invoice` where docstatus = 1
+ union
+ select name, due_date, bill_no, bill_date from `tabJournal Entry`
+ where docstatus = 1 and bill_no is not NULL""", as_dict=1):
voucher_details.setdefault(pi.name, pi)
return voucher_details
diff --git a/erpnext/controllers/taxes_and_totals.py b/erpnext/controllers/taxes_and_totals.py
index 85c58de..6c0347f 100644
--- a/erpnext/controllers/taxes_and_totals.py
+++ b/erpnext/controllers/taxes_and_totals.py
@@ -608,16 +608,19 @@
for item_code, tax_data in item_tax_map.items():
itemised_tax.setdefault(item_code, frappe._dict())
+ tax_rate = 0.0
+ tax_amount = 0.0
+
if isinstance(tax_data, list):
- itemised_tax[item_code][tax.description] = frappe._dict(dict(
- tax_rate=flt(tax_data[0]),
- tax_amount=flt(tax_data[1])
- ))
+ tax_rate = flt(tax_data[0])
+ tax_amount = flt(tax_data[1])
else:
- itemised_tax[item_code][tax.description] = frappe._dict(dict(
- tax_rate=flt(tax_data),
- tax_amount=0.0
- ))
+ tax_rate = flt(tax_data)
+
+ itemised_tax[item_code][tax.description] = frappe._dict(dict(
+ tax_rate = tax_rate,
+ tax_amount = tax_amount
+ ))
return itemised_tax
diff --git a/erpnext/hr/doctype/leave_application/leave_application.py b/erpnext/hr/doctype/leave_application/leave_application.py
index d6d8b1c..25a42f2 100755
--- a/erpnext/hr/doctype/leave_application/leave_application.py
+++ b/erpnext/hr/doctype/leave_application/leave_application.py
@@ -56,6 +56,7 @@
self.status = "Cancelled"
# notify leave applier about cancellation
self.notify_employee()
+ self.cancel_attendance()
def validate_applicable_after(self):
if self.leave_type:
@@ -149,6 +150,13 @@
doc.insert(ignore_permissions=True)
doc.submit()
+ def cancel_attendance(self):
+ if self.docstatus == 2:
+ attendance = frappe.db.sql("""select name from `tabAttendance` where employee = %s\
+ and (attendance_date between %s and %s) and docstatus < 2 and status in ('On Leave', 'Half Day')""",(self.employee, self.from_date, self.to_date), as_dict=1)
+ for name in attendance:
+ frappe.db.set_value("Attendance", name, "docstatus", 2)
+
def validate_salary_processed_days(self):
if not frappe.db.get_value("Leave Type", self.leave_type, "is_lwp"):
return
diff --git a/erpnext/hr/doctype/salary_slip/salary_slip.py b/erpnext/hr/doctype/salary_slip/salary_slip.py
index 09e4925..03f1cd8 100644
--- a/erpnext/hr/doctype/salary_slip/salary_slip.py
+++ b/erpnext/hr/doctype/salary_slip/salary_slip.py
@@ -18,8 +18,12 @@
from erpnext.hr.doctype.employee_benefit_claim.employee_benefit_claim import get_benefit_claim_amount
class SalarySlip(TransactionBase):
+ def __init__(self, *args, **kwargs):
+ super(SalarySlip, self).__init__(*args, **kwargs)
+ self.series = 'Sal Slip/{0}/.#####'.format(self.employee)
+
def autoname(self):
- self.name = make_autoname('Sal Slip/' +self.employee + '/.#####')
+ self.name = make_autoname(self.series)
def validate(self):
self.status = self.get_status()
@@ -460,6 +464,10 @@
self.set_status()
self.update_status()
+ def on_trash(self):
+ from frappe.model.naming import revert_series_if_last
+ revert_series_if_last(self.series, self.name)
+
def email_salary_slip(self):
receiver = frappe.db.get_value("Employee", self.employee, "prefered_email")
diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py
index b809eaf..e933f5a 100644
--- a/erpnext/manufacturing/doctype/bom/bom.py
+++ b/erpnext/manufacturing/doctype/bom/bom.py
@@ -162,7 +162,7 @@
if not self.buying_price_list:
frappe.throw(_("Please select Price List"))
rate = frappe.db.get_value("Item Price", {"price_list": self.buying_price_list,
- "item_code": arg["item_code"]}, "price_list_rate")
+ "item_code": arg["item_code"]}, "price_list_rate") or 0.0
price_list_currency = frappe.db.get_value("Price List",
self.buying_price_list, "currency")
diff --git a/erpnext/public/js/controllers/taxes_and_totals.js b/erpnext/public/js/controllers/taxes_and_totals.js
index 0047186..cd32e3e 100644
--- a/erpnext/public/js/controllers/taxes_and_totals.js
+++ b/erpnext/public/js/controllers/taxes_and_totals.js
@@ -340,12 +340,18 @@
set_item_wise_tax: function(item, tax, tax_rate, current_tax_amount) {
// store tax breakup for each item
- var key = item.item_code || item.item_name;
- var item_wise_tax_amount = current_tax_amount * this.frm.doc.conversion_rate;
- if (tax.item_wise_tax_detail && tax.item_wise_tax_detail[key])
- item_wise_tax_amount += tax.item_wise_tax_detail[key][1];
+ let tax_detail = tax.item_wise_tax_detail;
- tax.item_wise_tax_detail[key] = [tax_rate, flt(item_wise_tax_amount, precision("base_tax_amount", tax))];
+ let key = item.item_code;
+ if(item.item_name && !Object.keys(tax_detail).includes(item.item_name)) {
+ key = item.item_name;
+ }
+
+ let item_wise_tax_amount = current_tax_amount * this.frm.doc.conversion_rate;
+ if (tax_detail && tax_detail[key])
+ item_wise_tax_amount += tax_detail[key][1];
+
+ tax_detail[key] = [tax_rate, flt(item_wise_tax_amount, precision("base_tax_amount", tax))];
},
round_off_totals: function(tax) {
diff --git a/erpnext/regional/report/gstr_1/gstr_1.py b/erpnext/regional/report/gstr_1/gstr_1.py
index 690fbbc..27390d4 100644
--- a/erpnext/regional/report/gstr_1/gstr_1.py
+++ b/erpnext/regional/report/gstr_1/gstr_1.py
@@ -144,17 +144,10 @@
""" % (self.doctype, ', '.join(['%s']*len(self.invoices))), tuple(self.invoices), as_dict=1)
for d in items:
- item_details = {}
- item_details[d.item_code] = d.base_net_amount
-
- if d.parent in self.invoice_items:
- parent_dict = self.invoice_items[d.parent]
- if d.item_code in parent_dict:
- item_details[d.item_code] += parent_dict[d.item_code]
- else:
- item_details.update(parent_dict)
-
- self.invoice_items[d.parent] = item_details
+ if d.item_code not in self.invoice_items.get(d.parent, {}):
+ self.invoice_items.setdefault(d.parent, {}).setdefault(d.item_code,
+ sum(i.get('base_net_amount', 0) for i in items
+ if i.item_code == d.item_code and i.parent == d.parent))
def get_items_based_on_tax_rate(self):
self.tax_details = frappe.db.sql("""
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py
index eed4016..7d822a7 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.py
@@ -310,7 +310,7 @@
d.actual_qty = previous_sle.get("qty_after_transaction") or 0
# validate qty during submit
- if d.docstatus==1 and d.s_warehouse and not allow_negative_stock and d.actual_qty < d.transfer_qty:
+ if d.docstatus==1 and d.s_warehouse and not allow_negative_stock and flt(d.actual_qty, d.precision("actual_qty")) < flt(d.transfer_qty, d.precision("actual_qty")):
frappe.throw(_("Row {0}: Qty not available for {4} in warehouse {1} at posting time of the entry ({2} {3})").format(d.idx,
frappe.bold(d.s_warehouse), formatdate(self.posting_date),
format_time(self.posting_time), frappe.bold(d.item_code))
diff --git a/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py
index b5d2e3f..085e87f 100644
--- a/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py
+++ b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py
@@ -77,8 +77,8 @@
elif not frappe.db.get_value("Batch",{"item": self.item_code, "name": self.batch_no}):
frappe.throw(_("{0} is not a valid Batch Number for Item {1}").format(self.batch_no, self.item_code))
- elif item_det.has_batch_no ==0 and self.batch_no:
- frappe.throw(_("The Item {0} cannot have Batch").format(self.item_code))
+ elif item_det.has_batch_no ==0 and self.batch_no and self.is_cancelled == "No":
+ frappe.throw(_("The Item {0} cannot have Batch").format(self.item_code))
if item_det.has_variants:
frappe.throw(_("Stock cannot exist for Item {0} since has variants").format(self.item_code),