diff --git a/erpnext/__init__.py b/erpnext/__init__.py index ba42d34e23a..3492977e798 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -5,7 +5,7 @@ import frappe 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 a09c0a8c649..8ab25a3da22 100644 --- a/erpnext/accounts/party.py +++ b/erpnext/accounts/party.py @@ -414,10 +414,10 @@ def get_timeline_data(doctype, name): # 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 f722e7f743b..0befa5d0573 100644 --- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py +++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py @@ -286,7 +286,10 @@ class ReceivablePayableReport(object): 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 b44f597ed7c..41ba61b231e 100644 --- a/erpnext/controllers/taxes_and_totals.py +++ b/erpnext/controllers/taxes_and_totals.py @@ -600,16 +600,19 @@ def get_itemised_tax(taxes): 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 e03764a43f0..eb5aec604db 100755 --- a/erpnext/hr/doctype/leave_application/leave_application.py +++ b/erpnext/hr/doctype/leave_application/leave_application.py @@ -60,6 +60,7 @@ class LeaveApplication(Document): def on_cancel(self): # notify leave applier about cancellation self.notify_employee("cancelled") + self.cancel_attendance() def validate_dates(self): if self.from_date and self.to_date and (getdate(self.to_date) < getdate(self.from_date)): @@ -138,6 +139,13 @@ class LeaveApplication(Document): 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 5fbd3b1ff28..5f195d925c3 100644 --- a/erpnext/hr/doctype/salary_slip/salary_slip.py +++ b/erpnext/hr/doctype/salary_slip/salary_slip.py @@ -14,8 +14,12 @@ from erpnext.utilities.transaction_base import TransactionBase from frappe.utils.background_jobs import enqueue 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() @@ -418,6 +422,10 @@ class SalarySlip(TransactionBase): 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 060894c5413..7a2aa8a06b8 100644 --- a/erpnext/manufacturing/doctype/bom/bom.py +++ b/erpnext/manufacturing/doctype/bom/bom.py @@ -158,7 +158,7 @@ class BOM(WebsiteGenerator): 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") @@ -652,4 +652,4 @@ def get_boms_in_bottom_up_order(bom_no=None): bom_list.append(child_bom) count += 1 - return bom_list \ No newline at end of file + return bom_list diff --git a/erpnext/public/js/controllers/taxes_and_totals.js b/erpnext/public/js/controllers/taxes_and_totals.js index f00b84f368e..865a5ffd776 100644 --- a/erpnext/public/js/controllers/taxes_and_totals.js +++ b/erpnext/public/js/controllers/taxes_and_totals.js @@ -338,12 +338,18 @@ erpnext.taxes_and_totals = erpnext.payments.extend({ 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 52f0748c5dc..98379964a4a 100644 --- a/erpnext/regional/report/gstr_1/gstr_1.py +++ b/erpnext/regional/report/gstr_1/gstr_1.py @@ -144,17 +144,10 @@ class Gstr1Report(object): """ % (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 d1dcb31b350..5ed8ada4993 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/stock_entry.py @@ -263,7 +263,7 @@ class StockEntry(StockController): 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 b5d2e3f790f..085e87f5f41 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 @@ class StockLedgerEntry(Document): 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),