diff --git a/erpnext/__init__.py b/erpnext/__init__.py index a06efa0ff75..8c70de3cc19 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__ = '11.1.39' +__version__ = '11.1.42' def get_default_company(user=None): '''Get default company for user''' diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index ca94b52c532..e06db8f4bc6 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -487,7 +487,7 @@ class SalesInvoice(SellingController): """Set against account for debit to account""" against_acc = [] for d in self.get('items'): - if d.income_account not in against_acc: + if d.income_account and d.income_account not in against_acc: against_acc.append(d.income_account) self.against_income_account = ','.join(against_acc) diff --git a/erpnext/accounts/report/non_billed_report.py b/erpnext/accounts/report/non_billed_report.py index 41ec9b74665..9f19c0d7591 100644 --- a/erpnext/accounts/report/non_billed_report.py +++ b/erpnext/accounts/report/non_billed_report.py @@ -12,20 +12,21 @@ def get_ordered_to_be_billed_data(args): child_tab = doctype + " Item" precision = get_field_precision(frappe.get_meta(child_tab).get_field("billed_amt"), currency=get_default_currency()) or 2 - + project_field = get_project_field(doctype, party) return frappe.db.sql(""" Select `{parent_tab}`.name, `{parent_tab}`.{date_field}, `{parent_tab}`.{party}, `{parent_tab}`.{party}_name, {project_field}, `{child_tab}`.item_code, `{child_tab}`.base_amount, - (`{child_tab}`.billed_amt * ifnull(`{parent_tab}`.conversion_rate, 1)), + (`{child_tab}`.billed_amt * ifnull(`{parent_tab}`.conversion_rate, 1)), (`{child_tab}`.base_amount - (`{child_tab}`.billed_amt * ifnull(`{parent_tab}`.conversion_rate, 1))), `{child_tab}`.item_name, `{child_tab}`.description, `{parent_tab}`.company from `{parent_tab}`, `{child_tab}` where - `{parent_tab}`.name = `{child_tab}`.parent and `{parent_tab}`.docstatus = 1 and `{parent_tab}`.status != 'Closed' + `{parent_tab}`.name = `{child_tab}`.parent and `{parent_tab}`.docstatus = 1 + and `{parent_tab}`.status not in ('Closed', 'Completed') and `{child_tab}`.amount > 0 and round(`{child_tab}`.billed_amt * ifnull(`{parent_tab}`.conversion_rate, 1), {precision}) < `{child_tab}`.base_amount order by diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.js b/erpnext/buying/doctype/purchase_order/purchase_order.js index c032df32706..7b90b2b2a6f 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.js +++ b/erpnext/buying/doctype/purchase_order/purchase_order.js @@ -104,7 +104,7 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend( if(doc.docstatus == 1 && !in_list(["Closed", "Delivered"], doc.status)) { if (this.frm.has_perm("submit")) { - if(flt(doc.per_billed, 2) < 100 || doc.per_received < 100) { + if(flt(doc.per_billed, 6) < 100 || flt(doc.per_received, 6) < 100) { cur_frm.add_custom_button(__('Close'), this.close_purchase_order, __("Status")); } } diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py index 664bce4e4fa..917c901cfcb 100644 --- a/erpnext/controllers/buying_controller.py +++ b/erpnext/controllers/buying_controller.py @@ -428,8 +428,9 @@ class BuyingController(StockController): elif not flt(d.rejected_qty): d.rejected_qty = flt(d.received_qty) - flt(d.qty) + val = flt(d.qty) + flt(d.rejected_qty) # Check Received Qty = Accepted Qty + Rejected Qty - if ((flt(d.qty) + flt(d.rejected_qty)) != flt(d.received_qty)): + if (flt(val, d.precision("received_qty")) != flt(d.received_qty, d.precision("received_qty"))): frappe.throw(_("Accepted + Rejected Qty must be equal to Received quantity for Item {0}").format(d.item_code)) def validate_negative_quantity(self, item_row, field_list): diff --git a/erpnext/controllers/status_updater.py b/erpnext/controllers/status_updater.py index 2484586d041..a3018029bc0 100644 --- a/erpnext/controllers/status_updater.py +++ b/erpnext/controllers/status_updater.py @@ -27,7 +27,7 @@ status_map = { ], "Quotation": [ ["Draft", None], - ["Submitted", "eval:self.docstatus==1"], + ["Open", "eval:self.docstatus==1"], ["Lost", "eval:self.status=='Lost'"], ["Ordered", "has_sales_order"], ["Cancelled", "eval:self.docstatus==2"], diff --git a/erpnext/hooks.py b/erpnext/hooks.py index 9b18e5e1f3a..a067e28747e 100644 --- a/erpnext/hooks.py +++ b/erpnext/hooks.py @@ -42,7 +42,7 @@ update_and_get_user_progress = "erpnext.utilities.user_progress_utils.update_def on_session_creation = "erpnext.shopping_cart.utils.set_cart_count" on_logout = "erpnext.shopping_cart.utils.clear_cart_count" -treeviews = ['Account', 'Cost Center', 'Warehouse', 'Item Group', 'Customer Group', 'Sales Person', 'Territory', 'Assessment Group'] +treeviews = ['Account', 'Cost Center', 'Warehouse', 'Item Group', 'Customer Group', 'Sales Person', 'Territory', 'Assessment Group', 'Department'] # website update_website_context = "erpnext.shopping_cart.utils.update_website_context" diff --git a/erpnext/hr/doctype/attendance/attendance_calendar.js b/erpnext/hr/doctype/attendance/attendance_calendar.js index b21afe5eaee..104f09d69ff 100644 --- a/erpnext/hr/doctype/attendance/attendance_calendar.js +++ b/erpnext/hr/doctype/attendance/attendance_calendar.js @@ -2,8 +2,8 @@ // For license information, please see license.txt frappe.views.calendar["Attendance"] = { field_map: { - "start": "date", - "end": "date", + "start": "attendance_date", + "end": "attendance_date", "id": "name", "docstatus": 1 }, diff --git a/erpnext/hr/doctype/department/department.js b/erpnext/hr/doctype/department/department.js index 76bc932144c..963f3615cc5 100644 --- a/erpnext/hr/doctype/department/department.js +++ b/erpnext/hr/doctype/department/department.js @@ -4,7 +4,7 @@ frappe.ui.form.on('Department', { refresh: function(frm) { // read-only for root department - if(!frm.doc.parent_department) { + if(!frm.doc.parent_department && !frm.is_new()) { frm.set_read_only(); frm.set_intro(__("This is a root department and cannot be edited.")); } diff --git a/erpnext/hr/doctype/department/department.json b/erpnext/hr/doctype/department/department.json index aed7f42faf8..3b400ce8d76 100644 --- a/erpnext/hr/doctype/department/department.json +++ b/erpnext/hr/doctype/department/department.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_events_in_timeline": 0, "allow_guest_to_view": 0, "allow_import": 1, "allow_rename": 1, @@ -19,6 +20,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "department_name", "fieldtype": "Data", "hidden": 0, @@ -52,6 +54,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "parent_department", "fieldtype": "Link", "hidden": 0, @@ -85,6 +88,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "company", "fieldtype": "Link", "hidden": 0, @@ -118,6 +122,7 @@ "bold": 1, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "is_group", "fieldtype": "Check", "hidden": 0, @@ -150,6 +155,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "disabled", "fieldtype": "Check", "hidden": 0, @@ -182,6 +188,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "section_break_4", "fieldtype": "Section Break", "hidden": 0, @@ -214,6 +221,7 @@ "collapsible": 0, "columns": 0, "description": "Days for which Holidays are blocked for this department.", + "fetch_if_empty": 0, "fieldname": "leave_block_list", "fieldtype": "Link", "hidden": 0, @@ -246,6 +254,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "leave_section", "fieldtype": "Section Break", "hidden": 0, @@ -279,6 +288,7 @@ "collapsible": 0, "columns": 0, "description": "The first Leave Approver in the list will be set as the default Leave Approver.", + "fetch_if_empty": 0, "fieldname": "leave_approvers", "fieldtype": "Table", "hidden": 0, @@ -312,6 +322,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "expense_section", "fieldtype": "Section Break", "hidden": 0, @@ -345,6 +356,7 @@ "collapsible": 0, "columns": 0, "description": "The first Expense Approver in the list will be set as the default Expense Approver.", + "fetch_if_empty": 0, "fieldname": "expense_approvers", "fieldtype": "Table", "hidden": 0, @@ -378,6 +390,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "lft", "fieldtype": "Int", "hidden": 1, @@ -410,6 +423,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "rgt", "fieldtype": "Int", "hidden": 1, @@ -442,6 +456,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "old_parent", "fieldtype": "Data", "hidden": 1, @@ -479,7 +494,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2018-08-29 06:26:12.995703", + "modified": "2019-06-25 18:43:05.550387", "modified_by": "Administrator", "module": "HR", "name": "Department", @@ -543,7 +558,7 @@ "write": 1 } ], - "quick_entry": 1, + "quick_entry": 0, "read_only": 0, "read_only_onload": 0, "show_name_in_global_search": 1, diff --git a/erpnext/hr/doctype/leave_application/leave_application.py b/erpnext/hr/doctype/leave_application/leave_application.py index 88b8f77b2e0..ef8221108cf 100755 --- a/erpnext/hr/doctype/leave_application/leave_application.py +++ b/erpnext/hr/doctype/leave_application/leave_application.py @@ -400,19 +400,6 @@ def get_leave_balance_on(employee, leave_type, date, allocation_records=None, do return flt(allocation.total_leaves_allocated) - (flt(leaves_taken) + flt(leaves_encashed)) -def get_total_allocated_leaves(employee, leave_type, date): - filters= { - 'from_date': ['<=', date], - 'to_date': ['>=', date], - 'docstatus': 1, - 'leave_type': leave_type, - 'employee': employee - } - - leave_allocation_records = frappe.db.get_all('Leave Allocation', filters=filters, fields=['total_leaves_allocated']) - - return flt(leave_allocation_records[0]['total_leaves_allocated']) if leave_allocation_records else flt(0) - def get_leaves_for_period(employee, leave_type, from_date, to_date, status, docname=None): leave_applications = frappe.db.sql(""" select name, employee, leave_type, from_date, to_date, total_leave_days diff --git a/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py b/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py index 95cb30b7918..18431768528 100644 --- a/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py +++ b/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py @@ -5,7 +5,7 @@ from __future__ import unicode_literals import frappe from frappe import _ from erpnext.hr.doctype.leave_application.leave_application \ - import get_leave_allocation_records, get_leave_balance_on, get_approved_leaves_for_period, get_total_allocated_leaves + import get_leave_allocation_records, get_leave_balance_on, get_approved_leaves_for_period def execute(filters=None): @@ -35,6 +35,9 @@ def get_data(filters, leave_types): allocation_records_based_on_to_date = get_leave_allocation_records(filters.to_date) allocation_records_based_on_from_date = get_leave_allocation_records(filters.from_date) + if filters.to_date <= filters.from_date: + frappe.throw(_("From date can not be greater than than To date")) + active_employees = frappe.get_all("Employee", filters = { "status": "Active", "company": filters.company}, fields = ["name", "employee_name", "department", "user_id"]) @@ -51,7 +54,8 @@ def get_data(filters, leave_types): filters.from_date, filters.to_date) # opening balance - opening = get_total_allocated_leaves(employee.name, leave_type, filters.to_date) + opening = get_leave_balance_on(employee.name, leave_type, filters.from_date, + allocation_records_based_on_to_date.get(employee.name, frappe._dict())) # closing balance closing = get_leave_balance_on(employee.name, leave_type, filters.to_date, diff --git a/erpnext/patches.txt b/erpnext/patches.txt index ae06b5dba35..962ef8a8a8d 100755 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -586,7 +586,7 @@ erpnext.patches.v11_0.add_permissions_in_gst_settings erpnext.patches.v11_1.setup_guardian_role execute:frappe.delete_doc('DocType', 'Notification Control') erpnext.patches.v11_0.remove_barcodes_field_from_copy_fields_to_variants -erpnext.patches.v10_0.item_barcode_childtable_migrate # 16-02-2019 +erpnext.patches.v10_0.item_barcode_childtable_migrate # 16-02-2019 #25-06-2019 erpnext.patches.v11_0.make_italian_localization_fields # 26-03-2019 erpnext.patches.v11_1.make_job_card_time_logs erpnext.patches.v11_1.set_variant_based_on @@ -601,4 +601,5 @@ execute:frappe.delete_doc("Report", "Inactive Items") erpnext.patches.v11_1.delete_scheduling_tool erpnext.patches.v11_1.update_bank_transaction_status erpnext.patches.v11_1.renamed_delayed_item_report -erpnext.patches.v11_1.set_missing_opportunity_from \ No newline at end of file +erpnext.patches.v11_1.set_missing_opportunity_from +erpnext.patches.v11_1.set_quotation_status \ No newline at end of file diff --git a/erpnext/patches/v10_0/item_barcode_childtable_migrate.py b/erpnext/patches/v10_0/item_barcode_childtable_migrate.py index e30e0a74c00..ec9c6c3b760 100644 --- a/erpnext/patches/v10_0/item_barcode_childtable_migrate.py +++ b/erpnext/patches/v10_0/item_barcode_childtable_migrate.py @@ -8,8 +8,10 @@ import frappe def execute(): frappe.reload_doc("stock", "doctype", "item_barcode") + if frappe.get_all("Item Barcode", limit=1): return + if "barcode" not in frappe.db.get_table_columns("Item"): return - items_barcode = frappe.get_all('Item', ['name', 'barcode'], { 'barcode': ('!=', '') }) + items_barcode = frappe.db.sql("select name, barcode from tabItem where barcode is not null", as_dict=True) frappe.reload_doc("stock", "doctype", "item") diff --git a/erpnext/patches/v11_1/set_quotation_status.py b/erpnext/patches/v11_1/set_quotation_status.py new file mode 100644 index 00000000000..87643a23545 --- /dev/null +++ b/erpnext/patches/v11_1/set_quotation_status.py @@ -0,0 +1,7 @@ +from __future__ import unicode_literals +import frappe + +def execute(): + + frappe.db.sql(""" UPDATE `tabQuotation` set status = 'Open' + where docstatus = 1 and status = 'Submitted' """) diff --git a/erpnext/public/js/conf.js b/erpnext/public/js/conf.js index 477781bc805..b94e9183bd8 100644 --- a/erpnext/public/js/conf.js +++ b/erpnext/public/js/conf.js @@ -41,7 +41,8 @@ $.extend(frappe.create_routes, { "Item Group": "Tree/Item Group", "Sales Person": "Tree/Sales Person", "Account": "Tree/Account", - "Cost Center": "Tree/Cost Center" + "Cost Center": "Tree/Cost Center", + "Department": "Tree/Department", }); // preferred modules for breadcrumbs diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js index d0ebce8c429..79119b262ca 100644 --- a/erpnext/public/js/controllers/transaction.js +++ b/erpnext/public/js/controllers/transaction.js @@ -1290,10 +1290,13 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ }, callback: function(r) { if(!r.exc) { - for (let tax of r.message) { - me.frm.add_child("taxes", tax); + me.frm.set_value("taxes", r.message); + + if(me.frm.doc.shipping_rule) { + me.frm.script_manager.trigger("shipping_rule"); + } else { + me.calculate_taxes_and_totals(); } - me.calculate_taxes_and_totals(); } } }); diff --git a/erpnext/selling/doctype/quotation/quotation.json b/erpnext/selling/doctype/quotation/quotation.json index 33fc4dbeb04..65fbe52d9a4 100644 --- a/erpnext/selling/doctype/quotation/quotation.json +++ b/erpnext/selling/doctype/quotation/quotation.json @@ -3096,7 +3096,7 @@ "no_copy": 1, "oldfieldname": "status", "oldfieldtype": "Select", - "options": "Draft\nSubmitted\nOrdered\nLost\nCancelled\nOpen\nReplied", + "options": "Draft\nOpen\nReplied\nOrdered\nLost\nCancelled", "permlevel": 0, "print_hide": 1, "print_hide_if_no_value": 0, @@ -3224,7 +3224,7 @@ "istable": 0, "max_attachments": 1, "menu_index": 0, - "modified": "2019-05-11 19:26:50.735628", + "modified": "2019-06-25 15:31:04.724730", "modified_by": "Administrator", "module": "Selling", "name": "Quotation", diff --git a/erpnext/selling/doctype/quotation/quotation_list.js b/erpnext/selling/doctype/quotation/quotation_list.js index 61a8bc1cab3..5f4e2546fbc 100644 --- a/erpnext/selling/doctype/quotation/quotation_list.js +++ b/erpnext/selling/doctype/quotation/quotation_list.js @@ -13,11 +13,11 @@ frappe.listview_settings['Quotation'] = { }, get_indicator: function(doc) { - if(doc.status==="Submitted") { + if(doc.status==="Open") { if (doc.valid_till && doc.valid_till < frappe.datetime.nowdate()) { return [__("Expired"), "darkgrey", "valid_till,<," + frappe.datetime.nowdate()]; } else { - return [__("Submitted"), "blue", "status,=,Submitted"]; + return [__("Open"), "orange", "status,=,Open"]; } } else if(doc.status==="Ordered") { return [__("Ordered"), "green", "status,=,Ordered"]; diff --git a/erpnext/selling/doctype/sales_order/sales_order.js b/erpnext/selling/doctype/sales_order/sales_order.js index 53b3e73f5e2..84c1693d20c 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.js +++ b/erpnext/selling/doctype/sales_order/sales_order.js @@ -133,7 +133,7 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend( if (this.frm.has_perm("submit")) { // close - if(flt(doc.per_delivered, 6) < 100 || flt(doc.per_billed) < 100) { + if(flt(doc.per_delivered, 6) < 100 || flt(doc.per_billed, 6) < 100) { this.frm.add_custom_button(__('Close'), function() { me.close_sales_order() }, __("Status")) } diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.py b/erpnext/stock/doctype/delivery_note/delivery_note.py index 23f7ed1889d..6cd329ef2bc 100644 --- a/erpnext/stock/doctype/delivery_note/delivery_note.py +++ b/erpnext/stock/doctype/delivery_note/delivery_note.py @@ -414,6 +414,8 @@ def get_returned_qty_map(delivery_note): @frappe.whitelist() def make_sales_invoice(source_name, target_doc=None): doc = frappe.get_doc('Delivery Note', source_name) + + to_make_invoice_qty_map = {} returned_qty_map = get_returned_qty_map(source_name) invoiced_qty_map = get_invoiced_qty_map(source_name) @@ -434,8 +436,7 @@ def make_sales_invoice(source_name, target_doc=None): target.update(get_fetch_values("Sales Invoice", 'company_address', target.company_address)) def update_item(source_doc, target_doc, source_parent): - target_doc.qty, returned_qty = get_pending_qty(source_doc) - returned_qty_map[source_doc.item_code] = returned_qty + target_doc.qty = to_make_invoice_qty_map[source_doc.name] if source_doc.serial_no and source_parent.per_billed > 0: target_doc.serial_no = get_delivery_note_serial_no(source_doc.item_code, @@ -443,7 +444,12 @@ def make_sales_invoice(source_name, target_doc=None): def get_pending_qty(item_row): pending_qty = item_row.qty - invoiced_qty_map.get(item_row.name, 0) - returned_qty = flt(returned_qty_map.get(item_row.item_code, 0)) + + returned_qty = 0 + if returned_qty_map.get(item_row.item_code, 0) > 0: + returned_qty = flt(returned_qty_map.get(item_row.item_code, 0)) + returned_qty_map[item_row.item_code] -= pending_qty + if returned_qty: if returned_qty >= pending_qty: pending_qty = 0 @@ -451,7 +457,10 @@ def make_sales_invoice(source_name, target_doc=None): else: pending_qty -= returned_qty returned_qty = 0 - return pending_qty, returned_qty + + to_make_invoice_qty_map[item_row.name] = pending_qty + + return pending_qty doc = get_mapped_doc("Delivery Note", source_name, { "Delivery Note": { @@ -471,7 +480,7 @@ def make_sales_invoice(source_name, target_doc=None): "cost_center": "cost_center" }, "postprocess": update_item, - "filter": lambda d: get_pending_qty(d)[0] <= 0 if not doc.get("is_return") else get_pending_qty(d)[0] > 0 + "filter": lambda d: get_pending_qty(d) <= 0 if not doc.get("is_return") else get_pending_qty(d) > 0 }, "Sales Taxes and Charges": { "doctype": "Sales Taxes and Charges",